もんりぃ is undefined.

育児ネタとか、技術ネタとか。

ZenjectSceneLoader が便利です

はじめに

新年あけましておめでとうございます。本年も何卒よろしくお願い申し上げます。

さて、最近 Zenject と仲良くなれてきている気がする id:monry です。

github.com

Zenject は Unity *1 における DI *2 フレームワークです。

で、その Zenject でマルチシーンを取り扱う際に ZenjectSceneLoader というクラスがとても便利だったので紹介します。

ZenjectSceneLoader とは

一言で言えば UnityEngine.SceneManagement.SceneManager の Zenject 版 で、マニュアルにシレッと書いてある 機能だったりします。

何かと面倒になりがちな Zenject におけるマルチシーン の補助的なライブラリクラスだと思ってもらえると理解が早いかも知れません。

ZenjectSceneLoader の使い方

とても簡単なので、サンプルコードをご覧いただければ理解できるかと思います。

class LoadButton : MonoBehaviour
{
    private ZenjectSceneLoader zenjctSceneLoader;

    [Inject]
    private void Construct(ZenjectSceneLoader sceneLoader)
    {
        this.zenjectSceneLoader = zenjectSceneLoader;
    }

    public void OnClick()
    {
        zenjectSceneLoader.LoadScene("Foo", LoadSceneMode.Additive);
    }
}
  1. Scene 読み込みを実行したいクラスに対して ZenjectSceneLoader を Inject します。
    • サンプルコードでは Method Injection を用いていますが、Field/Property Injection とかでも良いと思います。
  2. 読み込みたいタイミングで LoadScene を用いて読み込みます。
    • 非同期呼び出し用の LoadSceneAsync メソッドも用意されていたりします。
    • LoadSceneAsync の場合 AsyncOperation が返されるので、 UniRx.Async と組み合わせて await させるコトで可読性の高い書き方が出来るようになるかと。
    • LoadSceneMode.Single, LoadSceneMode.Additive の何れも対応しています。

ZenjectSceneLoader の特長

これだけだと便利さは伝わらないと思うので、便利な特長を紹介します。

読み込み時の追加 Binding 可能

LoadSceneAsync()Scene が読み込まれる時に、読み込み先の SceneContext に対して追加の Binding を設定 するための delegate を第3引数に受け取るオーバーロードが提供されています。

zenjectSceneLoader.LoadSceneAsync(
    "Bar",
    LoadSceneMode.Additive,
    (DiContainer container) =>
    {
        // 何か色々 Bind したりとか
        container.Bind<IHoge>().To<Fuga>().AsCached();
    }
);

例えば、共通ダイアログ的な Scene を読み込む際に中身のテキストを追加 Bind するなどの使い方が考えられそうです。

他にも、押したボタンの内容に応じて、LoadSceneMode.Single で読み込みつつ次画面のモードを切り替える などの使い方もできるかもしれません。((Single で読み込む場合は後述の LoadSceneRelationship を定義できない( None 限定)ので注意が必要です。))

読み込む Scene の関係性を定義できる

LoadSceneAsync() の第4引数に LoadSceneRelationship という列挙値を渡すことで、 読み込み元の SceneContext から見た読み込み先の SceneContext の関係性 を定義できます。

zenjectSceneLoader.LoadSceneAsync(
    "Baz",
    LoadSceneMode.Additive,
    (container) => { /* 何か Bind */ },
    LoadSceneRelationship.Child // 子 Context として読み込む
);

これにより、元 Context に Bind 済の値を用いつつ、閉じた Context として読み込むことができるようになります。*3

例えば、ダイアログのボタン押下時の処理をダイアログ呼び出し元の Scene 側で Bind して、ダイアログ内のボタンに Inject するような実装が考えられます。

他にも、読み込む毎に処理を Stack していき IEnumerable<AnyDelegate> に Inject して子 Scene 側で纏めて発火させる、といった実装ができるかもしれません。

全ての Context に Bind されている

ここまでの説明から分かるように、特別に Bind を行わずとも Inject が行えるのも特長の一つです。

具体的にどこの Context に Bind されているのかまでは調べておりませんが、恐らく ProjectContext 的なモノに Bind されているんじゃないかと思われます。

まとめ

ZenjectSceneLoader が便利なので、マルチシーン対応する場合の選択肢として利用してみては如何でしょう?

Zenject はドキュメントがとても長いので、なかなか全部の機能を理解することが難しいですが、便利機能がてんこ盛りなのでじっくりドキュメントを読む時間を確保したいものです…。

*1:以外でも使えると思うけど。

*2:Dependency Injection

*3:簡易的な Scene Parenting だと思ってヨサソウ?

2018年を振り返って

はじめに

2018年はそりゃもう公私ともに激動の1年でした。

ということで、貧弱な記憶力をフル稼働させてカレンダーやら個人 KPT の記録とかの外部記憶に頼りつつ、振り返り記事を書きたいと思います。

1月

Schoo 講義

2017年末にお話しをいただいており、講師として出演していました。

元々ある Unity の講義のバージョン更新版という体でお話しを頂いていたのですが、あまり面白く無さそうだったので、無理矢理こんな形にさせてもらいました。

ガッチガチに緊張しまくっていたのを覚えております。

今思えばもっと巧くやれた気もするけど、まぁそれも思い出。

パートナーさん増強計画

お仕事の方で人手不足が深刻化しており、 フリーランスのウェブエンジニアさんを軸に業務委託契約でのジョインを打診しまくっていた。

カレンダー振り返ってみたら、結構な頻度で色々な人と会っており、そのときの繋がりによって今のごっこランドは支えられているので、頑張った甲斐があったなぁという感じ。

親父の入院

プライベートの方では、親父に経度の脳腫瘍があるコトが判明して、カテーテル手術による治療をすることになった。

親父は勿論なんだけど、お袋もかなり参ってしまっていて、実家との往復でちょっとバタバタしていたような記憶があります。

何事も無く完治したので何より。今となっては、定年して日がなゲームしてるらしく、そっちをお袋に心配されてる始末w

