FC2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »Unityトラブルシューティング
このページの記事一覧

【Unity】【C#】Addressable Assets でキー(アドレス)の存在(登録)を調べる  


 新しいリソースの管理のシステムである Addressable Assets をちょっといじってみた。しかしなぜか、素材のアドレス(キー)が存在しないときに出る InvalidKeyException が try~catch で捕捉できないので、登録の有無の検出ができなかった…(掲載時点:Addressables System 0.5.3-preview)。


InvalidKeyException encounterd in operation UnityEngine.ResourceManagement.CompletedOperation`1[UnityEngine.Texture], result='', status='None', valid=True, location=..
UnityEngine.AsyncOperation:InvokeCompletionEvent()

InvalidKeyException: Exception of type 'UnityEngine.AddressableAssets.InvalidKeyException' was thrown., Key=hogehoge
UnityEngine.AsyncOperation:InvokeCompletionEvent()

 まだ preview 版なので、単なるバグなのかも知れないが、少し不便と感じたのでググってみたら、フォーラムにも同じ内容があった。

Can I ask Addressables if a specified key (addressable name) is valid?

 まぁそのうち、ちゃんとエラー捕捉できるようになったり、「Addressables.HasKey()」みたいなのができそうな気がするが、今使うには簡単なものを用意しておくのも良いだろう。



(※) Unity 2018.3.2f1 / Addressables System 0.5.3-preview / Windows10(x64) で確認



■Addressable Assets にアドレス(キー)が存在するか否か?を返すメソッドを定義

 フォーラムにある「AddressableResourceExists」でも判別可能ではあったが、そのすぐ下に Unity の中の人からのアドバイスが書かれていたので、試しにやってみた。

What you have above probably could work. But the thing I would actually recommend is to just do Addressables.LoadAsset<IResourceLocation>("key");

This will not load your asset, but will load the location that points to your asset. If your key is valid, then you'll get a valid location back. Otherwise you will not. You can keep and use that location (doing LoadAsset<GameObject>(myNewLocation)) or you can just discard it and continue to load with key once needed.

 Google翻訳すれば『これはアセットをロードするのではなく、アセットを指す場所をロードします。キーが有効であれば、有効な場所に戻ります』となるが、要するに「存在位置が示されればアセットは存在する」ということだろう。

●Addressable Assets にアドレス(キー)が存在するか否か?
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;

public static class AddressablesUtil { //※クラス名は任意

// (参考) https://forum.unity.com/threads/can-i-ask-addressables-if-a-specified-key-addressable-name-is-valid.574033/
// http://fantom1x.blog130.fc2.com/blog-entry-319.html
/// <summary>
/// Addressable Assets にアドレス(キー)が存在するか否か?
/// </summary>
/// <param name="key">アドレス(キー)</param>
/// <returns>true = 存在する / false = 存在しない</returns>
public static bool Exists(string key)
{
return Addressables.LoadAsset<IResourceLocation>(key).Status == AsyncOperationStatus.Succeeded;
}
}

 やってみたら、どうやら存在しないキー(アドレス)を指定したときには「AsyncOperationStatus.Failed」になるみたいなので(まだ何もしてないときは None)、これだけで存在有無は確認できそうだ。Addressables.LoadAsset() の戻値:IAsyncOperation<IResourceLocation> は null は出ないみたいなので、チェックは省略した。

 使用例を簡単に書くと以下のようになる。

●Exists() の使用例(Addressable Assets からテクスチャを読み込んで RawImage に入れるサンプル)
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;

public class AddressablesTest : MonoBehaviour { //※クラス名は任意

public RawImage image;

void Start () {
string key = "hogehoge"; //アセットのアドレス(キー) ※任意

if (AddressablesUtil.Exists(key))
{
Addressables.LoadAsset<Texture>(key).Completed += op => {
image.texture = op.Result;
};
}
else
{
Debug.LogWarning("Invalid key = " + key);
}
}
}




■Task と連携して非同期で読み込むメソッドを定義

 ついでに前述した「Exists」と以下の拡張メソッドを組み合わせて、動作を Task 化し、アドレスの存在検出して、有れば素材を、無ければ default(この場合は基本的に null)が返ってくる関数を定義してみよう。これを使うとかなり楽に非同期ロードができるようになる。Task 化メソッドは以下の記事(IAsyncOperationExtensions.GetAwaiter<T>)をまるっとコピーして欲しい。
 
【Unity】Addressable Asset Systemのリソース読み込みをasync/await対応する

●アドレス(キー)が存在するならロードし、無ければ default (= null) を返す
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;
using System.Threading.Tasks; //※Task ならこっち
//using UniRx.Async; //※UniTask ならこっち

public static class AddressablesUtil { //※クラス名は任意

// (参考) https://qiita.com/toRisouP/items/e03b53e8eb6af06fbcbf (※IAsyncOperationExtensions.GetAwaiter<T> を利用)
// http://fantom1x.blog130.fc2.com/blog-entry-319.html
/// <summary>
/// アドレス(キー)が存在するならロードし、無ければ default (= null) を返す
/// </summary>
/// <typeparam name="T">素材の型</typeparam>
/// <param name="key">アドレス(キー)</param>
/// <returns>取得した素材</returns>
public static async Task<T> LoadOrDefault<T>(string key) where T : class
{
if (Exists(key)) //※前述のメソッド
return await Addressables.LoadAsset<T>(key); //※IAsyncOperationExtensions.GetAwaiter<T> が必要
return default;
}
}

 もちろん、Task を UniTask(UniRx が必要)に置き換えることも可能だ。

 簡単な使い方としては以下のようにしても良いだろう(※かなり適当なので、好きに書き換えて(笑))。

●LoadOrDefault()の使用例(Addressable Assets からテクスチャを読み込んで RawImage に入れるサンプル)
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement;
using System.Threading.Tasks; //※Task ならこっち
//using UniRx.Async; //※UniTask ならこっち

public class AddressablesTest : MonoBehaviour {

public RawImage image;

void Start () {
string key = "hogehoge"; //アセットのアドレス(キー) ※任意
LoadImage(key); //※Task なら警告が出る
//LoadImage(key).Forget(); //※UniTask なら警告を消せる
}

async Task LoadImage(string key)
{
var tex = await AddressablesUtil.LoadOrDefault<Texture>(key);
if (tex != null)
{
image.texture = tex;
}
else
{
Debug.LogWarning("Invalid key = " + key);
}
}

}

 もちろんこれも UniTask(UniRx が必要)に置き換えても良い。

 待機したいなら、async/await を付ければ良い(※この例ではあまり意味がないが(笑))。
async void Start () {
string key = "hogehoge"; //アセットのアドレス(キー) ※任意
await LoadImage(key);
}



 まだ、Addressable Assets はプレビュー版だからか、使い勝手が微妙な所もあるが、いずれは Resources の代わりに使われるようになるだろう。Addressable Assets ははじめから非同期ロードだったり、プリロード機能もあったりして便利なので、今から慣れておくのも良いかも知れない。





(関連記事)
【Android】【Java】パーミッションの付与(許可)のチェックと要求をする
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
【Unity】AssetStore版 FantomPlugin のセットアップ
【Unity】Unity2018 でビルドエラー「CommandInvokationFailure: Gradle build failed.」が出る
【Unity】【C#】モバイルビルド中の警告:Game scripts or other custom code contains OnMouse_ event handlers.~ を消す


スポンサーサイト

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityトラブルシューティング  C# 
tb: 0   cm: --

【Unity】Unity2018.3.2 にアップグレードすると見た目がおかしくなることがある  


 原因は不明なのだが、Unity2018.3.1 以前のプロジェクトを Unity2018.3.2 にアップグレードしたら、見た目がガタガタになった…。えっ?何これ…?


●髪など揺れものがガタガタになってる…

(※) Unity 2018.3.2f1 / Windows10(x64) で確認

 一応 Git で管理してたので、以前のバージョンに戻って調べてみたら、どうやら Quarity Settings(Edit>Project Settings...>Quarity)のデフォルトが(緑色のチェックマーク)、なぜか全て「Very Low」になっていた…。


(左) Unity2018.3.1 のデフォルト / (右) Unity2018.3.2 へのアップグレード変換失敗?



 とりあえず、デフォルトを以前の状態に戻して(手動でやるなら、下の逆三角アイコンを押して、各プラットフォームの Quarity を選択する)、ビルドしてみたら、元に戻った。


●髪がサラサラになった


 アップグレード変換失敗を失敗したのか、何らかでデータが飛んでしまったのかわからないが、設定を戻せば直るようだ。

 ちなみに、新規プロジェクトでは、以前と同じデフォルト設定だった。他のプロジェクトでアップグレードしてみたけど、同じように「Very Low」になってしまうものがあった。PC は起動時にクオリティ選べるが(ダイアログのプルダウンもデフォで「Very Low」になる)、スマホではスペックにより自動となるので、自分で選べないので困る。う~ん、これは Unity2018.3.2 特有のバグっぽいな…。





(関連記事)
【Android】【Java】パーミッションの付与(許可)のチェックと要求をする
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
【Unity】AssetStore版 FantomPlugin のセットアップ
【Unity】Unity2018 でビルドエラー「CommandInvokationFailure: Gradle build failed.」が出る
【Unity】【C#】モバイルビルド中の警告:Game scripts or other custom code contains OnMouse_ event handlers.~ を消す


category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityトラブルシューティング  VRM  VRoid 
tb: 0   cm: --

【Unity】Android アプリでパーミッション(権限)要求をする  


 もしかしたら Unity2018.3.x のバグかも知れないが、Android ビルドした際に、パーミッション(権限)要求が自動で出なくなったので、「一部機能が使えない」等のトラブルが結構出てるのではないかと、改めて記事を書いてみた。

●Unity 上で権限要求ダイアログを出す

 公式のデベロッパーサイトにも掲載されているが、Android 8.0 ではパーミッション付与の仕様(どちらかというとガイドライン)も変更されたようで、今まではアプリ起動時に権限要求が自動で全て表示されてたけど、Android 8.0 以降では、その機能を利用するときに権限を要求しましょうということになっている(不要な権限やセキュリティに関わる権限をなるべく減らし、ユーザーにとって許可する内容をわかりやすくするため)。

Android 8.0 での動作変更点>パーミッション
実行時のパーミッション リクエスト

 冒頭に書いた「バグかも知れない」というのは、Unity でアプリビルドした際には自動で起動時に権限要求が表示されていたからだ。Android 開発では Android 6.0 以降、その機能は実装されているが、Unity のみ開発している人にとっては、割と敷居の高い設定項目となる(公式にも「上級レベルの Android 開発者にのみ推奨」とある)。そのうち、Android ビルドで権限要求の選択ができるようになるかも知れないが(例えば PlayerSettings>Other Settings>Configuration>Write Permission を「External (SD Card)」にすると、書き込み権限が自動的に要求される)、とりあえず現在の状態ではそういう機能はないので、プラグインを使って権限要求する方法を書いておこう。

 なお、今回の記事はプラグインのデモも兼ねている。サンプルシーンを使えば1から構築する必要はないので、すぐに試してみたい人はプラグインをダウンロードして欲しい。AssetStore版[無料]GoogleDrive版の2つがあるが、基本的にはどちらも同じものだ。好きな方で構わない。

>>GoogleDrive版 プラグイン&サンプルをダウンロード
(Google Drive を利用。画面右上にあるダウンロードアイコン:を押す)

>>AssetStore版をダウンロード


※とりあえず試してみたい方は、最新版をビルドした apk デモをダウンロードできます。動作確認にもどうぞ。

プラグインデモをダウンロード
(Google Drive を利用)


Android 4.2以上
※「提供元不明アプリのインストール」許可が必要です。


 プラグイン自体のセットアップは以前の記事を参照して欲しい(>>GoogleDrive版 | >>AssetStore版)。デモが入っているパスは GoogleDrive 版では「Assets/_Test/」に、AssetStore版は「Assets/FantomPlugin/Demo/」となっているので適宜置き換えて欲しい。ファイル名は基本的に同じだ。


(※) Unity 2018.3.1f1 / Windows10(x64) で確認



■PermissionCheckController を配置と使い方

 実際、以前の記事にも書いたのだが、パーミッション要求というのは通常ネイティブで書くしかないので、Unity で利用するには非常に困難である。なので、誰でも手軽に使えるようにプラグインとして導入しておいた(プラグインの中身も以前の記事とほぼ同じ)。その使い方を簡単に説明しておこう。

 「PermissionCheckController」はプレファブとスクリプトで提供している(FantomLib/Prefabs/System/ 以下 ※検索で探すと楽)。これをシーンにドラッグ&ドロップで配置しよう。配置したら、以下の項目を設定すれば完了だ。




※ここではデモシーン「ExternalStorageTest」の「AndroidFunctions」に入っているプレファブを使っているが、
基本的に同じものである(説明ダイアログ付きのデモとなっている)。

Permission要求する権限の文字列定数。この文字列定数は公式のデベロッパーサイトに掲載されている「Constant Value」の値を指定する。例えばカメラの権限なら「android.permission.CAMERA」を入れる。基本的に "android.permission.~" で始まる文字列となる。
Check On StartUnity のライフサイクル Start() で自動的にパーミッションのチェックが実行される。シーンごとに配置している場合は、プレファブがアクティブなら、シーン開始時にチェックされるようになる。
Request When Not Grantedパーミッションをチェックした際、許可されてないときのみ、要求ダイアログを出す(ユーザー設定により、出ないこともある)。オフのときは、要求ダイアログは出さず、結果のみコールバックへ返す。
Title, Message,
Style, Localize
権限要求の説明ダイアログのタイトル, メッセージ, スタイル, ローカライズの設定(多言語対応)。
Localize>Localize Resource が設定されてないときは、Title, Message で設定されている文字列のみが使われる(単一言語)。
On Resultパーミッションチェックの結果を Permission の文字列と真偽値(true = 許可 / false = 拒否)でコールバックする。複数同時に要求しているとき判別するのに使う。
On Grantedパーミッションチェックの結果が「許可(Granted)」のときのみコールバックする
On Deniedパーミッションチェックの結果が「拒否(Denied)」のときのみコールバックする
On Allowedパーミッションチェックの結果が「許可(Granted)」に変更されたときのみコールバックする(元から許可されてる、または拒否のときは何もしない)。

Manifest.permission(パーミッションの文字列定数)
テーマ(スタイル)
【Android】【Java】パーミッションの付与(許可)のチェックと要求をする



■AndroidManifest.xml を設定する

 意外と重要なのは、このマニフェストファイルの設定である。少なくとも以前はこの辺りを Unity が自動でやっていてくれたのだが、Unity2017 での Gradle ビルド導入以降、ある程度は自分で書いた方が良いこともある。例えばビルドエラー(or コンフリクト)が出たときなども、手動で直せることもある。

 最終的にマニフェストファイルは「Assets/Plugins/Android/AndroidManifest.xml」を中心に統合されたファイルとなる。そして、その設定に従ってアプリが起動する(なのでアプリが起動できないときは、このファイルを疑うのも良い)。

 ちなみにデフォルトのマニフェストテンプレートは Unity をインストールしたフォルダ以下の「Editor/Data/PlaybackEngines/AndroidPlayer/Apk/AndroidManifest.xml」にあり、
現在の出力されているマニフェストを見たいなら、ビルドした直後に、プロジェクト内の
Temp/StagingArea/AndroidManifest.xml」を開けば見ることができる。

Android マニフェスト
アプリ マニフェスト
UnityPlayerActivity Java コードの拡張

 ただ、資料を見ると結構難しく感じるので、ここではプラグインに付属している「AndroidManifest_test.xml」(AssetStore版は「_demo.xml」)を複製して「AndroidManifest.xml」にリネームし、これに少し手を加える形で使ってみよう。内容がわかるようになったら、自由に設定すれば良いのである。以前の記事にも書いたが、要点だけを抜き出すと「<manifest>~</manifest>」タグの間に「<uses-permission ~」で要求したい権限を書いておくことが必要となる。


 例えば、カメラマイクの権限を要求したいなら、以下のように書いておく(マニフェストに書いてない権限は要求できない)。

<manifest>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
・・・(略)・・・
</manifest>

パーミッションの設定
Manifest.permission(パーミッションの文字列定数)

 また、手動で要求する場合、「<application>~</application>」または「<activity>~</activity>」タグの間に、以下を入れて「自動で要求するのをスキップさせる」と良いとも公式に書いてある

<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />

Android マニフェスト

 まぁ、この辺りは定形処理なので、そのうちまた自動化されそうだが(もしかしたら、この自動化あたりがバグっている?[Unity2018.3.1f1 時点])、最近は色々なプラグインを導入する機会も増えてきたので、覚えておくとイザというとき役に立つだろう。





(関連記事)
【Android】【Java】パーミッションの付与(許可)のチェックと要求をする
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
【Unity】AssetStore版 FantomPlugin のセットアップ
【Unity】Unity2018 でビルドエラー「CommandInvokationFailure: Gradle build failed.」が出る
【Unity】【C#】モバイルビルド中の警告:Game scripts or other custom code contains OnMouse_ event handlers.~ を消す


category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityトラブルシューティング 
tb: 0   cm: --

【Unity】IncrementalCompiler でのエラー:Unloading broken assembly Packages/com.unity.incrementalcompiler/Editor/Plugins/Unity.PureCSharpTests.dll, this assembly can cause crashes in the runtime  


 Unity2018.3.0f2 にアップグレードしたら、いきなり出た。

Unloading broken assembly Packages/com.unity.incrementalcompiler/Editor/Plugins/Unity.PureCSharpTests.dll, this assembly can cause crashes in the runtime

(※) Unity 2018.3.0f2 / Windows10(x64) で確認

 まぁ、こういうのはいつものことだ。慌てない慌てない。とりあえず、Google先生に聞いてみよう。

 ググったら、公式のフォーラムに引っかかった。しかも回答者は UnityTechnologies の人だ。これは信頼性が高い。

This is caused by a breaking change in one of Unity's internal API.
I've released version `0.0.42-preview.30` which works with 2018.3.b11++, but breaks compatibility with previous 2018.3 betas.
For support for 2018.3.b10 and lower, please use 0.0.42-preview.29.

 どうやら、今使っている IncrementalComplier が原因のようだ。私は IncrementalCompiler Version 0.0.42.preview21 を使っていたので、試しに IncrementalCompiler Version 0.0.42.preview30 にアップデートしてみた。そしたら、めでたくエラーが消えた。

 次に Standalone にプラットフォームを切り替えたら、以下のエラーが出た。

(0,0): Unity.Compiler.Client.InvokeCompiler Exception:System.AggregateException: One or more errors occurred. ---> System.Exception: System.Reflection.TargetParameterCountException: パラメーター カウントが一致しません。
場所 System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
場所 System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
場所 UnityEditor.ServiceBroker.ZeroMQBackend.Invoke(RPC rpc)
at UnityEditor.ServiceBroker.NetworkObject.Replicate[T] (System.Reflection.MethodBase method, System.Object[] args) [0x000a0] in <3f1d7481444e4e89892aa60066a31da9>:0
at UnityEditor.Compilation.IncrementalCompiler.LocalIncrementalCompilerService.InvokeIncrementalCompiler (System.Int32 callerPid, System.String pid, System.String commandLine) [0x0000e] in :0
at UnityEditor.Compilation.IncrementalCompiler.LocalIncrementalCompilerService+d__1.MoveNext () [0x0001a] in :0
--- End of inner exception stack trace ---
・・・(以下25行ほど)・・・

 ググったけど、よくわからん…。よし!こういうときは再起動だ!

 Unity を再起動したら、エラーは消えていた。これもよくあること。特にパッケージマネージャーでアップデートしてエラーが出た場合、再起動すると直ることがある

 同じようなエラーで悩む人たちのためにもメモとして残しておこう。困ったときの Google 頼みである。だが、新しい情報ほど日本語は少ない。誰かの役に立てば幸いである。
 
 ふっ、今回もつまらぬものを斬ってしまった…(笑)。
 





(関連記事)
【Unity】Unity2018 でビルドエラー「CommandInvokationFailure: Gradle build failed.」が出る
【Unity】【C#】モバイルビルド中の警告:Game scripts or other custom code contains OnMouse_ event handlers.~ を消す
【Unity】アイコン画像のフォーマット警告:Compressed texture XXX is used as icon. This might compromise visual quality of~ を消す
【Unity】5.6 の Canvas の警告:Shader channels Normal and Tangent are most often used with lighting~ を消す
【Unity】InitializeUnityExtensions: Must have a valid path for the plugin [XX] (XX:番号) というエラーの修正方法


category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityトラブルシューティング 
tb: 0   cm: --

【C#】【Unity】enum 型と string, int 型の相互変換など  


 enum 型をファイルに保存したり、UIなどのインデクスに対応させたりと、相互変換するとき確認したいことが多くあるので、備忘録的にまとめておいた。今回は通常の C# として書いているが、Unity などでも使用することは多いので、ちょっとしたトラブルシューティングなどもついでに。どちらかというとリファレンス的な使い方になると思うので、解説は少なめに凡例を列挙しておこう。


(※) mono-4.2.1 (C#6, CLI4.5)[paiza.io] / Unity 5.6.3p1 - 2018.1.5f1 / Windows10(x64) で確認



■enum → string 変換
using System;

enum BloodType //※enum 型は任意
{
A, B, O, AB
}

//enum → string 変換
BloodType bloodType = BloodType.A;
string str = bloodType.ToString();

Console.WriteLine(str);

A

 または以下のようにも書ける。
string str = Enum.GetName(typeof(BloodType), bloodType);

Console.WriteLine(str);

A




■string → enum 変換
using System;

enum BloodType //※enum 型は任意
{
A, B, O, AB
}

//string → enum 変換
string str = "B"; //"b" でも可
BloodType bloodType = (BloodType)Enum.Parse(typeof(BloodType), str, true); //true = IgnoreCase

Console.WriteLine(bloodType);

B

 ちょっと試しに IgnoreCase のオプションを外して小文字にしてみると、System.ArgumentException が出る。
string str = "b";
//↓このコードはエラーが出ます。
BloodType bloodType = (BloodType)Enum.Parse(typeof(BloodType), str); //System.ArgumentException

Console.WriteLine(bloodType);

System.ArgumentException




■enum → int 変換
using System;

enum BloodType //※enum 型は任意
{
A, B, O, AB
}

//enum → int 変換
BloodType bloodType = BloodType.AB;
int i = (int)bloodType;

Console.WriteLine(i);

3




■int → enum 変換
using System;

enum BloodType //※enum 型は任意
{
A, B, O, AB
}

//int → enum 変換
int i = 3;
BloodType bloodType = (BloodType)Enum.ToObject(typeof(BloodType), i);

Console.WriteLine(bloodType);

AB

 試しに範囲外の値を入れてみると、そのまま整数値が出てくる。
//int → enum 変換
int i = 4; //範囲外の値
BloodType bloodType = (BloodType)Enum.ToObject(typeof(BloodType), i);

Console.WriteLine(bloodType);

4




■enum の名前の配列を取得
using System;

enum BloodType //※enum 型は任意
{
A, B, O, AB
}

string[] names = Enum.GetNames(typeof(BloodType));

Console.WriteLine(string.Join(", ", names));

A, B, O, AB




■enum の値(enum)の配列オブジェクト(Array)を取得
using System;

enum BloodType //※enum 型は任意
{
A, B, O, AB
}

Array values = Enum.GetValues(typeof(BloodType));

foreach (var item in values) {
Console.WriteLine(item + " = " + (int)item);
}

A = 0
B = 1
O = 2
AB = 3




■enum を long 型で使う
using System;

enum LongRange : long //※enum 型は任意
{
Min = long.MinValue,
Num = 123456789L,
Max = long.MaxValue,
}

long min = (long)LongRange.Min; //キャストが必要
long num = (long)LongRange.Num; //キャストが必要
long max = (long)LongRange.Max; //キャストが必要

Console.WriteLine(min);
Console.WriteLine(num);
Console.WriteLine(max);

-9223372036854775808
123456789
9223372036854775807




■enum の値割当と Unity インスペクタのずれを直す(Unity トラブルシューティング)

 例えば以下のような列挙型があったとき、途中から "Banana" を削除したくなったとしよう。しかし、コメントアウトで消したとするとそれぞれに割り当てられれた値がずれ、インスペクタでの表示(名前)も変わってしまう。

public enum Hoge  //※enum 型は任意
{
Apple,
//Banana,
Cat,
Dog,
}
public Hoge hoge;

 これは、コメントアウト前は {Apple = 0, Banana = 1, Cat = 2, Dog = 3} であったのに対し、コメントアウト後は {Apple = 0, Cat = 1, Dog = 2} になるために出る症状なので、以下のように値を直接割り当てれば、元の並びと同じになる。

public enum Hoge  //※enum 型は任意
{
Apple,
//Banana,
Cat = 2,
Dog,
}
public Hoge hoge;

 また列挙型はデフォルトでは0からの整数連番だが、重複しなければ値は自由に割り当てられるので、飛び番号や負の値なども使える。色々やってみると良いだろう。



■enum の PlayerPrefs 保存と読み込み(Unity)

 Unity でユーザーデータとして enum 型の保存と読み込みをやってみよう。といっても内容的には先に述べた「enum←→stringの相互変換」をやっているだけである。ここでは Load と Save の機能を持ったメソッドを2つ作ったとする。シーンに UI-Button を2つ置いて、それぞれの OnClick() で呼び出すなどすれば、簡単に確認できるだろう。

using System;
using UnityEngine;

public enum Hoge { //※enum 型は任意
Apple,
Banana,
Cat,
Dog,
}
public Hoge hoge = Hoge.Apple;

string prefsName = "hoge";

public void LoadHoge() //UI-Button の OnClick に登録する等
{
string str = PlayerPrefs.GetString(prefsName, hoge.ToString());
hoge = (Hoge)Enum.Parse(typeof(Hoge), str);

Debug.Log("Loaded : " + hoge);
}

public void SaveHoge() //UI-Button の OnClick に登録する等
{
PlayerPrefs.SetString(prefsName, hoge.ToString());
PlayerPrefs.Save();

Debug.Log("Saved : " + hoge);
}

(インスペクタで「Banana」を選んで保存・読み込みをした場合)
Saved : Banana
Loaded : Banana

 ちなみに int 型で保存と読み込みをする場合には以下のように書ける。

・・・(略)・・・
public void LoadHoge()
{
int i = PlayerPrefs.GetInt(prefsName, (int)hoge);
hoge = (Hoge)Enum.ToObject(typeof(Hoge), i);

Debug.Log("Loaded : " + hoge + " (" + i + ")");
}

public void SaveHoge()
{
PlayerPrefs.SetInt(prefsName, (int)hoge);
PlayerPrefs.Save();

Debug.Log("Saved : " + hoge + " (" + (int)hoge + ")");
}
・・・(略)・・・

(インスペクタで「Banana」を選んで保存・読み込みをした場合)
Saved : Banana (1)
Loaded : Banana (1)

 stringint のどちらでも良いが、後から値の割当を変えたくなったときにも対応できるように、string 型で保存しておいた方が無難ではあるだろう(※public で宣言してる場合、後から変更するとインスペクタでの名前表示のずれが発生するので注意)。


(関連記事)
【Java】enum を int で取得する
【Java】文字列を enum 型に変換する
【Unity】色形式:Unity の Color と Android の ARGB(int32) の相互変換をする


category: C#

thread: プログラミング

janre: コンピュータ

tag: C#リファレンス  Unityトラブルシューティング 
tb: 0   cm: --


プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop