YAMADA TAISHI’s diary

ゲームについてとか私の日記とか。このブログのあらゆるコードは好きにどうぞ。利用規約があるものは記事内のGitHubのRepositoryのリンクで貼られていると思うので、そちらを参照ください。

鈴木竹治氏のフォント「Fonts66コンプリートパック/109書体 -商用利用可」はUnityのSDFで使える?問い合わせてみた

こんにちは、やまだたいし( やまだ たいし (@OrotiYamatano) / Twitter )です。
以前、Fonts66のセールがあり今回はUnityのTextMeshProでSDFを使いたいと思ったんですが、
使えるかどうかが不明だったので問い合わせをしてみました。

目次


なぜ問い合わせをしたの?


様々な用途で使えるようですが、ゲームで使う方法については具体的に記載されていません。
以前から私も気になっていましたし、今回セールがあり他にも気になる人が多く出てきそうなことや、Unityで使わず死蔵してる人も多いと思ったので問い合わせてみました。
以前ゲームない使用については、Unity AssetStoreさんが問い合わせをされていたようですが、SDFで使えるかどうかについては詳しく記載されていませんでした。

www.asset-sale.net

ズームしても滑らかに表示されるためNGだと思います

と書いてあるけど、具体的には不明?

今回のセール


nlab.itmedia.co.jp

27万円→2980円になるセールです。
半年に1回ぐらい(?)のペースでセールをされているようです。
とても安いです。

で、使えるの?


Dynamic SDFについては、もちろん使えません。
動的にフォントSDFを生成するためにゲーム内バイナリにフォントデータが含まれることになります。
ですので、PDFと同様に使用は出来ません。

しかし、Static SDFについては使えるようです!

問い合わせをした文章


ちょっと日本語が変ですが、私が問い合わせをした文章がこちら。

