xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

Unity における Windows Store App のアプリケーションライフサイクル

Unity で VR などの PC / Standalone 向けのアプリケーションを作っている場合、アプリの終了処理をしたかったら MonoBehaviour.OnApplicationQuit を使います。ですが、HoloLens などの Windows Store App (Universal Windows Platform) 向けのアプリケーション作りをしている場合はそうはいきません。

UWP / WSA のアプリケーションライフサイクル

以下の図にあるように、中断 / 再開という概念を伴うものになります。詳細はリンク先をご覧ください。

f:id:xin9le:20170212221534p:plain

このライフサイクルによると、アプリケーションの中断後に前触れなく突如終了 (Terminate) ということがあり得ます。実はこのとき、アプリケーションが終了しているにも関わらず Unity フレームワークから MonoBehaviour.OnApplicationQuit は呼び出されません

Unity で呼び出されるコールバック

パッと調べた範囲では、呼び出されるのは以下のふたつだけです。

呼び出し順序 中断時 再開時
1. OnApplicationFocus(false) OnApplicationPause(false)
2. OnApplicationPause(true) OnApplicationFocus(true)

つまり、中断時にはいつ勝手に終了されるかも分からないので、不測の自体に備えた終了処理に相当するものが必要ということになります。Unity を使って Windows Store App 向けのビルドを作る場合はアプリケーションライフサイクルに注意しましょう!

BuriKaigi 2017 in Toyama でライブコーディングしてきた

数えれば今回で早 5 回目。毎年恒例、北陸の恒例イベント (?) と言っても過言ではない C# 大好き MVP による、C# ドキドキ・ライブコーディング対決 !! をやってきました。これまでは @Fujiwo / @AILight / @xin9le の 3 人でしたが、今回は @RyotaMurohoshi が加わっての 4 人体制。

お品書き

今回は以下の 3 本建て。

  • ふたりペアになって FizzBuzz を 1 行交代で書く
  • 九九表を作る
  • 4 人オセロ対決

オセロは事前準備がありましたが、それ以外の問題は相変わらず当日その場まで一切知らされないという徹底ぶり。何が来るか分からないという緊張感と、できなかったらどうしようとういう焦りは本当です。どんなに簡単でも冷や汗が出ますw

セッション資料

資料には以下が書かれています。

  • 自己紹介
  • C# の好きなところ / 推したいところ
  • 4 人対戦オセロのアルゴリズム

ちょっとした裏話

@AILight さんが Twitter に書いていたので引用しておきます。

セッション直前でプログラムが動かないという自分たち自身がセッションできないかも、というドキドキ/ハラハラに見舞われて本当に焦りましたw 少し詳しく説明すると、以下のようなことが起こっていました。

  • オセロの AI (アルゴリズム) を作ってくるというお題が課せられる
  • 誰のアルゴリズムが強いか分からないので、先に 5 回試行して一番強いやつを自分のアルゴリズムにしようとした @Fujiwo さん
  • ネットワーク経由で最強と思われるアルゴリズムを自分のアルゴリズムとして利用しようとした @xin9le
  • お互い全員の AI インスタンスを内部で勝手に生成/キャッシュする仕組みだった
  • 期せずして PlayerFujiwoPlayerXin9le を生成し、PlayerXin9lePlayerFujiwo を生成するという無限ループが発生
  • このふたりが揃うと見事に StackOverflowException が飛ぶ

これまでにこんなことは一度もなかったのですが、もはやお互い何をしてくるか分からないので怖いですねw

まとめ

5 年続けてきて思うのは、一種のプログラミングエンターテイメントとしてセッションする側も見る側も楽しめていると実感できていることです。このような楽しみを今後も届けられればと思います。来年は @AILight さんからの「仕返し」が待っているようなので、僕も今から楽しみです!是非ご期待ください :)

その他の参加レポート

1 次元配列から 2 次元辞書を作ろう

以前 2 次元配列の要素をインデックス付きで 1 次元配列に落とす、というのを紹介しました。

となると、その逆もやってみたくなりませんか…?*1

