赤兎ラボ

コーディングからバージョン管理、業務効率化までをまとめます。

NatShareを使っていたらiOSビルドでエラーが起きた話

モバイルアプリ制作において画像やテキストの共有、SNSシェアを実装してくれる力強いアセットであるNatShare。お世話になっております。

 

こいつを使っているときにiOSビルドエラーが出たため共有しておくこととします。

実際に出たエラーはこちら

Undefined symbols for architecture armv7

今回はCloudBuildでエラー文を確認したためこのような形だが、UnityEditor上でビルドしてみてもarmv7の文言が入ったエラーが出ていました。

 

意味としてはアーキテクチャarmv7がありませんといったところです。

そもそも、armv7は32bitアプリケーション開発で使われていたアーキテクチャみたいで、Android側の設定ではARMv7にチェックが入っていてARM64にチェックが入っていない状態だとPlayストアにアップロードする際に弾かれる。

iOS側でも同じようにARM64だけで動作するように変更します。

 

解決策

PlayerSettings > iOSのタブ >OtherSettings内のArckitectureがデフォルトだとUniversalになっているため、ARM64に書き換える。

(画像下部)

f:id:RedRabbitNet:20210917173720p:plain

 

私はInspectorでパラメータを設定するのをやめるぞ!

コード

Reset()
{
GetComponent<Text>;
}

 

使い方

Start関数等と同じようにMonobehaviour継承クラスで関数を実装して使います。

GetComponentはStart内部で呼ぶには重い!とかSelializeFieldを設定したけどドラッグで設定しなければならない時、かなりの効率化が見込めます。便利ですね。

 

スクリプトリファレンスによると、インスペクターのコンテキストメニューのリセットボタンを押したとき、またはコンポーネントを初めて追加したときに呼び出されるようです。

 

参考

docs.unity3d.com

ちょっとエモいグラデーション画像を作る

本日の成果物

f:id:RedRabbitNet:20210915210708p:plain

ちょっと縁がふんわりしててエモい!

 

作り方

a,bの2つのレイヤーを作成します。

 

a-1. 2色の線形グラデーションを全体に塗る

a-2.

全体範囲選択(ctrl+a)した後、

選択範囲->選択範囲を変更->縮小(カンバスの境界に効果を適用)

今回は画像横幅1242pxに対して64pxの縮小をかけました。

a-3.

更に、選択範囲->選択範囲を変更->境界をぼかす

上記と同じく64pxのぼかしを入れました。

a-4. 選択範囲を削除(deleteキー)

ここまででaのレイヤーは完成です。

f:id:RedRabbitNet:20210915211528p:plain

 

b-1. 2色の線形グラデーションをaと逆さに塗る

以上!bのレイヤーも完成です。

f:id:RedRabbitNet:20210915211658p:plain

 

あとはbの上にaのレイヤーが重なるようにレイヤーを整頓してあげれば始めに示した成果物の出来上がりです。

境界ぼかしはよく使うのですが、偶然エモくなったので記事として残してみました。

Enumを文字列の配列として使おう

Enumを文字列の配列として使う

Enum.GetNames(typeof(MyEnumType)).ToList()

 

よく使うのでメモっておこうシリーズ。

リソースファイルの名称等をenumにまとめた上でアクセスしたりしやすい。

Unity x PlayFab 導入しやすい! ただし注意点も

最近流行りのPlayFabについて知見が溜まってきたので共有したいと思います。

本記事はPlayFabを導入しようか迷っている方に向けて、導入のメリットと注意点について紹介できればと思っています。

また、既に利用している人は、注意点の項目を読むことで、意外な知見が得られるかもしれません。

 

 

PlayFabとは

PlayFabはライブ ゲームを構築して運用するための完全な LiveOps バックエンド プラットフォーム」です。と公式サイトにはあります。
つまりは、ネットワークデータベースとそのAPIをまとめたもの、というように理解しています。

導入のメリット

導入が簡単です。 クライアントエンジニアでも扱うことが容易である。

自前でデータベース管理用のAPIを用意しなくて良いです。
当方はクライアントエンジニアなので細かくは知りませんが、
通常、自前でデータベースを用意する際、そのデータを何処において、ロードしてきて、エラー判別して、
と様々なフローを定義する必要があるかもしれません。
その他、セキュリティへの配慮やデータが飛ぶことがあるかもしれません。
そのあたりをやってくれるのはとても助かります。