2月

ととちゃんジョイン!

まだ1年経ってないんだっけ…?っという濃度で活躍してくれている id:lycoris102a.k.a. ととちゃん)が 2/1 にジョインしてくれました。

2017年末に当時ととちゃんが所属していた会社で開催された勉強会でダイレクトリクルーティングをしたのは良い思い出ですw

ファシリテーションが得意な彼が入ってくれたお陰で、会社内のミーティングがとても健全になったと思っています。

個人的には、彼なくして今の自分の諸々の肩書きは為し得なかったと言っても過言ではないので、スマブラをプレゼントしたいレベルにとっても感謝しています。仔細は後述。

Unity 部の運営に本格的に参画

初めて参加したのは2017年12月の回だったと思うけど、「日本 Android の会 Unity 部」の運営ミーティングに本格的に顔を出し始めました。

Unity のコミュニティの一つなんだけど、ゆるい雰囲気ながらも勉強会の運営慣れしているので勉強になります。

また、UNIBOOK の執筆によりコミケや技術書典に参加するキッカケになったることもあり、これも今の肩書きに欠かせないモノの一部となっています。

3月

関東デベロッパー交流会 2018

割と突発で開かれた感のあるイベントでしたが、「お酒飲めるし、Unity だし、参加しておこう。」くらいの軽いノリで参加し、ちょいちょい Unity の中の人をお見かけしてお話ししたりしてました。

また、ココで nao さんと出会い、お仕事の打診をして、今やパートナーさんとして欠かせない存在になってくださっています。

何が出会いに繋がるか分からんので、ホントこういうイベントへの参加は重要だなぁと思っています。

CAFU の開発本格化

CAFU: Clean Architecture For Unity の開発が佳境に入り、CAFU を利用したパビリオン *1 のリリースが間近に迫っていたような気がします。

正直3月は仕事が忙しくて個人活動はそんなにやれていなかったような気がします。

Gotanda.unity #5 in 株式会社meleap

ととちゃんのジョインにより、 Gotanda.unity という Unity 勉強会コミュニティの運営に参画するようになりました。

元々ととちゃんは、株式会社タノシム(現・ワンダープラネット株式会社)の開さんと一緒にごたゆにの運営をしていたのですが、「何か面白そう!」という浅い理由で運営に関わらせて貰うコトになりました。

とはいえ、完全に未経験の世界で、右も左も分からずキョロキョロして邪魔しかしていなかったんじゃないかというレレルでした。

この活動も肩書きに深くリンクしているので、もうホント何がどうなるか分からんですね…。

4月

ディズニー

家族3人でディズニーランド・ディズニーシーに遊びに行きました。

2017年にも行った気はするけど、そのときよりも娘が楽しんでいたので、それがなによりも良かったです。

昔はマウンテン系のアトラクションとか、タワーオブテラーとか乗りまくってたけど、子どもが生まれると完全に行動が変わるなぁ、というのを実感しました。

技術書典4

f:id:monry84:20181231205549j:plain

日本 Android の会 Unity 部として UNIBOOK9 の新刊頒布を行いました。

人生初の技術書典参加で、「へー!すごいな!」という語彙力の低い感想を抱きました。

5月

この辺から個人 KPT の記録が残っているので、ちょっと情報が増えますw

Unite 2018 Tokyo

f:id:monry84:20181231184331j:plain f:id:monry84:20181231184348j:plain

とにかく楽しかったです。

公募セッションに応募していたのですが、あえなく落選してしまったので、来年こそは…!

Gotanda.unity #6 in 株式会社オルトプラス

運営メンバーになってから2度目のごたゆに。

この日は次のイベントと被っており、前半ちょっとだけ受付お手伝いして颯爽と退散しました。

確か、この回からキッズスターとして懇親会費を負担し始めたような気がします。

しがないラジオmeetup 1

しがないラジオ自体には2017年後半に sp.10 にて出演させていただいたんですが、そこからリスナーとしても薄く関わり続けており、初の meetup イベントが開催される!ってコトで足を運びました。

30人規模くらいの部屋にギッシリとパーソナリティ・ゲスト・リスナーが詰め込まれて、大いに盛り上がりました。楽しかった!

また機会があれば出演したいなぁ。

Unity テスト完全に理解した 決起会

「Unity ○○完全に理解した」勉強会シリーズ発足のキッカケとなる打ち合わせ(という名の飲み会だったと思う)でした。

元々は 殺意開発駆動 (@toru_inoue) さん がととちゃんに声を掛けて、色々あって mixiいも (@adarapata) さん も巻き込んで、運営メンバー・スピーカーが集まって「Unity テストに関する勉強会しようぜ!」って話をしたような気がします。

この時点では「完全に理解した」のサフィックスはついていなかった気もします。

この日が全ての流れを変えたような気がしている。

6月

Unity テスト完全に理解した

そんなわけで、「Unity ○○完全に理解した」勉強会シリーズの第一弾!

speakerdeck.com

私も運営やりつつ「さては密結合だなオメー Clean Architecture で学ぶテストフレンドリーな疎結合設計」という内容で登壇しました。

f:id:monry84:20181231180444j:plain

「最初は50人くらい行けば良いかねぇ?」なんて言いながら募集ページを作りましたが、あれよあれよと人が増えて会場キャパシティ限界まで増やしてもなお増え続け、最終的にピーク時は150/90人という状況になり、注目の高さに運営メンバー一同で震え上がったのを覚えています。

会場を提供してくださった mixi さんには、この回以降もお世話になっており、この場を借りて改めて御礼申し上げます!

ABC 2018 Spring

所属する「日本 Android の会 Unity 部」として講演トラックを2本持つコトになったので、1枠借りて登壇してきました。講演内容はテスト完全理解とほぼ同じ内容でした。

f:id:monry84:20181231180023j:plain

東大で講演するという実績を解除しました!w

神奈川県合唱祭