個人ゲーム開発者の山田大志です。
Fonts66の利用についての問い合わせです。
私はFonts66をゲーム内での利用を検討しています。
そこでゲームエンジンUnityのTextMeshPro機能にてSDF(Signed Distance Field)形式『ビットマップ画像だけれど、輪郭をきれいに出すプログラムを利用して表示させるもの』が利用可能かを伺いたいです。
以前Fonts66のゲーム内利用については、ビットマップでの利用ならOKとの回答をしていたようですが、( https://www.asset-sale.net/entry/Vector_Fonts66 )
SDF形式は「フォントデータを一部取り出しビットマップの画像形式で保存し表示させるもの」ではあるものの、「拡大縮小で品質が大きく変わるものでは無い」のですが、利用する場合は問題があるのでしょうか?
ご回答いただけますよう、よろしくお願いします。

そして、スキルインフォーメーションズさんの回答がこちら。
(念の為、担当者名は伏せます)

山田大志様
スキルインフォメーションズのxxと申します。
この度はFonts66についてのお問い合わせ
誠にありがとうございます。
ご質問いただきました内容についてですが、
ビットマップ化された画像データをゲームに搭載いただくことは
可能ですが、フォントデータそのものをゲームに実装、搭載する
ご使用方法は不可となります。

とのことです。

つまり今回は フォントデータそのもの ではないからOKだと思われます。

SDF形式を知らない可能性が高い気がしますが、一応、

SDF形式は「フォントデータを一部取り出しビットマップの画像形式で保存し表示させるもの」ではあるものの、「拡大縮小で品質が大きく変わるものでは無い」のですが、利用する場合は問題があるのでしょうか?

と私が軽く説明した上で返答が来ているので大丈夫だと思われます。
念押しとして本日(2020/08/24)以下の文章で返信をしておきました。

回答ありがとうございます。
フォントデータそのものが含まれないのであれば
SDF形式で利用が可能ということで実装させていただきたいと思います。

何か齟齬があれば返信が来るはずなので、その際はこの記事を編集しようと思います。

生のフォントデータそのものをゲームソフトに組み込むことについては、別途契約が必要らしいので、組み込まないようにだけ気をつけましょう!
またPC1台につき1ライセンスだということにも気をつけましょう。複数台で動作確認する際は台数分購入するようにしましょう!

Unityでstatic SDFで使う時に参考にできる記事


qiita.com

ということで、このあたりを参考にfontをベイクして使ってしまいましょう!

まとめ


Static SDFなら使える!ということで回答を得ることが出来ました。
万が一、齟齬があったら訂正記事を出そうと思います。

ということで皆、格安セールのうちに!Fonts66を買おうぜ!
TxetMeshProをStaticで使う方法についてはこちら↓
orotiyamatano.hatenablog.com

【備忘録】怠惰な人(私)が書いたZenject(Extenject)の使い方の説明

こんにちは、やまだたいし( やまだ たいし (@OrotiYamatano) | Twitter )です。
今回はZenject(Extenject)の使い方についてです。
自分が使い方をよく忘れるので備忘録、まとめ用です。

N番煎じですので、参考にはならないと思います。

目次


Zenject(Extenject)とは


一応解説です。

DIフレームワークです。
DIとは依存性の注入(Dependency injection)です。
誤解を生みそうなくらい簡単にいうと、いい感じにクラスとかの初期化とかをやることをDIっていいます。
依存性っていうかオブジェクトの注入だよね。外部からオブジェクトを注入して初期化することをDIっていう。
(依存性って直訳するからわかりにくいだけで、切っては切り離せないものの注入って感じで訳した方が伝わりそう?)
初期化するときにDIコンテナというのを使っていい感じに自動で初期化してくれるのををDIフレームワークと言います。

厳密に詳しいこと知りたい?うるせぇ!コレは備忘録だ!説明書いてるだけありがたく思いやがれ!他の記事に行ってくれ。

他にも私が使ったことあるやつでDI使われてるフレームワークはSpringFrameworkとかZend Frameworkだな!
Webのやつだ!ただこの2つはDIフレームワークではなくて、DIも含まれるフレームワーク


私がZenjectなのになんでタイトルで(Extenject)ってついてるかって?
Zenject≒Extenjectだから。
Extenjectについては色々あるんだけど、元々のZenjectのメインメインコントリビューターのSteve Vermeulen氏がZenjectの権利関係で揉めたからとかなんとかで
Steve Vermeulen氏がメインで開発してるのにSteve Vermeulen氏がいてた会社がZenject権利を主張して色々揉めたって感じなのかな?詳しいことは知らん。
ま、それでSteve Vermeulen氏が別途つくったやつがExtenjectってわけ。なのでこの記事ではZenjectって私は呼んでるが、実質私がつかってるのはExtenjectの方。
Zenjectは更新されてないのでExtenject皆使おうね。

github.com

DI使う利点って何よ!


DIすると密結合の設計が疎結合になるって思ってる人がいるけど、それは違くて、
DIを使えれば疎結合に設計されたものを疎結合に保ち続けやすいって話。
だから、「イカしてるからDIフレームワーク導入しようぜ!」ってプロジェクトの途中で導入はやめたほうがいい。
止めはせんが、覚悟はしたほうが良い。

後単純にDIするだけでなくDIフレームワークを利用すると初期化の手間が省けてのが副産物的にうれしいって感じ。
メインは疎結合にするものだから、(後で軽く解説するけど)いろいろな初期化の手間を省くためだけに利用するのだけはやめたほうがいい。


あと、もう少し詳しく説明する。

グローバル変数で定義するのは良くないっていう理由で
シングルトンっていうデザインパターンがあるけど、
それもキレイじゃないって言われていて
サービスロケーターパターンってのを使い始められてるけど、
それすらもキレイじゃないって最近は言われてるのよね。

更にキレイに使えるようにしようってなって出てくるのがDIってわけ。

blog.a-way-out.net

場合によってはサービスロケーターやシングルトンも使うけど、基本DIでOK。

で、使い方


DIフレームワークっていうけどUnityで色々使えちゃうのよね。
逆に色々使えちゃうがために相応しくない使い方をしてしまって阿鼻叫喚する人もいる。
いくらいい感じに初期化してくれるからって何でもかんでも初期化対象にしたらゲームが始まるときとかに、初期化処理が走りまくって、とても遅くなるし、最悪の場合、ゲームが止まる。
まぁ、最初はグローバルで定義してるシングルトンやサービスロケーターを消すだけのために導入はありなんじゃないかな。

初期化処理で阿鼻叫喚した話は別の人がスライドとかで発表してた人がいたと思うので「Unity Zenject完全に理解した」とかで検索してくれ。
多分そこで言ってたと思う。記憶が正しければ。
ただ、ちょっと古い発表会なので、そのままコードは使えないこともあるので概念の理解だけに留めておいたほうがいいかも?
しらんけど。

さて、使い方を説明していく。

Zenject Binding


コンポーネントを自動でアタッチしてくれるやつ!
色んなオブジェクトにアタッチしないといけないときに、毎回[SerializeField]って定義したスクリプトに手作業でアタッチしていくのって面倒くさくない?
え、面倒くさくない?だったら手動でやってください。DI使うより初期化の動きの負荷がないのでそっちが良いと思います。この部分は終わり。

面倒くさい場合はDIで自動でアタッチされるようにしましょう。

1.アタッチするGameObjectをつくる
2. Zenject Bindingというスクリプトコンポーネントをプロジェクト上のどっかのオブジェクトにアタッチする(まぁ、普通に1のオブジェクトのほうが良いと思う)
3.Zenject BindingコンポーネントのComponentsにアタッチしたいオブジェクトを設定する。
4.[SerializeField]って書いてるところを替わりに[Inject]って定義する
5.終わり!

え、アタッチしたいオブジェクトが複数あって違うオブジェクトをそれぞれアタッチしたい?非MonoBehaviourとかのクラスを注入したい?シーン上に置かれてないやつをアタッチしたい?

うるせぇ!知るか!どういう設定でインストールするかっていうのはスクリプト書けば設定できると思うけど、そこまでは知らん!
↓でも読んどけ!

light11.hatenadiary.com

~~~~Context


シングルトンの消し方についてだ!
私はキー入力まわりをZenjectでいい感じにすることが多い。
人によってはシーン制御の共通系スクリプトとか、ネット通信周りとか、サウンドマネージャー的なやつをZenjectに任せるんじゃないか?しらんけど。

で~~~~Contextだけど、SceneContextとかProjectContextとかGameObjectContextとかあるけど、
DI対象を決めるために種類が分かれてるんだよね。

SceneContextならScene上にあるやつ全部、ProjectContextならプロジェクト上全部、GameObjectContextならアタッチしたゲームオブジェクトだな。

ぶっちゃけ面倒くさい人はProjectContextでも良いとは思うけど依存性を考えると一番はGameObjectContextよな。
しかし、私は面倒くさい!ので間をとってSceneContextを使う!一般的にもSceneContextが普通じゃないですかね?しらんけど。
シーンまたいで手軽に設定したい人はProjectContextを使うと良いんじゃないですかね。

肝心のSceneContextの出し方?他の記事をググれ。
で、実際に~~~~ContextでBindする方法だけど、それは、スクリプトを書かないといけない。

そのBind設定のスクリプト書くときに、このBindするスクリプトはプロジェクト上で一つだけ!とか複数個欲しいだとか生成するタイミングだとかは定義出来たはず。

備忘録用に私が使うキー入力のスクリプトだけ書いておく。

using xxxx.Util.Input;
using Zenject;

namespace Util.ZenjectInstaller {
    public class InputInstaller : MonoInstaller
    {
        public override void InstallBindings()
        {
            Container.Bind<IInputEventProvider>().To<InputEditor>()
                .AsCached();
        }
    }
}

何やってるかというと、[inject] IInputEventProvider hoge; って書いてるところにInputEditorをシングルトン的な感じでBindしてねってこと。
なんでIInputEventProvider とインターフェースを定義してるかっていうとInputEditorのところが差し替えやすいから。
TestInputとかInputSmartphoneとか別途作って定義おけばビルドごとに差し替えが出来たり楽よね。
NPCとかで擬似的にキー入力させたりとか?モンキーテストしたりとか、媒体によって変えたりとか?疎結合だからキーコンフィグ周りのコードもスッキリしそう。
こういうところをこんな感じでインターフェースを使って疎結合化することを依存性逆転の原則に則った設計っていうけど今回の筋からは外れるので解説は割愛。

「書いたスクリプトをどこにアタッチさせて利用できるようにするのか?」とか詳しい設定とかは他の人の記事を読んでくれ。説明面倒くさい。

qiita.com

マルチシーンで使いたいけどProjectContextは使いたくないとき


使いたいことがあったので書いておく。
それぞれのSceneでSceneContextを定義して親になるSceneContextを用意。

親のSceneContextに名前を設定する。

f:id:OrotiYamatano:20200808034224p:plain
親の名前

子供のSceneContextに親のSceneContextの名前を指定する。

f:id:OrotiYamatano:20200808034343p:plain
子供の方に親の名前を指定

後は、先に親のシーンから読み込まれるようにしておけばマルチシーン構成でもいい感じに親子関係なくBind出来るはず。

まとめ


雑にかきましたが、自分用です。
特に見る人も居ないだろうし、適当でいいよね?
他の人の参考になったら儲けもの程度に考えておきます。
この解説じゃ全然物足りないよーって人はimoさんの本がとても良いので買うと良いと思います。

booth.pm

では、アデュー。

1ヶ月GameAWeekに挑戦して失敗したって話

こんにちは、やまだたいし( やまだ たいし@ソシャゲプログラマ (@OrotiYamatano) | Twitter )です。
去年からGame A Weekやってみたいなと思って思い切って挑戦したら失敗したって話です。
今回はその時の体験談です。知見は少ないです。ただ私が語りたいだけです。

目次


Game A Weekとは

説明


2dgames.jp

インディー系デベロッパー「Vlambeer」のRami Ismail氏さんが提唱したもので簡単に言ってしまえば、
1週間でゲームを作りソレを何週間か続けることです。

  1. 毎週ゲームを作る
    月曜日の12:00にプロジェクトを開始し、日曜日の23:59までにゲームを作り上げること

  2. 毎週ゲームをリリースする
    作ったものは例えクソゲーでもWebサイトを通じて配信を行うこと。さらにSNSやブログなどでそれを告知すること

  3. 作り終えたゲームは修正しない
    ゲーム完成後は手を入れてはダメ。どうしても修正したい場合は Game A Week 終了後に行うこと

  4. パターン化を避ける
    毎週、異なることにチャレンジすること。例えばデジタルゲームを作る代わりにアナログゲームを作る、アクションゲームではなくパズルゲームを作る、など

  5. 振り返りを行う
    作って良かったところ、間違っていたところ、興味深かったところ、などをまとめておきます。作ったゲームは何人かにプレイしてもらい感想を聞くこと。そしてその感想をまとめておくこと

上記の様なルールがありますが、私には無理だと思ったのでMyルールを設定してはじめました。

Myルール


好きなこととか用事とか全部キャンセルせず、健康的に(睡眠をしっかりとって)、Game A Weekを成功させる
配信はできなくても良い(ゲームは完成しなくても良い)。
金曜日開始、木曜日終了

まぁ、ゆるゆるに設定。

なんで始めたのか

いろんな人のGame A Week(っぽい)作品


Downwellで有名なmoppinさん!

madewithunity.jp

ui_nyanさんの作品!

uinyan.com

uinyan.com

坪倉さんのHack A Week!

www.slideshare.net

しゅんさんのGame A Week!

note.com

そして、Game A Weekとは違うけど、Unity1Weekで回を重ねるごとに強くなるUnityゲームプログラマ達、Unity1WeekきっかけでTGS出展する方々。
私は思いました。

「Unity1Week数回重ねて超強くなるエンジニア多いし、何回もやればめっちゃ強くなるじゃん!」

ただの馬鹿である。

後、世の中に出てるけど、はじめは、ほんのちょっとの時間で作られたゲームも市場には多かったりするので、
フラッシュアイデアを形にする習慣をつけておけば今後にも役に立つと思ったので取り組みました。

Game A Weekを通じて

私が感じた利点と欠点を紹介していきます。

利点


  1. 毎日試行錯誤が出来る
    必然的に毎日コードを書くことが出来ます。いつかやろうと思ってたことをやれるいいチャンスでした。使ってないアセットや利用したことのないサービス、設計、スケジュール管理いろいろ。

  2. 毎日コードのことを考えるようになる
    毎日コードのことを考えているおかげで、いつもは至らないところまで思考が回ります。設計やプロジェクトの構成、面倒な設定の自動化業務にも生きてくるような内容を考えるようになります。

  3. 日々の効率化
    毎日ゲームを作らないといけないので、週ごとに段々行動が効率化されていきます。効率化をしないとゲームを作る時間が確保出来ないからです。

  4. ゲームアイデア脳の成長
    コードのことも毎日考えるようになるんですが、ゲームのネタを考える時間が増えます。なんてったって毎週別のゲームを作らなければならないのですから。ふと、日常の光景を目の当たりにした時、これゲームに出来ないかなとか考えるようになります。

欠点


  1. 疲れる
    ただただ疲れる。1週間ならともかく何週間も続くと疲労困憊です。能力がないと続けられません。特に家事や睡眠や用事を削らずにゲームを作り続けるのは至難の技です。

  2. 自由がなくなる
    ゲームを作っている間、その他のことが出来なくなります。ゲームを作っていてゲームをする時間がないという事態に私は陥りました。

  3. 自分の無能さを思い知る
    一応、ゲームプログラマを職業にして働いてる私ですが、Game A Weekをやって1作品も仕上げられませんでした。いくらチーム作成じゃないからとは言え、あまりにひどい。無能さを思い知りました。ちょっと修行しなおして来ます。人によっては自信を無くしてしまうので諸刃の剣だと思います。

思ったこと(ポエム)


Game A Weekを通して思ったこと。
ゲームを1週間で作れる人たちはやはり凄い。
自分の無能さと土日が自由に出来ないことへの苦痛、ゲームの実装時間の関係で調べきれないアセット機能を触りきれないもどかしさ。
普段、どれだけ潤沢な時間の中でゲームを作っているのか思い知らされた。
思い返してみれば学生時代より実装時間が長くなっている。
丁寧になっているとも言えるが、あの時ほどの勢いが無くなって来ていると感じる。
作業を多くしていると学生時代や社畜をしていた時期を事細かに思い出す。

体は疲れているのに(ゲームを作成するサークルとプログラミングのアルバイトをやりながらだったので日曜日しか休みが無かったにもかかわらず)なぜか家でコードを書いていた私を思い出す。
くたくたになりながら(月90時間残業)、クソコードを産み出しながらも実装をバリバリ進めて行った私を思い出す。
社畜の時は30分もあれば一つのタスクが終わっていたし、学生のころは1時間あれば一箇所のコードを4回は書き直している。
今は違う。
一つの実装に3時間以上かけることも多い。

全てが良かった訳じゃないけど、確実に書いてる時の方が実力が上がっていた。
最近は狂うような狂気の中に居ない。

言い訳はいくらでも出来る。
実家暮らしじゃ無くなった、今回はGame A Week中に身内が亡くなった、会社からの強制ではない、チームの作業じゃない。真っ当な理由だ。

だけど、出来ないのは、それだけじゃない何かがあるような気がした。

作業途中、学生時代に「1時間あれば何か実装できただろ!」と先生に怒られたことを思い出した。
きっと今回も何か出来たはずなんだ。
当時は「確かに、その通りだ」と思っていたが、最近はそうでもない。

そんな学生時代を思い出したということは、もしかしたら、今回は少しだけ過去の狂気に近づいたのかもしれない。
そんな気がした。

Game A Weekはまだ無理だけど、とりあえず、毎日コードをかけるようにしようと思った。

その他


Game A Week中のツイートです。

【Unity】TilemapでRayが衝突した場所のTileを消す

こんにちは、やまだたいし( やまだ たいし@ソシャゲプログラマ (@OrotiYamatano) | Twitter )です。
Unity1WeekJamの時にTileMapを消す処理を書いた時に苦戦したので
今回はその時の知見を共有したいと思い記事化しました。

目次


前提


Unity2018.4.11f1で動作確認
UniRxだけど、分かる人はわかると思う。

使用結果


↓こんな感じで使いました。

f:id:OrotiYamatano:20191106003237g:plain

といっても、実装そのままだとコードが少し複雑なので皆様には、もう少し簡略化したものをお見せします。

f:id:OrotiYamatano:20191106235710g:plain

カーソルとかその他諸々を消しました。

Tileを消すプログラム全体


using Script.Util.input;
using UniRx;
using UniRx.Triggers;
using UnityEngine;
using UnityEngine.Tilemaps;
using Zenject;

namespace Script
{
    public class GetReyObject : MonoBehaviour
    {
        [Inject] 
        private InputService _inputService;

        private RaycastHit2D _hit;
        private Vector2 _hitPos;
        [SerializeField]
        private GameObject cursorObj;
        
        [SerializeField]
        Tilemap blockTilemap;

        private void Start()
        {
             //画面をクリックしたら呼ばれる
            _inputService.GetClickPos.Subscribe(val =>
            {
                //クリックするか、クリックを離すと反応
                if (val == Vector3.zero){    //クリック話したときはマウスの位置が0で来る
                    return;
                }

                var position = gameObject.transform.position;
                if (Camera.main == null) return;

                Vector3 diff =  (Camera.main.ScreenToWorldPoint(val) - position).normalized;
                _hitPos = diff;
                _hit = Physics2D.Raycast(position,diff/*方向*/, 1/*距離*/,LayerMask.GetMask("Block"));
            }).AddTo(gameObject);

             //毎フレーム呼ばれる
            this.UpdateAsObservable().Subscribe(_ =>
            {   
                Action();
            }).AddTo(gameObject);
        }
        
        private void Action(){
            if (_hit.collider == null) return;
            var tilePos = blockTilemap.WorldToCell(_hit.point+_hitPos);
            blockTilemap.SetTile(tilePos, null);    //消去
        }
    }
    
}

切り取って説明したいと思います。

Rayを飛ばす


            _inputService.GetClickPos.Subscribe(val =>
            {
                //クリックするか、クリックを離すと反応
                if (val == Vector3.zero){    //クリック話したときはマウスの位置が0で来る
                    return;
                }

                var position = gameObject.transform.position;
                if (Camera.main == null) return;

                Vector3 diff =  (Camera.main.ScreenToWorldPoint(val) - position).normalized;
                _hitPos = diff;
                _hit = Physics2D.Raycast(position,diff/*方向*/, 1/*距離*/,LayerMask.GetMask("Block"));
            }).AddTo(gameObject);

キャラクターの位置からクリックした方向までRayを飛ばします。 _hitPos という変数にどういう角度でRayを飛ばしたか格納しておきます。

Debug.DrawRay((Vector2)position,diff*10, Color.white,1);
をすると以下のようになります。

f:id:OrotiYamatano:20191107000438p:plain

消去処理


        private void Action(){
            if (_hit.collider == null) return;
            var tilePos = blockTilemap.WorldToCell(_hit.point+_hitPos);
            blockTilemap.SetTile(tilePos, null);    //消去
        }

今回Actionメソッドは毎フレーム呼ばれています。
Destroy(_hit.collider.gameObject); としたいところですが、それをするとTileマップ全体が消えてしまいます。
Tilemapのあたった箇所を Vecter3Int に変換し該当箇所のtileをnullに設定することでTileを消去できます。
_hitPos を足す理由としては_hit.pointだけだと、Tilemapの表面にあたってしまい、上手く変換できないためです。
_hitPos という変数を使わずにあたった箇所から一番近いTileを削除というロジックでも良いかも知れません。

以上です。

まとめ


とりあえず、まとめてみました。
一つのマップを拡縮させたり等は現状では厳しそうです。
今後もっと使い安くなっていってほしいです。

Unity1WeekJamに参加する前に自動ビルドを導入しよう

こんにちは、やまだたいし( やまだ たいし (@OrotiYamatano) / Twitter )です。

Unity1WeekJamに参加するにあたって自動ビルドを行いました。
理由は自動ビルドを今回行った理由は開発時間の短縮化のためです。
自動ビルドの設定をゲームジャム前に行っていればゲームジャム中楽が少しだけ出来ます。
今回はその時の知見を共有したいと思い記事化しました。
自分で全て構築したのは初めてです。
少し間違ってる点、他にもっといいやり方などがあるかも知れませんが、許してください。

目次


前提


Jenkinsを使用
構築はMacBook pro
OSはmacOS mojave
また今回はUnityをビルドするためにJenkinsのUnity3d pluginを使用しました。
Gitを使うのでそれぞれの端末にGitを入れておく
Githubを利用
Slackに通知もさせます

欠点・利点

ゲームジャムにおけるJenkinsのビルドを使う欠点


  • 設定が少し多く素早く用意できない

素早く用意したいならUnity公式のCloudBuildが良いかも?

  • 準備が必要

何はともあれビルドように準備が必要

  • 1台では意味がない

私はPCが2台あるのでもう1台の方でビルドという手段が取れますが、1台しかPCがない方は無理です。
Unityを立ち上げているとコマンドビルドが多重起動になってビルド失敗します。別手段を考えなければいけないため効率が良くないかも?
因みに私の会社ではMacProをビルドマシンにしてます。
スマホゲームのアプリのビルドはiPhome・AndroidどちらともビルドできるMacに構築するのが主流のため、UnityのJenkinsビルドの情報はMac向けが多いと思います。
とある会社さんではMacMiniをビルドマシンにしてるところもあるみたいですね。

developer.aiming-inc.com

ゲームジャムにおけるJenkinsのビルドによる利点


  • 無料

Unity公式のCloudBuildはProもしくは Unity Team Advanced に入ってないと使えないので無料で使えるのは嬉しいですね。

  • バグに早く気づける

UnityのWebGLは制限機能が多く実際にビルドしてみて初めて気づくエラーなども多いです。

  • ビルドの時間短縮

別PCでビルドすればメインPCを専有することなく開発時間が少し捻出出来ます。


Jenkinsセットアップ


MacBook proをビルド機として使うので
まずMacBook Proに私はインストールして行きます。

1.Jenkinsのダウンロード

Jenkins公式サイトのURLにアクセスして「Download」をクリックします。 jenkins.io

下の方にあるリンクのMac OSXを選択してpkgをダウンロード。
(私は安定版にした)

2.インストールしていく

インストーラーに従ってインストール

3.Administrator passwordの入力

Administrator passwordを求められるので入力を行う
Administrator passwordは指定されているファイルに値があるので、その値を入力
適当にsudo suとかでスーパーユーザーになってcatでファイルを見にいく。

4.Customize Jenkins選択

ちゃんとカスタマイズして入れていってもいいんですが、推奨プラグインのInstall suggested pluginsにしておきます。
何を入れれば良いか私は知らないので。
後で足りない分は追加します。

5.ユーザー作成

Jenkinsのadminユーザー作成を求められるので適当に作成

後はそのまま進めます

進めるととりあえずJenkinsのインストール完了

Credential Pluginの設定


GitHub等にログインできるようにCredential Pluginの設定の設定をします。
(Install suggested pluginsを選択していればあるはずですが、なければ追加してください)

Jenkins>認証情報>System>グローバルドメイン
認証情報を追加をクリック。

今回はグローバルで作成。
ユーザー名とパスワードGitHubのアカウントを設定。
それとGitのアカウントとして
SSHユーザー名と秘密鍵 でGitのSSHの鍵を設定
(私の設定が悪いのかもしれませんがhttp認証設定だと上手く認証が動かないっぽいです)
SSHの作り方は割愛します。
後でSlackのアカウントも設定しますが一旦ココはこれだけ設定。

Unity3dBuilder Pulginの設定


このままではUnityのビルドで使えないのでUnity3dBuilder Pluginを入れます。
バッチモードでUnityを起動してくれていい感じにやってくれるやつです。
Unity3dBuilder Pluginを使わずにCIビルドの設定をしても良いですが、今回はやりやすさ優先。

1. プラグインの検索

Jenkinsの管理>プラグインの管理>利用可能タブ でUnity3dとフィルター検索
Unity3Dが出てくる。

2. プラグインのインストール

Unity3Dを選択(チェックを入れる)、そしてインストール、再起動
Jenkinsが再起動かかったら次の作業へ。

3.プラグインの追加

Jenkinsの管理>Global Tool Configuration>Unity3d>Unity3d追加

名前:(適当に私は「Unity2018.4」にした)
インストールディレクトリ:/Applications/Unity/Hub/Editor/2018.4.xxf1/Unity.app(Unity.appを指定)

指定できたら「Applay」ボタンを押す

Slack通知設定


プラグインの追加

Unity3dBuilder Pulginの設定と同じ様にSlackのプラグインの追加を行います。
Jenkinsの管理>プラグインの管理>利用可能タブ でSlack Notificationとフィルター検索
インストール、再起動

Slackの設定

Slackのワークスペースにて
Jenkins CI というアプリを追加します。

設定でどのチャンネルに投稿するか等設定。
トークンはコピーしておく

Slackアカウント設定

先程開いた、Credential Pluginを開きます。
Secret textを選択
Secretに先ほどコピーしたトークンを貼り付ける。
IDはなしでOK

Slackの通知設定の追加

Jenkinsにて Jenkinsの管理>システムの設定 を選択
Slackの項目にてワークスペース名を設定

CrdentialにCredential Pluginの設定で追加したSlackアカウントを選択

設定が出来たら Test Connection ボタンをクリック
上手く設定できていればSlackに通知が飛びます。
↓こんな感じ

いったんコレでSlackの設定は完了。
ビルド通知との紐付けは後でやります。

BuildScriptを書く


今回はUnity1Week用なのでWebGLのビルドを出来るようにする。
Assets/Editor配下 に以下のようなScriptを追加。
コメントが少ないのは許して。

using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace Editor
{
    public static class BuildScript
    {
        private static void Build(bool isToolBer = false)
        {
            bool isSuccess;
            const string path = "../output";
            FolderCreate(path);

            PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.WebGL, "");
            // ビルド処理
            BuildPlayerOptions buildOption = new BuildPlayerOptions
            {
                options = BuildOptions.None,
                scenes = GetAllScenePaths(),
                target = BuildTarget.WebGL,
                locationPathName = path,
            };
            UnityEditor.Build.Reporting.BuildReport reports = BuildPipeline.BuildPlayer(buildOption);
            isSuccess = (reports.summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded);
            

            Debug.Log("isSuccess:"+ isSuccess);
            if(isToolBer){return;} //ツールバーからの実行だったら閉じたくないので終了
            EditorApplication.Exit(isSuccess ? 0 : 1); //上手く動かなかった時の検出に使う
            
        }

        /// <summary>
        /// 出力先フォルダ生成
        /// </summary>
        /// <param name="path"></param>
        private static void FolderCreate(string path)
        {
            
            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
        }

        //GetAllScenePath
        private static string[] GetAllScenePaths()
        {
            var levels = EditorBuildSettings.scenes
                .Where(scene => scene.enabled)
                .Select(scene => scene.path)
                .ToArray();

            return levels;
        }

        [MenuItem("Build/Build Develop App")]
        private static void BuildApp()
        {
            Build(true);
        }
    }
}

