文字列からstatic/classプロパティの取得

staticプロパティを文字列から取得する方法がわからなかったので調べてみた。
ついでに、文字列でオブジェクトのプロパティの取り出しとメソッドの実行も。

class TestClass {
	public static string StaticPropName = "StaticValue";
	public int propName = 100;
	public string TestFunc(int num) {
		return "TestFuncValue : " + num;
	}
}

TestClass test = new TestClass();
Type testType = test.GetType();
print(testType.GetField("propName").GetValue(test));
// 出力 : 100

print(testType.GetMethod("TestFunc").Invoke(test, new object[]{ 777 }));
// 出力 : TestFuncValue : 777

Type typeOfTestClass = typeof(TestClass);
print(typeOfTestClass.GetField("StaticPropName").GetValue(typeOfTestClass));
// 出力 : StaticValue

CanvasGroupのinteractable

button_interactable_canvas_group_effect

いまさらながらですがCanvasGroup。
いままで、alphaが下層のImageとか(CanvasRendere)に影響して、まとめて透過させることは使ってたけど、interactableも便利。

button_interactable_canvas_group

下層のボタンとか(Selectable)のUIパーツを一気に操作不可にしてくれる。
もちろん、Buttonなどの個別のinteractableは保持しつつ、上層の設定値を優先してくれる。
各UIパーツからは、IsInteractable()メソッドにて上層の設定を含めたものが取得可能。

using UnityEngine;
using UnityEngine.UI;

/// <summary>
/// ボタンのinteractableの情報表示。
/// </summary>
public class ButtonInteractableStatus : MonoBehaviour {
	/// <summary>
	/// ステータス表示のText。
	/// </summary>
	[SerializeField]
	Text statusTxt;

	/// <summary>
	/// Button.
	/// </summary>
	Button button;

	/// <summary>
	/// Start.
	/// </summary>
	void Start() {
		this.button = this.GetComponent<Button>();
	}

	/// <summary>
	/// Update.
	/// </summary>
	void Update() {
		this.statusTxt.text = "interactable : " + this.button.interactable + "\n"
			+ "IsInteractable : " + this.button.IsInteractable();
	}
}

Invokeについて

Invokeを使うと指定秒後に指定のメソッドが実行できて便利。
でも引数が文字列なので、それが嫌な場合は

((Action)MethodName).Method.Name

で取得できる。
しかもInvokeはそのGameObjectが破棄されると自動で呼び出しも終わる。
簡易的に遅延させたい場合は便利。

参考)
いんでぃーづ | Invoke , Coroutine , SendMessage で文字列を使わない方法
Qiita | 【Unity】スクリプトの処理の実行タイミングを操作する

using UnityEngine;
using System;

/// <summary>
/// Invokeのテスト。
/// </summary>
public class InvokeTest : MonoBehaviour {
	/// <summary>
	/// Start.
	/// </summary>
	void Start() {
		this.InvokeMethod();
	}

	/// <summary>
	/// Invokeテスト。
	/// </summary>
	void InvokeMethod() {
		print("InvokeMethod called.");
		Invoke(((Action)this.InvokeMethod).Method.Name, 3f);
	}
}

アセットバンドルDL時の容量不足のケース

アセットバンドルを使った場合の容量不足について軽く試してみた。
予想としてはIOExceptionが発生するかと思っていた。実際試してみると、アセットバンドルの形式やサイズなどにもよるかもしれないけどどうやら容量が足りない場合もメモリ上(?)にて展開されているようでとくにエラーは出ず、DLが終わり通常通り処理が続く。
当然保存されていないので、アプリを落とすと次の起動の際に再度DLされる。
AssetBundleManagerを使っている場合は、指定のアセットを取り出す際にAssetBundleManager.m_DownloadingErrorsに“{0} is not a valid asset bundle.”というエラーが格納される。
あるべきはずアセットがないのはアセットが正しく保存されていない(おそらく容量が足りていない)という考えで、その際に容量不足のエラーを出すようにした。

アセットバンドルではなく、通常のファイルをDLする場合や圧縮ファイルを解凍する場合に容量が足りない場合にはIOExceptionが発生するようで、その際に容量不足のエラーを出した。

アセットバンドル更新時の削除

以前ここで書いたキャッシュファイルの削除について実際に、アセットバンドルを更新することがあったので具体的な補足。

AssetBundleManagerを使っているとアセットバンドルを更新すると自動的に新たなアセットバンドルをDLしてくれる。
ただし、以前のアセットバンドルが削除されるわけではなくて、別のアセットバンドルとして保存される。
でも、本当は以前のものは使わないので削除してほしい、、、
こちらのサイトでも言及されているけど、アセットバンドルを削除するのはすこし厄介なので、maximumAvailableDiskSpaceを設定した方が簡単。
以下の行程で挙動を確認し最大キャッシュ容量を設定し、以前のアセットバンドルが消えることを確認した。