合唱を趣味として続けているわけですが、毎年この時期に合唱祭イベントがあり、今回は私が参加しました。*2

ちょっと難しい曲を演奏したのですが、楽しかったです。

f:id:monry84:20181231180630j:plain

ジャンケン大会でお花貰いました。

あと、打ち上げの焼き肉がメッチャ美味しかった。

7月

「マンガでわかる Unity」第一話公開!

unity-manga.hatenablog.com

「始めますよ!」って記事が2018年末時点で、289ブクマとか行く謎の盛り上がりを見せており、プレッシャーもそこそこありましたが、何とか第一話公開できました。

最近更新が滞りがちなので、この年末年始休みに本気出す。

Gotanda.unity #7 in 株式会社ミクシィ

f:id:monry84:20181231181821j:plain

安定の高出席率でした。

speakerdeck.com

性懲りも無く運営やりつつ登壇もさせてもらいました。

娘が3歳の誕生日を迎える

個人情報保護の観点で写真は割愛しますが、私の実家の両親を呼び簡単な誕生パーティーを催しました。

日々娘の可愛さが増し続けており、親バカが過熱する一方でヤバいです。

8月

コワーキングオフィス契約

ワーカーホリックなので、オフィスで働いていると定時にパッと切り上げて、個人活動の時間に割くといったコトが苦手です。

また、オフィスが狭いのでどうしても騒がしくなりがちだったり、電話応対とかで集中力が切られがちだったりもしました。

なので、集中して作業したかったり、登壇資料作成やブログ執筆をしたいときなど、リモートで作業できると良いなぁという思いがあり、前からちょいちょい使わせて貰っていたコワーキングオフィスを契約することにしました。

元々自宅リモートとかはチョイチョイやってましたが、可愛い娘が「ねぇねぇパパ!見て!」みたいな感じで寄ってくるとやっぱり作業の手を止めざるを得ないので…。

決して安い金額ではないですが、凄い集中できるようになったので、コストを払うだけの価値は十二分にあったと言えそうです。

結果として、8月からリモートワークの回数が激増して、週の半分以上リモートワークするようになりました。

Unity ゆるふわサマーアドベントカレンダー2018 参加

何か楽しそうだったので参加してみました。

monry.hatenablog.com

当時ハマった問題を記事に纏めた感じです。

C94 参戦

f:id:monry84:20181231184040j:plain

夏コミで「日本 Android の会 Unity 部」の売り子として参戦しました。

相当久しぶりのコミケなので、かなり楽しかったです。疲れたけど。

Clean Architecture 討論会 at ワンダープラネット

ワンプラの開さんから「Clean Architecture について語りたいメンバーがいるので、一緒にどうですか?」と言われて、色々喋ってきました。

お互いのコンテキストを語り合うのがメインになってしまって、もう少し深掘りできても良かったかなぁ?という気もするので、また機会があれば参加したいです!

9月

Unity Zenject 完全に理解した

完全理解シリーズ第2弾として開催しました。

「Unity テスト完全に理解した」の打ち上げで「次は Zenject ですかねー?」って流れから、あれよあれよと開催まで進行していきました。

オープニングトークを担当させて貰ったような気がしています。

Unity 非同期完全に理解した

f:id:monry84:20181231210016j:plain

コチラは とり (@toRisouP) さん 主導で開催された、完全理解シリーズの第3弾です。

登壇者がめちゃ強で、会場キャパシティも200名弱と大規模な勉強会となりました。

ものラジ 始動!

gremito (@grem_ito) くん に以下のリプをしたところから話が始まりました。

殆ど gremito くんに任せっきりで申し訳ないけど、順調に継続できています。

Gotanda.unity #9 in ワンダープラネット株式会社

「五反田とは?」でお馴染みのごたゆにですが、この回もご多分に漏れず五反田以外で開催w

会場設営とか受付とかをお手伝いしました。

10月

技術書典5 参加

f:id:monry84:20181231212032j:plain

今度は UNIBOOK10 を新刊頒布しました。

前回に比べて、だいぶ知り合いも増えたので、ちょいちょい「あ、どうも!」みたいな会話をしていた気がします。

Unity ECS 完全に理解した

完全理解シリーズ第4弾!まだ Preview な機能ですが、ECS について語りたいという方が周りに多かったので、開催する運びとなりました。

この辺から 完全理解シリーズの運営メンバーの一人 という認識ができてきたかなぁ?という気もします。

Virtual Summoner 公開………後、即取り下げ

Live2D と OpenCV と Dlib を用いたデスクトップマスコット召喚用アプリ(macOS 専用)を開発し、BOOTH にて公開しました。

が、「Live2D 社のライセンス的にマズいかもよ?」って指摘を頂戴して、急遽取り下げ。

その後 Live2D 社とのやり取りに2ヶ月くらい要するコトとなりました。

現在、紆余曲折あって Mac AppStore への公開に向けて審査待ち中です。

11月

Microsoft MVP 受賞!!!

monry.hatenablog.com

実は8月にセルフノミネートしており、本当は10月に発表されるハズだったのが、当落何れのメールも来ないので「落ちたのかなぁ…?」とか思っていました。
んで、11月3日の0時頃に自宅でくつろいでいるときに、何の気なしにメールチェックしたところ「受賞しましたよ!」というメールが届いており、衝撃のあまり大声を出して妻にキレられたのは良い思い出です。

これからも技術コミュニティへの貢献を頑張りたいと思います!

転職 LT #3 登壇

VTRyo (@3s_hv) さんはっせー (@Dear_you_cry) さん が主催する LT 会で登壇させてもらいました。

特別な目的があったわけではないのですが、たまたま見かけて LT 枠が空いていたので申し込ませていただいた感じです。

内容もそうなんですが、資料自体もお褒めいただいたので凄く嬉しかったです。

Gotanda.unity #9 in Unity Technologies Japan

遂に本拠地にカチ込みを…!

speakerdeck.com

運営やりつつ、Managed Debugger の使い方について LT してきました。

UTJ の人達が後ろにズラッと並んでて、ちょっと緊張しましたw