ちゃんと動くかメニューから Build/Build Develop App をクリックして確認してみてね。

ビルドの設定


いよいよビルドの設定
Jenkinsの左のメニューより 新規ジョブ を選択
名前を設定して
フリースタイル・プロジェクトのビルド を選択
OKを押す

Generalの設定

特に無し

ソースコード管理の設定

Git を選択

リポジトリURLを設定(git cloneコマンドと同じ記法)
私は以下のように設定しました。

git@github.com:TripleAt/XXXXX.git

認証情報は先程作ったGitのSSHキーのものを設定

ブランチを指定
私は以下のように設定しました。

*/master

追加処理の設定

  • Advaned checkout behaviours

pullに時間がかかったときにコケるので設定します。
チェックアウトのタイムアウト(分) 20

  • Advenced clone behaviours

フェッチのタイムアウト時間も一応 20分に設定

  • Git LFS pull after checkout

GitLFSをつかってる人は必ず入れましょう。
Pullに失敗します。

ビルド・トリガ

ポーリングをして定期的にコミットを確認しに言ってもらいます。
ビルド・トリガの項目で SCMをポーリング を選択
私は以下のように設定15分ごとにコミットされているか確認しに行ってくれる。

H/15 * * * *

もう少し高頻度でも良かったかも?