拡張メソッドを作る

通常の ToDictionary メソッドはひとつのプロパティをキーにして辞書を作りますが、このキーをふたつにすればよいでしょう。以下のような感じになります。

//--- キーだけ選択してそのまま要素を格納するバージョン
public static Dictionary<TKeyX, Dictionary<TKeyY, TSource>> ToDictionary2<TSource, TKeyX, TKeyY>
    (
        this IEnumerable<TSource> self,
        Func<TSource, TKeyX> xSelector,
        Func<TSource, TKeyY> ySelector
    )
{
    if (self == null)      throw new ArgumentNullException(nameof(self));
    if (xSelector == null) throw new ArgumentNullException(nameof(xSelector));
    if (ySelector == null) throw new ArgumentNullException(nameof(ySelector));

    return  self.GroupBy(xSelector)
            .ToDictionary(x => x.Key, xs => xs.ToDictionary(ySelector));
}

//--- キーを選択するだけでなく、要素として何を格納するかを選ぶバージョン
public static Dictionary<TKeyX, Dictionary<TKeyY, TElement>> ToDictionary2<TSource, TKeyX, TKeyY, TElement>
    (
        this IEnumerable<TSource> self,
        Func<TSource, TKeyX> xSelector,
        Func<TSource, TKeyY> ySelector,
        Func<TSource, TElement> elementSelector
    )
{
    if (self == null)            throw new ArgumentNullException(nameof(self));
    if (xSelector == null)       throw new ArgumentNullException(nameof(xSelector));
    if (ySelector == null)       throw new ArgumentNullException(nameof(ySelector));
    if (elementSelector == null) throw new ArgumentNullException(nameof(elementSelector));

    return  self.GroupBy(xSelector)
            .ToDictionary(x => x.Key, xs => xs.ToDictionary(ySelector, elementSelector));
}

使ってみよう

こんなものが一体どんなケースで役に立つというのだ…。と思うかもしれませんが、例えば以下のようなものがあります。

//--- こんなクラスがあるとする
class Block
{
    public X { get; set; }
    public Y { get; set; }
    public Color Color { get; set; }
}

//--- こういう 1 次元配列を 2 次元辞書化してしまえば...
var blocks = new []
{
    new Block{ X = 0, Y = 0, Color = Colors.Red },
    new Block{ X = 0, Y = 1, Color = Colors.Blue },
    new Block{ X = 1, Y = 0, Color = Colors.Green },
    new Block{ X = 1, Y = 1, Color = Colors.Yellow },
}
.ToDictionary2(x => x.X, x => Y);

//--- こんなに分かりやすくなる!
var color = blocks[0][1].Color;