12月

七五三の写真撮影

娘が可愛すぎてヤバい。

[Unity Advent Calendar 2018] 参加

monry.hatenablog.com

10日目の記事を書きました。

ちょっと気合い入れすぎて、かなりのボリュームになってしまいました。

AssetBundle 編も書きたいです。

Unity Network 完全に理解した

当日の進行は良いとして、そろそろ事前準備とかをシッカリ進めないとダメだなぁとか痛感した回になりました。

なお、募集は100人枠が1時間足らずで埋まるという盛況っぷりで (((((゚Д゚))))) ガクガクブルブル してました。

LT メインの回は、まぁ良いとしてセッションメインになると、色々と調整が必要になるなぁ…。

【年末だよ】Unity お・と・なのLT大会 2018 運営・登壇

f:id:monry84:20181231214211j:plain f:id:monry84:20181231214230j:plain f:id:monry84:20181231214246j:plain

お酒飲みながら LT 大会するという、毎年恒例の Unity 部のイベントの運営をしました。

speakerdeck.com

私自身も登壇しており、自作の Timeline 拡張について話してきました。

ActiveTimeline 自体はもう少し改良したいと思っているので、今後にご期待ください!

Unity アンバサダー任命!!!

monry.hatenablog.com

2017年中頃から「もんりぃ先生」として本格的に外向きの活動を開始した成果を認めていただいた形となり本当に嬉しいです!

ちなみに、実はお話自体は10月の頭にいただいていたんですが、オフィシャルアナウンスがあるまで言えずにもどかしい2ヶ月半でしたw

2018年末時点で、日本で唯一の「Unity アンバサダー」と「Microsoft MVP」のダブルホルダーとなっておりますw

総括

やはり Unity アンバサダーMicrosoft MVP の二つが大きいトピックでした。

これに慢心せず来期以降も人の縁に感謝を忘れずに、公私ともに頑張っていく所存です。

ちなみに、マシュマロ受け付けているみたいですよ?

marshmallow-qa.com

*1:ごっこランドのコンテンツのコト

*2:娘がまだ小さいので妻と私とで交代しながら参加しています。

XsvUtility なる Unity ライブラリを作りました

github.com

CSV, TSV を Serialize/Deserialize する Unity 向けライブラリとして XsvUtility を作りました。

概要

XsvUtility は XSV *1 と任意の型とを相互に変換するためのライブラリです。

C# の属性をクラス・構造体のフィールド・プロパティに付与するコトで柔軟性の高い Serialize/Deserialize を実現しています。

何故作ったの?

キッカケとしては、以下のような流れ。

  • 「AssetBundle のサイズ情報を記録したファイルを Amazon S3 にでも置いて管理しようかな。」
  • JSON でも良いんだけど、CSV とか TSV のが楽なんだよなぁ…。」
  • 「でもパーサとか無いんだよなぁ…。」
  • 「作ろう。」
  • 「ついでだから Unity Package Manager で配信できるようにしてみよう。」

思いっきり車輪を再発明している気がしないでも無いですが、まぁ勉強目的ってコトで。

特徴

JsonUtility ライクな使い心地

UnityEngine.JsonUtilityFromJson<T>()ToJson() によって、 Serializable なクラス・構造体の Serializable なフィールドの値を読み書き できるわけですが、 XsvUtilityXSV をパースした結果の行・列を、特殊な C# 属性を付けたフィールド・プロパティに読み書きする 機能を Deserialize<T>()Serialize() というメソッドによって提供します。

リポジトリの README にも書いてありますが、以下のような感じです。

構造の宣言

class Foo
{
    [XsvRow]
    public IEnumerable<Bar> Bars { get; set; } // List<T> などの IEnumerable な Generics 型であれば何でも OK
}

struct Bar
{
    [XsvColumn(0)]
    public string Baz;
    [XsvColumn(1)]
    public int Quz { get; set; }
}

Deserialize/Serialize

var csvText = @"aaa,100
bbb,200";
var foo = Monry.XsvUtility.CsvSerializer.Deserialize<Foo>(csvText);
foo.Bars.ToList()[0].Baz; // aaa
foo.Bars.ToList()[1].Quz; // 200
var foo = new Foo
{
    Bars = new List<Bar>
    {
        new Bar {Baz = "aaa", Quz = 100},
        new Bar {Baz = "bbb", Quz = 200},
    }
};
var tsvText = Monry.XsvUtility.TsvSerializer.Serialize(foo); // aaa,100\nbbb,200

プロパティ・フィールドの両方に対応

Unity のシリアライザは仕様上、 [SerializeField] を付けたフィールドか public なフィールド のみをシリアライズ対象としています。

XsvUtility では、範囲を拡大して [XsvColumn] を付けたフィールドかプロパティ をサポートしています。

アクセス可視性についても、 privateシリアライズ対象としているので、既存のクラス・構造体を汚さないんじゃないかと思っています。

各行をパースした結果を保持するためには [XsvRow] を付けた IEnumerable<T> なフィールド・プロパティ を利用するようにしています。

また、現時点では IEnumerable<T><T> の型に対して [Serializable] なクラス・構造体であることを強制していません
これはいずれ仕様を変える可能性はあります。

特殊な XSV のパースに対応

Microsoft Office などで CSV を出力する際にカンマや改行を含むセルは " で囲まれるという仕様や、ダブルクォーテーションで囲まれているセル内のダブルクォーテーションは "" という風に重ねるという仕様があり、XsvUtility はそれをサポートしています。

詳しくはリポジトリに含めているテストを参照してください。

Unity Package Manager (upm) に対応

まだ完全民主化されていない Unity Package Manager ではありますが、依存を持たないパッケージであれば GitHub の URL を指定出来るようになっています。

ということで、 upm をサポートしてみました。

f:id:monry84:20181230022602p:plain

upm の仕様で、 package.jsonリポジトリルートに置かなければいけないため、 upm 用のリポジトリを別に分けて、開発用のリポジトリから submodule という形で upm 用のリポジトリ を参照させることにしました。*2