ビルド環境の設定

特に無し

ビルドの設定

Invoke Unity3d Editorを選択
Unity3d installation name
Unity3dBuilder Pulginの設定の3で設定したものを選ぶ

Editor command line argumentsに以下のコマンドを設定

-quit -batchmode -executeMethod BuildScript.Build

コマンドの意味
-quit 自動終了
-batchmode Unityをバッチモードで起動
-executeMethod 動かすクラスと関数を指定する

ビルド後の処理

Slack Notificationsを選択
選択はお好みで、私は全部チェック入れました。
これでSlackにビルド通知が飛ぶようになるはず。

他に気をつけること


これで基本的に構築完了です。
しかし、ゲームジャム中運用していて気をつけるべき点がいくつかありました。
書き残しておこうと思います。

  • Macの再起動

MacのOSの再起動をONのままにしており、Macが再起動されていました。
するとローカルホストに立てられているJenkinsは再起動後立ち上げれてないのでGitにPushしても反応しません……。
起動後にサービスを立ち上げるような設定が必要かもしれません。
Jenkinsが落ちても再起動できるようにJenkinsホームがどこになっているかだけは確認しておきましょう……。
そもそもOS更新が入らないようにしておくのが良いかもしれないですね。

  • Macがスリープ

スリープするとビルド自体は動きますが、凄く遅くなってしまうみたいです。
10分ほどで終わるビルドが 41分かかっていました。
またpullに時間がかかり過ぎてタイムアウトで落ちていました。
画面がスクリーンセーバーモードやスリープ状態にならないように設定しておいたほうが良さそうです。