Continue…

UIActivityのその他(more)を押すとスクリーンの方向が変わる

uiactivity_more

UnityにてSocialConnectorを使って、シェア機能を使っていて遭遇したんですが、横向きのみのアプリでこのSocialConnectorを使って、iOSのUIActiveViewControllerを呼び出し、そこからその他(more)を押すと許可するメディアの一覧が出てきます。
そのタイミングで端末の回転にロックがかかっていなく、端末自体がアプリの方向とは違う方向に傾いているとUnityのスクリーンの方向(Screen.orientation)が変わってしまった。。(横向きアプリのはずが縦向きなどになる)
1度発生してしまうとUnity上でScreen.orientationを書き換えてももう直らない。。。
取れる方法は、Screen.orientationをみて、本来の値と違っていたらエラーを出すとかになるでしょうか。
Unityのバグなのか、UIActivityのバグなのか、、、SocialConnectorではなさそうな気はするけど。

UIActivityのローカライゼーション

Unityで、Social Connectorを使うと簡単に、UIActivityが呼び出せる。

uiactivity

しかし、表記が英語になってしまう。
info.plistにてLocalization native development regionjaなどに変えれば指定の言語で表記されるようになる。
ただ、Localization native development regionは基本言語なので、ローカライズさせるには

UIActivity

こちらの値を変えたほうがいいかも。
XCodeProjectUpdaterを使う場合には、自分でつけ足す必要がある。
キーはCFBundleLocalizations、値はJapanseではなくja

ちなみに、LINEへの投稿を増やしたい場合には、iOS9以降許可するスキームの設定が必要。
XcodeProjectUpdaterにてApplication Queries Schemesの値を追加してみたけど、うまく反映されていなかった。
みてみたらSetApplicationQueriesSchemesの処理が抜けているようなので(僕が消した??)、その処理も加えて無事LINEへの投稿もできるようになりました。

AssetBundle化したShaderが外れてしまう

あるシーンをアセットバンドル化した際に、そのシーンで使われているパーティクルが白くなってしまったので調べてみた。
調べてみるとアセットバンドル化した際に、uGUIなどのシェーダーが外れてしまうことがあるらしい。

参考)神様は有給消化中です。 | AssetBundle化したPrefabのシェーダー参照が壊れる現象

AssetBundleManagerのSimulate Modeだと再現できないけど、実際にAssetBundleを読み込んでみると再現できる。

上記のサイトを参考に、パーティクルのGameObjectに対して再度設定するコンポーネントを割り当てたら動いた。

using UnityEngine;
using System.Collections;

/// <summary>
/// アセットバンドル化したパーティクルなどのシェーダーが外れてしまうので
/// それを回避するためにAwakeにて当て込む。
/// </summary>
public class ParticleShaderReset : MonoBehaviour {
	/// <summary>
	/// シェーダー。
	/// </summary>
	[SerializeField]
	string shaderStr;

	/// <summary>
	/// Awake.
	/// </summary>
	void Awake() {
		ParticleSystem ps = this.GetComponent<ParticleSystem>();

		Shader s = Shader.Find(this.shaderStr);

		if (s != null)
			ps.GetComponent<Renderer>().sharedMaterial.shader = s;
		else
			Debug.LogWarning(this.shaderStr + " シェーダーが見つかりません。");
	}
}

Unity IAP (In App Purchase)

iap
Unity5.3からUnity IAPがBetaで実装されたので使ってみようかなと思ったのでメモ。
下準備は、Soomlaのときと同じ感じで準備して、実装自体はSoomlaよりも簡単。
そもそもSoomlaのように、アイテムの個数の管理を端末で行ったりしないのでその辺の処理が一切必要なくStoreとの連携だけなのでシンプルで扱いやすい。サンプルが入っているので、中身を見ればだいたいわかる。
ただ、上の画像のようにUnity Analyticsを無効にするとUnity IAPも揃って無効になってしまう。逆にいうと、Unity IAPを入れるとUnity AnalyticsもONとなるので、おそらく購入の際のログが保存されるんじゃないかな??
このログは自分のアカウントと紐付いているので、クライアント案件のお仕事だと購入や起動などのログのデータをこちらのアカウントで保存するのはまずい気がするので今回は使用を控えようかなと思った。
ログのデータ自体は移行できるっぽい(?)けどクライアントにそもそもUnityアカウントを用意してもらう必要があるし、Personalアカウントの場合は月25ドルかかるらしい。

参考)
TechBuzz Unity勉強会 #35 | Unity Cloud BuildとUnity Analytics