まだ author が表示されなかったり、category の使いどころが分からなかったりと、色々ありますが、今後の民主化に期待しましょう。

課題

Documentation, ChangeLog

upm 的にこの辺のルールがあるっぽいので、対応してみる所存です。

なんか、今の時点では Package Manager UI のリンクをクリックしても https://docs.unity3d.com/Packages/tv.monry.xsvutility@0.1/index.html 的な URL に飛ばされてしまうので、どういう形でサポートされるのかは未知数ですが。

パフォーマンス

リフレクションをガッツリ使っていたり、あまり最適化ができていなかったりするので、パフォーマンスはそんなに良くないと思います。

まぁ、そもそも CSV やら TSV やらは構造上最適化が難しい気もするので、あくまでサッと利用する目的ってコトで。

カリカリにチューニングしたぜ!って人からの PullRequest 受付中ですよ!w

*1:CSV, TSV など

*2:この辺改善されてくれると良いなぁ…。

初代 Unity アンバサダーに任命されました!

はじめに

こちらの記事 にあるように、この度、私もんりぃ先生こと森哲哉は「初代 Unity アンバサダー」に任命されました!

めっちゃ嬉しいです!!!

Unity アンバサダー is 何?

Ambassador は直訳すれば「大使」とかになると思いますが、平たく言えば「Unity のコトを広めたりコミュニティを盛り上げたりする人」のコトです。

Unity Technologies Japan のスタッフさんにより選ばれた Unity ユーザに与えられる称号のようなもので、社外エヴァンジェリスト制度と言い換えても良いかもしれません。

何が嬉しいの?

何よりも、これまでの活動成果を高く評価していただいたコトが最大の誉れです。

いわゆる名誉称号のようなものなので、直接的な金銭の授受などはありませんが、以下のような特典にあやかれます。

  • Unite などのイベントに無償招待
  • 任命期間中の Unity Pro ライセンス
  • デモプロジェクトなどへのアクセス権

どうやったらなれるの?

細かいレギュレーションは分かりませんが、私の場合は次に挙げる活動が評価されたのかな?と思っております。*1

  • 「Unity ◯◯完全に理解した勉強会」の継続的な開催
  • 「マンガでわかる Unity」のブログ連
  • UNIBOOK への寄稿

同期の id:lycoris102 は Gotanda.unity を始めとする多彩な勉強会・Meetup のオーガナイズを手掛けており、 id:naichilab は unityroom の運営や unity1week のイベント開催をしているなど、オンライン・オフラインを問わず活動を評価してもらえるようです。

おわりに

以下の3名の方々を最初の認定者とさせて頂きます。

とあるように、今後も認定者は増えていくものかと思います。

一緒に Unity のユーザーコミュニティを盛り上げる人が一人でも増えると嬉しいので今後の動きが楽しみです。

私個人としては、今までと特段変わらず、本業のプログラマとしての本分を忘れないようにしつつ、合間に勉強会の開催・登壇や記事・書籍の執筆を続けていく所存です!
また、現時点においては日本で唯一の「Unity アンバサダー」と「Microsoft MVP」のダブルホルダーということで、何か活かせるコトがないか夢想してみたいと思います。

*1:機会があれば評価ポイントを聞いてみたいです。

Unity 2018.3 で気になるポイント

はじめに

日本時間 2018/12/14 (Fri) 未明に Unity 2018.3 がリリース されました!
ホントに年内に出るか怪しかったので、 中の人お疲れさまでした…!

2018 系最後のメジャーアップデート *1 ということで、(元々ベータは試していましたが)改めて個人的に気になったポイントをダラダラ書き殴りたいと思います。

気になる機能

Nested Prefab

Unite Berlin か何かで発表された機能ですね。
発表の時に完成が起きたのには笑った。

今まで、ネストの深い Prefab を編集する際には、「一度 Hierarchy に配置してから編集 → Apply → Hierarchy から削除」という面倒臭い流れが必要でした。
今回、これが Nested Prefab の実装により、直接 Prefab を編集できるようになった形です。
詳しい使い方は誰か他の人が纏めているハズなので、そちらをご参照ください。

Package Manager

元々 2017.2 で入っていた Unity Package Manager が 2018.3 でアップデートされました。

大きな改善点としては、 Unity 非公式のパッケージも作成可能になった という点になります。

今の所、ローカルストレージと依存を含まない git リポジトリからの取得のみとなりますが、遠からず完全民主化されるものと思われます。
詳しくは コチラの記事 もご参照ください。

.NET 4.x / C# 7.3

遂に、.NET 4.x がデフォルトになり、大手を振って利用出来るようになりました。

更に、コンパイラとして Roslyn が採用されたこともあり、最新の C# 7.3 が利用出来るようになりました!ひゃっほぉぉぉい!!!

ランタイムでの AssetBundle 圧縮

全然詳しく調べていませんが、AssetBundle をランタイムで作成出来るようになったらしいです。凄いな。

2D Isometric Tilemap

Final Fantasy Tactics が作れるようになりますw

これで Tilemap 系は粗方実装された感じになりますかね。

Android Runtime Permissions

Android 6.0 からの Runtime Permissions を C# API レベルでサポートしてくれました。

これでまた一つ Netive Plugin が減らせますね。((そもそも AndroidJavaClass, AndroidJavaObject で頑張れば Native は不要なんですが。))

Visual Effect Graph (Preview)

すごい Particle 的なモノをノードベースのエディタツールで作成できる機能です。

既存の Shuriken は CPU ベースでの演算でしたが、GPU ベースでの演算になるためパフォーマンス的にも非常に有利とのコトです。

Lightweight Render Pipeline

2019.1 での正式リリースに向けて動いているっぽいです。

モバイルな人としては、気になります!

Cloud Diagnostics

元々 Unity Services に Performance Reporting というサービスがあったのですが、それの名前が変わったっぽいです。