gitをhttp認証にしていたらいつまで立ってもpullやcloneが出来ませんでした。なぜかは分からない。

  • RegisterApplication(), FAILED TO establish the default connection to the WindowServer, CGSDefaultConnection() is NULL. というビルドエラー

Jenkinsの実行権限がないときに起こるみたいです。
私の環境だけなのか、違うのかが分からなかったので上記インストール手順には書きませんでしたが、
起きた場合

sudo vim /Library/LaunchDaemons/org.jenkins-ci.plist

をして、
GroupNameをstaffに
UserNameを自分のユーザーにしてJenkinsを再起動すればいいと思います。

詳しいことは忘れたましたが、Jenkinsのホームを指定して以下コマンドを叩けばいいと思います。
(Jenkinsホームが設定されてないと設定とかの参照が別のところを参照し日本語表記ではなく英語のJenkinsが表示される)

java -jar /Applications/Jenkins/jenkins.war

  • git-lfs: command not found

GitLFSをつかっているのにGitLFSの設定を忘れてたときにコレで怒られます。
インストール手順には書いたので、この記事を読んでる人が引っかる事はないと思いますが念の為。

まとめ


以上がJenkinsの設定でした!
一度Jenkinsを設定したら次回以降設定が使い回せると思います。
思い切って設定をしてみてはいかがでしょうか?
もう一歩踏み込んだビルドだと、自動デプロイまでしてくれるところまで出来たりします。
ここは始まりです。カスタマイズして自分だけの環境を手に入れよう!
自動ビルドは良いぞ!