導入方法

正直、PlayFab公式さんが丁寧なリファレンスを用意してくれているので、手順通りに進めれば何も困ることはないと思います。
ざっくり書くと、SDKをunitypackageとしてインポートして、PlayFabで作ったidを入力すれば準備完了です。

注意点

アイテムカタログのアイテムとバンドルについて


同じ一意のitemIdによって識別されますが、内部の挙動が若干異なります。
アイテムはそのまま内容が見れるのに対してバンドルはアイテムをまとめたものなので当然付加情報があります。
具体的な中身はバンドルの中身を見ればわかりますが、アイテムの配列は一階層潜ったところにありますね。

また、バンドルにはドロップテーブルを指定することも出来ます。
これを利用して、バンドルを購入することで自動的にドロップテーブルから抽選が行われます。
この挙動はリファレンスに明確な記述はありません。ただ、オススメするとか書いてあるので、察してください。
仮想通貨をユーザに付与する場合も、1セットにまとめたい場合はバンドルが扱えます。

ストアの挙動について


ストア内にあるアイテム一覧は料金とitemIdを羅列しただけの簡素なものとなっています。

PlayFabにはセグメントという概念があり、これはAndroidユーザとiOSユーザというように区切りを付けることが出来ます。
ただ、このセグメントに関しては、PlayFab側で、区切りに使用するパラメータがある程度決められており、開発側で決められないので柔軟性に欠けるというのが現状の認識です。
例えば、PlayFab上のデータである課金金額による区切りは可能ですが、
このユーザはこのアイテムをいくつ持っているかという区切りは不可能です。
行いたい場合、自前で工夫をする必要があるでしょう。

Unity Addressables

前提

以下の点を理解していない場合は、Addressableを導入するには早いかもしれません。
> Resources.Loadを使ったことがあること
> Coroutine等、非同期処理について理解していること

また、導入のための手順が比較的多いので、解説用の画像は以後追加できればしたいと考えています。
文字だけで読める勇者さん向けの記事になります。

Version
> Unity 2019.2.14f
> Addressable 1.7.5

Unity Addressablesとは

ResourcesやAssetBundleとして実装されていたバラバラのリソース管理システムが統合されたようなアセット管理システム。
非同期ロードをベースに考えられている。
ローカル環境でのリソースロードからリモート環境でのロードまで柔軟に変化させることができる。
リモートでのダウンロードは、一度ロードされたアセットは端末上に保管され、次回実行時はダウンロードせずに済む。
prefab等の他アセットへの参照を認識して保存してくれるため、AssetBundleのように参照切れが起こりにくい。

導入方法

PackageManagerからAddressableをインポートします。

既存リソースの整理

既存リソースを選択すると、インスペクタにAddressableのチェックが名前の下辺りに出ていると思います。
これにチェックを入れることでAddressable対応します。
チェックを入れると、チェックボックスの隣にパスが表示されると思います。これをAddressableNameと言います。
AddressableNameはAddressableで取得するために使う文字列です。
AddressableNameは編集が出来ます。これによって元のリソースの名前を変えることなく、リソースをロードすることができます。
デザイナーさんに命名規則を強制しなくて済みますね。

Addressableに登録されているリソースは
Window > AssetManagement > Addressables > Groups から確認ができます。
ここで各アセットにLabelを設定することができます。
Labelを設定しておくことで、一括でアセットをダウンロードしたりすることができます。

Window > AssetManagement > Addressables > Groups のdefaultGroup等の各グループを右クリックすると
GroupSettingsを開くことができます。

f:id:RedRabbitNet:20200420162455p:plain

Content Packing & Loading > Advanced Options > BundleMode を PackTogetherByLabelにしておきます。
ここを変更すると、AddressablesをBuildした際に生成される.bundleファイルが分割されます。
これを行うことで、Label単位でGetDownLoadSizeAsyncを呼び出した時にちゃんとダウンロードサイズが表示されます。
ここが設定されていないとダウンロードサイズが正確に表示されません。
エラーも表示されず、容量が0と出るだけなので既にロードが終わっているのか区別がつきません。
この仕様はいつか改善されるはずだと信じています。

Addressable Build

Window > AssetManagement > Addressables > Groups からBuildができます。