Exception を Slack に通知とかもできるとかって話を聞いたことがあるので、その辺も試してみたいです。

Project Tiny (Tiny Unity)

数KB のプレイヤーをビルドできる凄いヤツ。

今の所 TypeScript での開発らしいですが、正式ローンチまでには C# で書けるようになるそうな。

まとめ

相変わらずメジャーアップデートはワクワクする機能がてんこ盛りですね!

早いとこプロダクトを移行しないと…!

*1:SemVer 的にはマイナーの桁ですが。

JetBrains Rider 2018.3 に搭載予定の神機能について

はじめに

JetBrains Rider 2018.3 の EAP*1 が 2018/12/07 にアップデートされ、EAP 8 が公開されました。

このバージョンに神機能が搭載されていたので、それをご紹介します。

神機能 is 何?

まぁ、落ち着いて以下の画像を見てくれ。

f:id:monry84:20181211142948p:plain

実行結果は以下の画像だ。

f:id:monry84:20181211142805p:plain

ご理解、いただけただろうか…?

そうです。 任意のクラスが、どの GameObject/Prefab で利用されているかを探してくれる機能 が搭載されたのです!神!!!

使い方

Editor Plugin 更新

  1. JetBrains Rider EAP を更新
  2. Rider で Unity プロジェクトを開いて Assets/Plugins/Editor/JetBrains/JetBrains.Rider.Unity.Editor.Plugin.Repacked.dll を最新に更新

クラスを探す

  1. 探したいクラスのコンテキストメニューか左側のアイコンから Show usages in Unity を選択
    f:id:monry84:20181211145032p:plain
  2. Unity Editor にフォーカスが移って、利用箇所が表示される
    f:id:monry84:20181211145058p:plain

メソッドを探す

  1. 探したいメソッドのコンテキストメニューか左側のアイコンから Show usages in Unity を選択
    f:id:monry84:20181211145424p:plain
  2. Unity Editor にフォーカスが移って、利用箇所が表示される
    f:id:monry84:20181211145257p:plain

所感

いや、これはマジで控えめに言って神機能ですよ。ホント。

特に、メソッドの検索が相当アツいです。

ますます JetBrains 製品から離れられない身体になってきています…w

*1:Early Access Program

ごっこランドを支える技術 〜ビルド編〜

はじめに

この記事は、 Unity Advent Calendar 2018 の10日目の記事になります。
9日目の記事は gremito さんの AR上にShaderを動かしてみた という記事でした!

本記事は、株式会社キッズスターが開発・運営を行っているごっこランドというアプリの裏側を支える技術を少しずつ紹介する(予定の)連載 *1ごっこランドを支える技術」の ビルド編 になります。

ごっこランドは Unity 製モバイルアプリとして約5年に渡って運営されているのですが、月日を重ねるにつれて日々巨大化していくプロジェクト開発者を取り巻く環境・状況の変化への対応を行ってきました。
その結果として、様々な工夫が組み込まれたビルドシステムが構築されているので、本記事ではそのビルドシステムについて紹介をしていきたいと思います。

目次

  • 概要
  • 背景
  • 詳細

概要

もの凄くザックリ言うと、Slack にコマンドを打ち込んでしばらく待つと .ipa.apkDeployGate に配信される という仕組みです。

図で説明すると以下のような感じです。

image

上図をテキストでも解説すると以下のような感じです。

  1. Slack に jenkins build player <project_name> と発言する
  2. Slack Outgoing Webhook が実行される
  3. AWS API Gateway により発行された URL を叩く
  4. AWS Lambda にデプロイ済の Node.js アプリが実行されて Slack 上での発言を解析する
  5. 社内に配備してあるビルドサーバの Jenkins のパラメータ付きジョブを実行する
  6. Unity Editor を batchmode で起動し、 UnityEditor.BuildPipeline.BuildPlayer() を実行する
    • iOS の場合 PostprocessBuild 内で xcodebuild コマンドを実行し、アーカイブを作成する
    • Android の場合 PreprocessBuild 内で Keystore に関する設定を行う
  7. PostprocessBuild 内で作成されたアーカイブ ((iOS.ipaAndroid.apk)) を DeployGate にデプロイ
  8. DeployGate の Slack 連携設定により、Slack にデプロイ完了が通知される

詳細は次節以降で解説します。

Unity バージョン

2018/12/10 (Mon) 時点では Unity 2018.2.17f1 を用いています。

開発中は常に最新に上げ続けており、リリース内容が確定した時点で当該ブランチに於ける利用バージョンを最新バージョンでロックしビルドしています。

ビルドプラットフォーム

iOSAndroid 向け*2にビルドしています。

プロジェクトサイズ

$ du -sh Assets
5.1G    Assets

2018/12/10 (Mon) 時点でプロジェクトの総サイズは 5.1GB です。 Library/ ディレクトリも含めると 20GB を超えていました。

背景

上述の通りプロジェクトのサイズが割と大変なことになっているため、ごっこランドの開発では プロジェクト分割 というテクニックを用いています。

以下のスライドで簡単に纏めていますが、ざっくり言うと 個別の Unity プロジェクトとして開発したものを npm を使って1つのプロジェクトとして束ねる 仕組みを構築した感じになります。

そして、複数の開発プロジェクトが並行して走っている状態で、開発者一人一人の開発生産性を最大化する必要性が高まってきていました。
そのためには、個々の開発プロジェクトや束ねたプロジェクトを、開発者のマシンリソースを使わずにビルドできるようにする必要があります。
この課題を解決するために、専用のビルドサーバを配備*3し、開発者が任意のタイミングで実機ビルドを作成出来るようにしようと思い立ちました。*4

また、株式会社キッズスターでは、結構カジュアルにリモートワークが行われています。
そのため、VPN とかを使わずとも社内ネットワークにあるビルドサーバでビルドできるようにする必要性もあります。

更に、可能な限り API Token や認証鍵などの 秘匿すべき情報をリポジトリに載せたくない ので、その辺りにも気を遣う必要があります。