以上、やまだたいしでした!

【さがす】Unity1Week反省会

こんにちは、やまだたいし( やまだ たいし@ソシャゲプログラマ (@OrotiYamatano) | Twitter )です。
unityroomというゲーム投稿サイトにて第14回目Unity1Weekというゲームジャムがあり私も参加しました。
毎回300ほどの作品が投稿される大きなイベントです。
今回はその時の反省です。自戒を込めて書きます。

unityroom.com

目次


今回の成果

発掘せよ!ジェム!


ジェムこと宝石を探すゲームを今回は作りました。
14日から開発をはじめて27日に投稿。
音も無いし、1週間ゲームジャムのくせして1週間遅刻してるので、もはやUnity2WeekJam。
音も入れられなかったし、正直言って駄作です。
次回へ活かすには、どう駄目だったか、どうすれば良くなるか考えて書き出して行こうと思います。

unityroom.comf:id:OrotiYamatano:20191030021939p:plain

ゲームジャム中、どうやって過ごしたか

序盤


  • Jenkinsの構築

今回はあまり時間が取れないと分かっていたので自動ビルドを行うためにJenkinsの構築を進めていたのですが、予想以上に時間が取れず、環境構築作業がゲームジャム中にずれ込んでしまいました。

  • ゲームを考える

1日目でどういうゲームにするかは思いつきました。

  • オーディオ、キーインプット周りの準備

他のUnityプロジェクトで使っているものや使おうと思っていた機能を持ってきた。

  • Tilemapでゲーム画面を作る

Tilemap機能を使ってゲームを作っていました。

中盤


  • キャラクターの動きの制御

意外とUnityのRigidbody2Dが曲者で思ったように動かない

  • 残業

お仕事が忙しくて日に1、2時間ほど残業していました。

  • 爆睡

土曜とか18時間寝てました。

後半


  • 勉強会へ行く

期限が過ぎているにも関わらず、勉強会に行ってました。コレはコレで大事なので。

  • 読書

岩田さんを読んでました。コレはコレで大事なので。

  • asmdefについて調べる

気になったので……。

反省点

1.風邪をひいていた


風邪というか風邪を拗らせて気管支炎になっていました。
9末頃に前のプロジェクト退散して環境が変わり、どたばたしていたんですが、CEDEC行きました。 CEDECで疲れてたのに、(確か)土曜とかも休まず、ピクサー展行って、翌週TGSへ行きました。
軽く咳をしていましたが大丈夫だろと、高を括っていたら、風邪を拗らせて気管支炎になって咳が止まらなくなりました。
咳って意外と疲れるもので体力を持っていかれます。
そのせいでゲームジャム中にも関わらず休日に爆睡したり平日も早く寝てしまったのだと思います。
正直今回の一番の失態だと思います。

どうすればいいか

疲れたら休む。当たり前だけど、今回に限っては、それぐらいしか無いと思います。後はエアコンに気をつけるとか?(クーラーで喉を痛めて風邪引いたので)
「楽しいし、まぁ大丈夫だろう」じゃなくて、ちゃんと休む。
頑張って風邪ひくのとしっかり休んで作業するのとではコストパフォーマンスがかなり違います。しっかり休むことを優先したほうが結果的に成果が出る……かも知れないです。
「あの人が同じことをして大丈夫なんだから自分も大丈夫だろう」とかではなく、自分の体力に合わせてしっかり休むことを心がけたいです。
(明らかに疲れていることは分かってるのにピクサー展行った後、誘惑に負けて友達と遊んでしまったのは良くなかったかも知れない……)

2.残業していた


ぶっちゃけた話、作業が多く残業することになるのは分かっていました。しかし、それにしても、もう少し早く帰宅出来る日があったような気がします。
作業のきりが悪いから、と残っていた日もありました。きっぱり切り上げるようにしたいです。

どうすればいいか

前もってゲームジャムに参加する旨をプロジェクトメンバーに言っておく。
恥ずかしい思いをすることになるかも知れないですが勉強すること(ゲームジャムに参加すること)自体は悪いことじゃないです。前もって言って協力して貰ったほうが良かったかも知れないです。
前もってゲームジャムの準備をしておく。
今回も準備しようとしましたがJenkinsの構築やインプット周りの実装がゲームジャム中にずれ込んでしまいました。
アクションゲームを作るならUnityの2Dや3Dでキャラクターを動かすための基礎アルゴリズムは用意してゲームジャムに備えたら良い結果が残せたのではないかと思います。

3.Tilemapで詰まった


Tilemapを使ったことが無いのに今回初導入し、思った様に実装できず詰まった点があった。
やはり調べながらの実装だと時間がかかった。

どうすればいいか