…滅多に使わないとは思います(ハイ

*1:普通ならないと思う

2016 年を振り返って

ウチの CTO が毎年やっていて、「今年は僕も振り返ってみようかな」という気持ちになったので書いてみます。振り返りは大事だな、と言うことで!

単身赴任

2015 年 9 月に株式会社グラニに転職し、単身赴任生活が始まって早 1 年 3 ヵ月が過ぎました。転職して本当によかったって思っています。素晴らしいメンバーと毎日精一杯仕事ができているし、仕事ってこんなに楽しいんだなぁって社会人になって初めて思えました。...ただひとつを除いて。

それは家族と一緒にいる時間がものすごく少ないこと。これは単身赴任をしているので当然ですし、その選択をした自分のせいなのですが。家族って本当に大切だなぁとか愛しいなぁと改めて感じています。悲しませているとは思いつつ、自由にやらせてもらっていることに多大なる感謝が尽きません。だからこそ毎日何時間働いてもツラくないし、自分が選択したんだからって前向きになれます。そして帰省しているときは極力一緒に時間を過ごす、という (当然の?) 努力をするようになりました。単身赴任をするまでは「自分の時間をいかに確保するか」ばかりを考えていましたが、毎日が自分の時間になってしまった今はその逆ですね。以前にも増して仕事とプライベートにメリハリがついたのも良かった。

家族の理解とサポートって本当に素晴らしいですね。改めて、ありがとう。

どうして転職したの?

と、たまに聞かれます。「あんなに福井が好きって言ってたのに!」みたいな。すべてはコレだと思うんです。

プライベートではお友達 / 仕事では上司なこの方があまりにも、あまりにもブッ飛んでる。本当にリスペクトの極み。そんなスーパーな方の近くで仕事したかったから、というのが率直なところです。福井の田舎の会社で井の中の蛙にはなりたくなかった。そのためには環境を変えなきゃ / 冒険しなきゃって思えて、それで転職を決心しました。環境を変えるのが自分を変える最短かつ最高の方法だと思います。

もちろん、グラニ開発部のメンバー全員が素敵な個性と素晴らしい技量を持っていて日々尊敬していますし、毎日社内チャットでやりとりされる内容を見ているだけでレベルが高くて本当に勉強になります。

お仕事

入社してから 1 年ちょっと、グラニのメインタイトルである神獄のヴァルハラゲートの開発/運用をしてきました。日々の小さな改修はもちろんのこと、ユーザーさんが大いに盛り上がるイベントの実装までいろいろです。もちろんショックに沈む失敗もあったけれど、24 時間 365 日動き続けるゲームの運用の難しさや楽しさをいっぱい体験しました。ここで得た経験と自信はかなり大きい!

f:id:xin9le:20161231134015p:plain

夏にはグラニ開発部初のインターン生として @nanTosaka2 くんが 3 週間来てくださり、僕がメンターを担当していました。毎日「なんでこんなに優秀なの?」と目を丸くするばかりで、教えてもらうこともいっぱいありました。インターン終了後にブログを書いてくれたのを見て、ひとり泣いたのは本当です。とても有意義な時間を過ごせたみたいでこちらも感謝に絶えません。お疲れさまでした!本当にありがとね!

そして考え方や心境も結構変化しました。以前は「べき論」をかなり振りかざしていて、ちゃんとしていないことが大嫌いでした。それで喧嘩したり失いそうになったものもありました。そんなことにはもうなりたくないですし、そうしないための妥協を覚えた気がします。「人」をベースとした考え方の大切さ、忘れないようにしたいです。

C# 7

プライベートでは C# 7 のことばかり追いかけていて、重鎮 @ufcpp さんからお叱りを受けたりしつつ、新機能を先駆けて触ってみたのをベースにレビュー記事を書きまくっていました。社内で唱えていた言葉は「日本で最初に触ってみた系の記事を書く」でしたw そこだけは達成できたかなと思います。

勉強会でも C# 7 を唱え続け、C# 7 に関するセッションを半年以内で 3 回もやりました...(ぇ とは言えかなり好評で、de:code 2016 の直前にやったものが「de:code 2016 本体のセッションよりも詳しくてよかった」という評価もあって本当に嬉しかったです。C# 7 のリリースは楽しみにしています。

Hackathon

2015 年に引き続き 2016 年もハッカソンにちょこちょこ出たりしていました。SPA JAM 2016 というヤツでは東京の予選で最優秀賞を受賞して決勝に行ったりもしました。その様子はかなりの数のメディアで取り上げられ、素直に嬉しかったです。とは言え決勝ではしっかり負けたので、結果は何も残してないに等しいんですが!

紅白歌合戦の著作権表示

今日 12 月 31 日と言えば大晦日!大晦日と言えば日本中が楽しむ紅白歌合戦!そんな紅白歌合戦の公式アプリに Reactive Property が採用され、僕の名前も著作権表示に載りました

f:id:xin9le:20161231151710p:plain f:id:xin9le:20161231151716p:plain

「なんでお前がやねん!」というと、元々は @neuecc さんが作っていたライブラリなのですが、メンテが止まっていたので数年前から @okazuki さんと僕でメンテするようになりました。今は issue 対応のときの方針をどうするかを相談したり程度のただのお手伝いマンでしかないのですが、コントリビューターとして名前が入っているのでオマケとして載せていただいた感じです。これも嬉しい出来事でしたし、棚ぼたではありますが感謝に絶えません。

VR

「現在のお仕事は?」と言うと 2016 年 10 月からは新設された VR 部に異動し、その初期メンバーとして活動しています。VR 部発足の経緯などはプレスリリースが出ています。

f:id:xin9le:20161231140634p:plain

そんな Grani VR Studio 最初のプロダクトとして、弊社の六本木ヒルズオフィスを完全再現した Grani VR Office Tour を作成しました。Japan VR Summit 2 にもブース出展し、非常に良い評価をいただきました。TBS のあさチャン!でも取り上げてもらったりしました :)