これらの課題を解決するために回りくどいシステムを構築した次第です。
次節から各項目について掘り下げていきます。

詳細

システム構成

改めて概要の図を掲示します。

image

Slack → AWS API GatewayAWS Lambda

いわゆる ChatOps の基本的な構成になるかと思います。

Slack の任意のチャンネルに対する発言などを任意の URL に対して POST してくれる Outgoing Webhook という仕組みを使います。
そんなに難しくないのでググれば簡単に設定できると思います。
AWS の権限管理の仕組みである IAM 辺りはハマるかもですが、基本はテンプレ通りにやれば問題ないかと思います。

Lambda に配置する関数としては、Slack の発言内容をパースして Jenkins のパラメータ付きビルド URL を構築する という要件を満たせば、どんな言語で書こうが問題ありません。*5
(今回のアドカレの趣旨からは外れてしまうので仔細は書きませんが、需要があればいつか別記事で掘り下げるかもしれません。)

AWS Lambda → Jenkins

組織によってはココが最大の障壁になると思います。
と、言うのも、AWS 側から社内ネットワークに向けた内向きのアクセスを許可する必要があるため、セキュリティが厳しい組織の場合ココで詰む可能性を秘めています。
その場合でも、外向きのアクセスは行けると思うので、Lambda からジョブパラメータを JSON か何かで S3 に Put して、Jenkins でソレをポーリングするとかもアリかもしれません。頑張ってください。

Jenkins → Unity Editor

Jenkins のジョブ設定で、シェルを叩くことができるので、 /Applications/Unity/Unity.app/Contents/MacOS/Unity を実行するようなシェル(後述)を書きます。

前提として、ビルド時のエントリポイントとなる public static なメソッドが必要になるので、何らかの形でプロジェクトに組み込んでおきましょう。
弊社では umm/simple_build: Provide BuildPlayer menu というライブラリを開発し利用しております。

Keystore 設定(Android のみ)

Android の APK を作成するにあたって、Keystore による署名を施す必要があります。
ビルド処理実行前に ProjectSettings を上書きしてあげる必要があるので、 UnityEditor.Build.IPreprocessBuildWithReport を実装したクラスの OnPreprocessBuild() メソッドにて UnityEditor.PlayerSettings.Android.(keystore|keyalias)(Name|Pass) を上書きします。
鍵の情報をリポジトリに載せるのは危ないので、環境変数などから貰うとヨサソウです。
弊社では、 umm/keystore_manager: Manage Keystore for Android というライブラリを用いています。

Build

UnityEditor.BuildPipeline.BuildPlayer() を実行します。

出力先は何でも良いと思いますが、弊社では simple_build 側の実装として <path_to_project>/Build/ の下にプラットフォーム毎・環境種別(開発か本番か)で分けて出力するようになっています。

Archive/Export (iOS のみ)

いくつか方法はありますが、PostprocessBuild として実装するのが筋が良いでしょう。
具体的には UnityEditor.Build.IPostprocessBuildWithReport という interface を実装したクラスの OnPostprocessBuild() メソッドにて /usr/bin/xcodebuild コマンドを実行する形になります。
Android の場合は直接 .apk ファイルが出力されるので、この手続きは不要です。*6

弊社では umm/xcode_archiver: Run xcodebuild on PostprocessBuild というライブラリを用いてアーカイブしております。

こちらを用いない場合でも、以下のようなコマンドを構成すれば Archive/Export が行えます。

Archive

Unity から出力された Xcode Project を .xcarchive としてアーカイブします。
Firebase などの CocoaPods を利用するような Native Plugin を用いている場合は -project の代わりに .xcworkspace へのパスを -workspace 引数に指定する必要があります。

$ /usr/bin/xcodebuild \
 -project "<path_to_build>/Unity-iPhone.xcodeproj" \
 -scheme "Unity-iPhone" \
 -archivePath "<path_to_build>/Unity-iPhone.xcarchive" \
 -sdk iphoneos \
 -configuration Release \
 -allowProvisioningUpdates \
 archive

Export

先ず、Export Option と呼ばれる .plist ファイルを作成します。*7

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>ad-hoc</string>
    <key>compileBitcode</key>
    <false/>
    <key>embedOnDemandResourcesAssetPacksInBundle</key>
    <false/>
</dict>
</plist>

続いて、作成した Export Option とあわせて xcodebuild コマンドを実行します。

$ /usr/bin/xcodebuild \
 -exportArchive \
 -archivePath "<path_to_build>/Unity-iPhone.xcarchive" \
 -exportPath "<path_to_build>/export" \
 -exportOptionsPlist "<path_to_build>/ad-hoc.plist" \
 -allowProvisioningUpdates

Deploy

検証用端末などにデプロイするために DeployGate というサービスを用いており、同サービスが提供するコマンドラインインタフェース*8を実行するコトでビルド成果物をデプロイします。

以下のようなコマンドを構成すれば OK です。

$ dg deploy <path_to_archive>

DeployGate の機能として、新しいビルドがデプロイされると Slack に通知する機能があるので、それを有効にしておくと便利です。

プロジェクト構成

「背景」の章でも述べたように、弊社では複数のプロジェクトとして開発したゲームコンテンツを一つのプロジェクトに束ねてアプリにしております。
そのテクニックや注意点などについて掘り下げて紹介します。

マージ

プロジェクトを束ねる際のツールとして npm を用いています。
個々のプロジェクトを npm のパッケージと見なして、本体のプロジェクト側の package.json に依存パッケージとして定義するコトでマージを行います。
その際、インストールされた個別プロジェクトの中身を Assets/Projects/ 以下に丸っとコピーするスクリプトを書いて postinstall*9 内で実行させています。

なお、実行速度の観点から、生の npm ではなく yarn を用いて実行しています。

ライブラリ管理

弊社では umm という仕組みを用いてライブラリ管理を行っています。
仔細は上記リポジトリをご参照いただくとして、概要としては各ライブラリを npm のパッケージとして取り扱えるようにすることで npm を用いた依存管理を行えるようにするものとなります。