触ったことのない機能は触れない。
短い期間で仕上げるためには触ったことのない機能を使って実装するのは避けたほうが素早く実装できます。
しかし、触ったことのない機能は触らないと言っても実際にゲームを作るまで、どんな機能を触るか分からないと思います。
ゲームジャムへ参加する前にリハビリがてら何か作ってみるのも、ありかも知れないです。 (ゲームジャムでは触ったことのない機能の検証に使う人もいるので使ったことのない機能を使うこと自体は否定しないです)

4.ゲームループが早めに完成しなかった


ゲームループを完成させる前にキャラクターのドットとかをやっていました。
悪いことではないが、後でも良かったかも知れないです。

どうすればいいか

早めにゲームループだけを作る。
早めにゲームループを作るだけでボリューム感をつかみやすいと思います。 どんなに杜撰(ずさん)でもゲームループを早めにつくった方が良かったかも?

5.他のことが気になっていた


1週間を過ぎたあたりで半分どうでも良くなって、他の気になっていたことを調べたりしていました。
コレばかりは「期限内に作業を終わらせろ」って話ですが、それでも集中できていたら日曜日とは言わず金曜日には仕上がっていたと思います。

どうすればいいか

一旦気になったことは書き留めておいて、作業に集中する……とか?
別のことに興味がわき、自己抑止力が働かないのは、すでにその時点で疲れていると思われるので早々に休む……とか?
気になってしまうのは仕方ないので時間を決めてやるとか?

良かった点

1.Jenkinsの構築


去年Unity1Weekに参加したときは最後の最後で上手くビルドが出来ず苦戦しました。
今回は動作確認とまでは行かないが、上手くビルドが通ってるだけで心理的に安心しました。
後、別PCでビルドすると凄い捗りました。
ゲームジャム中にメインマシンを触れる時間帯が増えるはありがたい。

2.Tilemapについて学べた


Timemapを知らなかったがゆえに時間がかかったところもありますが、機能として知ることが出来たのは良かった様に思えます。
Timemapに限らず実装することで「力がついた」「理解が深まった」部分があったので、その点に関しては、とても良かったと思います。

3.普段の足りない部分を理解できた


良かった点2にも関係しますが、普段の業務だと自分の担当箇所ばかり作業することになります。(例えば私だと実装済み箇所の修正や2DUIの実装や環境設定周り)
しかし、ゲームジャムだと全てを自分で担当することになります。
出来ると思っていても、実際に実装してみると思ったように出来ない箇所も多く、自分の出来ないところを把握することが出来ます。

最後に


今回Unity1Week中Twitterで「ちょっと初心者じゃ入り込めない雰囲気だ」と言っている人を見かけました。
因みにUnity1Weekはハッシュダグを付けてTwitterで作品作成過程を投稿したりします。
それを見てで作品レベルが高かったからでしょうか?実際の初心者が「敷居が高い」と感じているかは分からないですが、私は「敷居が高いと感じていても気にしなくても大丈夫だ」と声を大にして言いたいです。
(そうじゃないと本職ゲームプログラマなのに完成すら出来ていない私の立場がない……)
ぶっちゃけ途中経過なんて晒せる人はだいたいが上位陣なので気にせずにやりましょう。

ゲームジャムは普段のゲームづくりとは違った能力を求められますが、
普段のゲームづくりにおけるプロトタイプ作りの訓練や基礎力を上げるための良いトレーニングになると思います。
上に上げたような利点もあるので参加すること自体に意味があると思います。
挑戦できずに一喜一憂することすら出来ないのは、もったいないです。
この記事を見て、なんだ、1週間でゲーム作れないなんてゲーム開発本職のプログラマーってショボいんやなってどんどん殴り込みに来てほしいです。
きっとその方が楽しいと思います。

UnityのGradle対応方法(Unity2018.2系)

概要

こんにちは、やまだたいし( やまだ たいし@ソシャゲプログラマ (@OrotiYamatano) | Twitter )です。
当チームはAndroid64bit対応にあたり、Android64bit未対応のライブラリから対応バージョンへのネイティブライブラリの更新を行いました。
ネイティブライブラリをAndroid64bit対応のあるバージョンへの更新を行いましたが、そのライブラリがGradle利用を想定していたため、Gradleの対応を行いました。
今回はその時の知見を共有したいと思い記事化しました。



本文

Gradle Bulidとは


InternalビルドはUnity独自のビルドシステムでしたが、Gradleはオープンソースのビルドシステムです。
UnityがプロジェクトをGradleプロジェクトとして出力した後、Gradleビルドを行います。

Build SystemのExport Projectにチェックを入れた場合は、出力先設定した場所に、「Gradleに変換されたプロジェクト」が出力され、
チェックを付けていない場合でも一時的なプロジェクトとして、UnityプロジェクトのTempフォルダにGradleOutという名前でGradleプロジェクトが出力されます。
(GradleOutフォルダはあくまでも一時ファイルでビルドされる度に削除される)

f:id:OrotiYamatano:20190902155256p:plain

プロジェクトをエクスポートした場合は、外部のGradleビルドシステム(Android Studioなど)でビルドが可能です。
エクスポートをしない場合、Unity内部のGradle ビルドシステムが使用されます。

導入手順


UnityのbuildSettingsのAndroidのBuild SystemをGradleに変更

f:id:OrotiYamatano:20190902155521p:plain

PlayerSettings>Publissing Settings>Build>Build SystemをGradleに変更(赤い枠内)
また当チームはGradleの設定が必要だったため、水色の枠内も変更

  • Custom Gradle Template
    →GradleのBuild設定をデフォルトからカスタムに変更する(詳細については後述※1)
  • User Proguard File
    →コードの圧縮しないファイル、バイナリ化しないファイルの設定(詳細については後述※2)
  • Minify
    →コードの圧縮設定(今回は圧縮なしに理由については後述※3)

f:id:OrotiYamatano:20190902155911p:plain

基本的な設定は以上になります。

SDKなどの設定


Unityで動作保証されているAndroid SDKのバージョンを使用します。
Gradleの設定をする時には以下の設定に注意が必要

Unity PrefarenseのExternal Toolより設定

f:id:OrotiYamatano:20190903120351p:plain

JDK

preferencesの設定項目を確認
1.8.0系なっていることを確認、Unity2018系では1.8.0系じゃないと上手く動かないので注意が必要
当チームは1.8.0_181を使用
Macの場合はhomeフォルダを指定
Unityのほかバージョンで設定していると設定が引き継がれるので注意が必要

SDK

SDKだけでなく詳細な設定が必要です。
以下のバージョンを確認を行います。

コマンドでも確認できますがGUIでの確認方法を記述します。

AndroidStudio起動後、右下のConfigureのSDKManagerを選択
AndroidSDKの項目で以下を確認

Android SDK Platform-Tools
28.0.1を当プロジェクトでは使用。インストールされていることを確認

Android SDK Tools
当プロジェクトの場合Android最新一個前で動かしたいので28が選択されていることを確認(他のは選択されていなくてもされていても問題ない)