f:id:RedRabbitNet:20200420161506p:plain
Addressableにリソースを追加したあとはこれを行うことで、リソースとして認識されるようになります。
また、このビルドによって生成されたファイルをネットワークサーバ上にアップロードすることで
実行ファイルからリソースをサーバに移すことができます。
詳しくはリモートの設定について調べましょう。

f:id:RedRabbitNet:20200420162039p:plain
PlayModeScript等を設定する必要があります。

リソースの保存場所の指定は Window > AssetManagement > Addressables > Profileから設定することができます。
パスにはAsset以下の相対アドレスの他、httpRqeuestの形式で指定できます。

Window > AssetManagement > Addressables > Settings でProfileやリモートの指定ができます。
Catalog > BuildPath, LoadPath が想定通り表示されているか確認しておきましょう。
また、Catalog > Player Version OverrideでAddressableのビルドバージョンが指定できます。
この値は設定しておかないと、ビルドごとに書き換わってしまうため注意が必要です。

プログラム側

書き方がいくつかありますが、今回はAssetReferenceによるロード方法は省きます。
また、ロードと同時にInstantiateする関数もありますが、ほぼ同様なので省きます。

1. Coroutine内で同期待ちをする方法
yield return によって待っているので、コルーチン内に書く必要があります。
また、同様の記述をasync/waitでも実装できます。
var loadAddressable = Addressables.LoadAssesAsync("AddressableName");
yield return loadAddressable;
var gameObject = Instantiate(loadAddressable.Result);

2. 同期処理内でコールバックを設定する方法
あくまでコールバックを設定しているだけなので、この時点でロードが完了してないことには注意。
Addressables.LoadAssesAsync("AddressableName").Completed += op => Debug.Log(op.Result);


Unity MonoBehaviourを継承する場合としない場合の使い分けについて

MonoBehaviourとは

MonoBehaviourはUnity上でクラスを生成すると自動的に継承されるクラスである。
これによってStart()やUpdate()等の関数が使える。 逆にコンストラクタが使えなくなるため、Awake()等で代用する必要がある。

どんな時にMonoBehaviourを継承しないで使うのか

これに対する私の答えは「データを扱うクラスの時は継承しない」です。
Start()やUpdate()を使う必要がない時というのは、つまりはイベント関数、UI等から直接呼び出しを行う可能性が少ないということで、自然とそうなっているケースも多いです。

論拠1

Unityを使ってデータをセーブするためにJsonUtilityをよく活用します。
これを使ってクラスごとセーブを行う際に、MonoBehaviourを継承していると固有の番号を書き出してしまいます。これはUnity起動ごとに変わる可能性のある値であり、全くセーブする必要のないものです
代わりに継承せずに作ったクラスの場合、そのまま書き出すことが出来ます。
この時点で自然とデータを扱う場合は継承しないほうが良いのだなと考えます。

論拠2

MonoBehaviourはStart()やUpdate()を実装してしまいます。
何も処理を書かなければ良いと思うかもしれませんが、実際にはMonoBehaviourを通して様々な処理が走っています。
インスペクタ上でもスクリプトが紐づいている欄だけが表示されるため煩わしいところがあります。

データの確保方法における使い分け

データの確保方法は大きく分けて2つあります。
アプリ開始時にデータを確保する、またはビルド時にプログラムに含んでしまうような静的確保という方法が1つ。
アプリ実行中にメモリに確保できないほどの大量のデータを扱う際に確保と開放を繰り返す動的確保という方法が2つ目。
これに対するMonoBehaviourの使い分けは
静的確保の場合、MonoBehaviourを使った方が適している。
動的確保の場合、MonoBehaviourを継承しないほうが適している。
と考えています。

静的確保の場合、MonoBehaviourとSelializeFieldを使ってインスペクタからコンポーネント間の関係が指定できます。
最も一般的なUnityエディタとしての使い方です。標準のButtonクラス等もインスペクタから指定することが出来ますね。

動的確保の場合、MonoBehabiourが邪魔になることが多々あります。
これが別の開発環境からUnityに移行した時の課題だと考えています。
コンストラクタが使えないため、別環境と同じようなクラス管理が出来なかったり、
Destroy()でオブジェクトを破棄したはずなのにUnityによってメモリが解放されていなかったりします。

開発速度の差について

MonoBehaviourを使った方が格段に早いです。
そのため、個人開発ではMonoBehaviourを多用し、
業務開発ではMonoBehaviourを使わずに動的確保を行うことで大量のリソースに対応しやすい記述を行う、
というのが僕のオススメです。