f:id:xin9le:20161231141811j:plain

f:id:xin9le:20161231141819j:plain

と、最近は毎日 VR という新しい時代のためにメッチャ頑張ってます。けれど、まずまず僕自身が VR に出会ったのが 2016 年 4 月くらい。超新参者だし Unity も初心者なで毎日 ウーン...ウーン... と唸っていますが、日々新しいことにチャレンジできるのって本当に幸せなことだと思います。仲間と一緒にインパクトを残せるよう取り組んでいきます。2017 年はそんな全力の一年!

まとめ

この歳になると人のつながりの大切さに改めて気付かされます。そのためにも Team Geek にある HRT の精神は大切だなぁと痛感しますし、今後も大切にしていきたいと思っています。その上で来年はさらに加速していきます!今後とも、どうぞよろしくお願い致します。

そして、この 1 年に @neuecc さんと取締役で VR 部長の福永からいただいた金言を忘れないように。

モノを作るときに忘れちゃダメなこと 3 箇条

  • 作らない
  • 薄く作る
  • すぐ捨てる

未来はでっかく

  • 未来を作るのは、エンジニアのちょっとした創造力

ニンテンドーアカウントが Outlook.com で受信できないときの対処

やってますか?スーパーマリオ ラン!僕も少し嗜む程度にはやっています。

そんなスーパーマリオランはニンテンドーアカウントとの連携ができ、連携するといろいろ良いことがあります。

  • セーブデータが消えても大丈夫!
  • アイコンを Mii に設定できる
  • 連携しないと手に入らないキャラクターや建物が手に入る

とりあえずセーブデータがニンテンドーアカウント紐付きでサーバー側にバックアップされるので、機種変更してもデータの引き継ぎができます。これだけでも連携しておく価値が十分にあります。ということでニンテンドーアカウントを作ろうと決心しました。

認証メールが飛んでこない

ニンテンドーアカウントを新規に作ろうとすると登録フォームで入力したメールアドレスに対して認証コードの書かれたメールが飛んできます。しかし、待てど暮らせど認証メールが飛んできません。任天堂の Q&A で認証メールが届かない旨を調べてみると以下のようなことが書いてあります。

  • 入力したメールアドレスが間違っていないか
  • 迷惑メールフォルダに入っていないか
  • ご利用メールサービスの受信拒否設定で「no-reply@accounts.nintendo.com」が拒否設定になっていないか
  • 入力したメールアドレスがすでに別のアカウントに登録されていないか

最後は絶対にあり得ないし、その他も何度確認しても問題ありません。イライラが高まってググッてみると、Outlook.com / Office 365 のような Microsoft のメールサービスの場合は送信元がブラックリスト扱いされていると出てきました。

さすがの @aetos382 先生。僕も Outlook.com をメールアドレスとして設定しようとしていたのでダメでした。

ホワイトリストに入れよう

さて、Microsoft に問い合わせしてブラックリスト解除とかそんな高度で面倒で、本当にできるかも怪しいことに時間を割きたくはありません。かと言って Gmail で逃げるのも (できれば) 奥の手にしたい。と思ったところで強制的に受信許可設定すれば行けるのではないか?と閃き、トライしてみたら上手くいきました!

f:id:xin9le:20161224235612p:plain

上記のように、受信許可メーリングリストに「no-reply@accounts.nintendo.com」を追加すれば OK です。良かった ×2。