Android SDK Build-Tools
これはAndroidStudioから確認できないため/user/xxxx/Library/Android/sdk/build-toolsのフォルダ内を確認
当プロジェクトでは28.0.3。新しすぎないバージョンであることを確認(新しすぎるとUnityで動作しない)

・ NDK

Unityが指定するバージョンを落としてくること。ビルドが通っても、上手く動かないことがあります。

・その他バージョン

上記でバージョンを設定したとしてもGredleファイル(後述※1)にバージョンを指定してあると無視されるため注意が必要

AndroidPluginVersion/GradleVersion
基本的にはUnityのバージョンによって決められています。

Gradleファイルのcom.android.tools.build項目にAndroid plugin version指定箇所がありますが
Unityのバージョンの組み合わせによって上手く動かないことがあるため、
バージョンは容易に変えないことを推奨します。

GradleVersionはUnityでビルドした場合は

Unityのインストールフォルダ\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\gradle

に格納されているGradleが使われます。
(置き換えれば、ほかのバージョンでもビルドが可能)

エクスポートビルドしてAndroidStudioでビルドした場合、
特に設定しなければAndroidStudioインストール時に自動で出来上がるGradleが使われます。
UnityでインストールされたGradleVersionが使われるわけではないため注意が必要です。
エクスポート時はgradlepropertiesでバージョンの指定が可能です。

(UnityのバージョンごとにAndroid plugin versionとGradle versionは決まっている) https://forum.unity.com/threads/gradle-build-error-gradle-version-2-10-is-required-current-version-is-4-0-1.499520/#post-3500005

当プロジェクトのUnity version
2018.2 usesAndroid plugin version 3.0.1
Gradle version 4.2.1

2019.1 starting from 2019.1.7f1, 2019.2 and 2019.3 use
当プロジェクトが変更したAndroid plugin  versionとGradleVersion
Android plugin version 3.4
Gradle version 5.1.1


当プロジェクトではOut of memoryが発生し、上手くビルドが出来なかったため、

例外的に

  • Android plugin version 3.4
  • Gradle version 5.1.1

を使用しています。

Build設定(Gredleファイルの設定) ※1


Gradle buildに切り替えることによってAndroidManifestの定義を変更する必要があります。
AndroidManifestの設定は基本的に変更しなくても良いですが、Gradleで設定されている設定が優先されます。

デフォルトの設定の場合、以下のテンプレートの設定が採用されます。(Unityのバージョンに応じて中身が異なります)

Unityのインストールフォルダ\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\GradleTemplates\mainTemplate.gradle


UnityのGradleプロジェクト作成時に参照され、**APIVERSION**などテンプレート変数の箇所が置き換わります。

テンプレート変数についてはUnityの公式(https://docs.unity3d.com/ja/current/Manual/android-gradle-overview.html)に記載があるのでそちらを参照してください。

Gradle設定ファイルはPlayer Settingsにチェックをつけることにより設定が可能になります。
チェックを入れると設定ファイルが

プロジェクトフォルダのAsset\Plugins\Android\mainTemplate.gradle

に出力されます。

UnityのProjectSettingsなどから値を拾ってくるため、ライブラリを新規追加したり、多すぎる量のライブラリを読み込まない限り
そのままの設定で利用可能

当チームの設定は公開しません。
(単純に記事書くのが面倒なため。要望があれば別記事で書くかも)

User Proguard Fileの設定 ※2


圧縮・難読化 しないファイル を記述します。

Unityのインストールフォルダ\Editor\Data\PlaybackEngines\AndroidPlayer\Tools\UnityProGuardTemplate.txt

デフォルトでは、以下のテンプレートが採用されるようです。

-keep class bitter.jnibridge.* { *; }
-keep class com.unity3d.player.* { *; }
-keep class org.fmod.* { *; }
-ignorewarnings

Gradle設定ファイルはPlayer Settingsにチェックをつけることにより設定が可能になります。
チェックを入れると設定ファイルが

プロジェクトフォルダのAsset\Plugins\Android\proguard-user.txt

に出力されます。

圧縮・難読化対象になるとバイナリ化と圧縮化され外部からのライブラリの参照が難しくなるため、ビルドエラーになることがあります。
Unityのコード上から参照している場合は難読化(バイナリ化)対象から外してビルドを行ってください。
また、難読化されるライブラリのメソッド数が65,536を超えるとビルドエラーが発生するため、超えた場合は難読化対象からいくつか外してやればビルドが通ります。

難読化対象から外したくない場合、multidexの設定をする、Minifyを使用するなどが必要です。(Minifyについては後述※3)
multidexは難読化対象にするファイルを2つ以上にわける設定です。
Android5.0以下と以上の設定をする場合2つの設定が必要になります。
当プロジェクトでは一応対応しましたが、込み入った話になるため詳細は記述しません。

Minifyの設定 ※3


設定するとデータの圧縮を行います。
難読化対象のライブラリの圧縮を行います。

ライブラリのメソッド数が65,536を超える場合や難読化を更に複雑にしたい場合などに利用します。
ライブラリが正常にうごかなくなることがあるため当プロジェクトでは採用しませんでした。

参考サイト developer.android.com

エラーなどの注意点


・Could not find com.android.tools.build:aapt2

Gradleファイルを以下のように修正
Goooglのライブラリに依存があったので、allprojects のrepositories を下のように修正

allprojects {
    repositories {
        google()
        jcenter()
        flatDir {
            dirs 'libs'
        }
    }
}

・ビルド時に ClassNotFound もしくはNoSearchMethod もしくは Out of Memory

ビルド時に、Androidネイティブでエラーが発生した場合

難読化されるライブラリのメソッド数が65,536を超えたときのビルドエラーです。
難読化対象から外す、圧縮する、分割することで対処が可能

また、ヒープサイズが大きすぎる場合も出たりします。
ヒープサイズはGradleファイルで設定できないため、Gradleプロジェクトをエクスポートしてlocal.properties設定してください。
mainTemplate.gradle の一番上にlocal.propertiesを別途読み込む処理を追記することで、
ビルド時に値を設定するという方法もあると思いますが、試していません。

GradleVersionの互換性で上手くビルドが出来ないケースもあります。
当プロジェクトでは、上手くビルドが出来ないケースでした。

・OutOfMemory

Build SettingsのCompression MethodがLZ4HCになっていた場合、Androidの一部端末でout of memoryが発生し、クラッシュすることがあります。

Compression Method:
→ゲームに含めたシーンやResourcesから参照しているアセット群の圧縮設定です。

多分ですが上手く圧縮できずビルドが上手くできないのだと思われます。
当プロジェクトではdefaltに設定することで対応

以上、Gradle化対応でした。

まとめ


実は社内の他チーム向けに作った資料なのですが、せっかくなので外部に公開し役立ててもらえたら良いなと思い公開しました。
お役に立てば幸いです。