現在の所、各ライブラリ npmjs へはパブリッシュしておらず*10GitHub にて公開しているモノを利用しています。

SortingLayer / Tag

複数プロジェクトをマージする関係上、SortingLayer や Tag などに代表される個々のプロジェクト設定として保存される情報は原則的にコピーできません。
これらの情報は ProjectSettings/TagManager.asset というファイルに保存されるのですが、全てのプロジェクトで設定が同じになるようにする必要があるため、無闇に増やせないなどの制約が生じています。

また、SortingLayer に関しては、表向き文字列ですが内部的には数値で管理しており、この値をプロジェクト間で統一することが難しかったため、独自のエディタ拡張*11を実装することで問題を回避しています。
特別な事情が無ければ SortingOrder だけで頑張るなどの工夫をした方が良いかも知れません。

Shader

個別のプロジェクトのスクリプトとシェーダを除くあらゆる Asset は基本的に AssetBundle として配信するため、設定に依ってはシェーダがアプリに含まれなくなることがあります。
そのため、都度 Always Included Shaders に含めるように設定するなどの作業が必要になる場合があります。

link.xml

Scripting Backend に IL2CPP を用いており、かつ AssetBundle を用いている場合、 Unity - Manual: Managed bytecode stripping with IL2CPP に記載があるように、一部のコードが削除されることがあります。
これを回避するために link.xml に情報を追記したり、 [Preserve] 属性を付けるなどの工夫が必要になることがあります。

Packages

2018年12月現在、 Unity Package Manager では GitHub などの git リポジトリからのパッケージ取得を完全にはサポートしていません。
詳細はブログを書いたのでそちらをご参照いただくとして、弊社では上述の通りライブラリの管理も npm を通して GitHub から取得する方法を採っているため、個別プロジェクト側で必要になったパッケージの依存解決を自動では行えません。
そのため、個別のプロジェクトで必要になったパッケージは、本体側のプロジェクトの manifest.json に手動で記載しないといけません。

この辺は Unity Package Manager が完全民主化されたあかつきには不要の悩みとなりそうです。

Assembly Definition Files

コンパイル時間の高速化とライブラリ間の循環依存を未然に防ぐために、Assembly Definition Files を積極的に導入しています。
各プロジェクトを個別の Assembly として切り出すため、 namespace などの重複は神経質にならなくても済むようになりました。*12

ビルドスクリプト

Jenkins が実行するビルドスクリプトの概要をご紹介します。

パラメータ

Jenkins のジョブとして受け付けるパラメータは以下のように設定しています。

Name Example Description
repository pretendland プロジェクトの名称
clone 先のルールを統一することで、リポジトリ名からパスを特定可能
branch develop/v4.10.0 ビルドするブランチ名
省略した場合は master をビルド
platform iOS ビルド対象のプラットフォーム
Switch Platform の効率を考えて、プラットフォーム毎に clone 先を分けている
editor_version 2018.2.17f1 起動する Unity Editor のバージョン
未指定の場合は ProjectSettings/ProjectVersion.txt の値を利用
development_build true 開発ビルドを作成する場合に真を指定

処理の流れ

  1. cd <path_to_project>
    • 先ず、パラメータとして渡された repositoryplatform から推定されるプロジェクトディレクトリに遷移
  2. git checkout <branch_name>
    • パラメータに指定されたブランチに checkout
  3. git lfs pull
    • サイズが大きいリポジトリの場合 Git LFS を用いているコトがあるため、実体を取得する
  4. yarn install
    • package.json, yarn.lock の情報に従い、パッケージを fetch, install
  5. /Applications/Unity/Unity.app/Contents/MacOS/Unity
    • simple_build のメソッドを実行
  6. git reset && git clean -fd
    • ビルド完了後、ビルドサーバ上のローカルリポジトリを掃除
  7. git checkout master
    • 元のブランチに戻って終了

Unity Editor 起動時引数

最低限、以下の引数が指定されていれば batchmode ビルドが可能です。

Argument Value Description
-quit ビルド完了時に Unity Editor のプロセスを終了させる
-batchmode Unity Editor の GUI は起動させない
-projectPath <path_to_project> プロジェクトのディレクト
Assets/ProjectSettings/ がある親ディレクトリを指定する
-executeMethod <method_name> 実行する public static なメソッド名を namespace を含む完全修飾名で指定
-logFile /dev/stdout Jenkins のログ管理に流すためにログの出力先を標準出力に設定する
-buildTarget [iOS|Android] ビルド対象のプラットフォーム
既にプロジェクトが Switch Platform 済であれば不要

そのほかの Unity Editor 起動時の引数は Unity - Manual: Command line arguments をご参照ください。

おわりに

ここまでお読みいただき、まことにありがとうございました!

もし貴方がオレオレビルドシステムを構築しようと思っており、本記事に構築の一助となるような情報があったのならば、心から嬉しく思います。

Unity Advent Calendar 2018 の11日目は copo さんの「インテリアマッピング(interior mapping)~その1~」です。

*1:本記事が第一回目なんですけどね。

*2:iOS SDKAndroid SDK ともに Latest でビルドしています。

*3:iOS のビルドを考慮し Mac mini を採用しています。

*4:勿論 Unity Cloud Build を用いる選択肢もあったのですが、柔軟性や後述のライブラリ管理の観点から断念しました。

*5:私は Node.js で書きました。

*6:Android Studio で開くためのプロジェクトを出力することも可能ですが、本記事では割愛します。

*7:この例では Bitcode や OnDemand Resources などを無効にしていますが、プロジェクトにあわせて変更してください。

*8:Ruby の gem として提供されています。

*9:記事執筆時点でレイアウトが崩れていましたが、頑張れば読める…かな?

*10:中身は Node.js じゃないので Ban されても嫌だな、というコトで。

*11:現在の所、弊社 Organizations の private リポジトリで管理しています。

*12:とはいえ、可読性などの観点から namespace の設定ルールは割と厳格にしていますが。