太郎Work

Unityとかで困ったこと等を残しておきます

UnityEditor再生開始時のイベント取得

UnityEditor再生時のイベント

実行、非実行時でモデルプレビュー出来るツールを作成しているのですが、再生時にモデルを一旦リセットして再生成するスクリプトを作成したい

ということでこんなスクリプトを書くと

f:id:tarowork:20160301174309p:plain

ここのボタンを押す度にOnPlayModeStateChangedメソッドが呼ばれるようになります

void OnEnable ()
{
    EditorApplication.playmodeStateChanged += OnPlayModeStateChanged;
}
void OnDisable ()
{
    EditorApplication.playmodeStateChanged -= OnPlayModeStateChanged;
}
void OnPlayModeStateChanged ()
{
    Debug.Log("Changed");
}

ここで問題なのが思っているよりも多くこのイベントが発行されるということです しかし、このメソッド内で

EditorApplication.isPlaying

EditorApplication.isPlayingOrWillChangePlaymode

の値を見るとより詳細なStateが確認できます

  1. 再生ボタン押下
  2. OnChanged : isPlaying=false, isPlayingOrWillChangePlaymode=true ※このタイミングで生成すると実行開始時にCleanupエラーが出る
  3. 開始するまで少し待つあれ 実行ログ出力開始
  4. OnChanged : isPlaying=true, isPlayingOrWillChangePlaymode=true ※実行開始、生成すると通常通り動作する
  5. 停止ボタン押下
  6. OnChanged : isPlaying=true, isPlayingOrWillChangePlaymode=false ※停止開始、生成するとあれ
  7. 完全停止待つ
  8. OnChanged : isPlaying=false, isPlayingOrWillChangePlaymode=false ※完全停止Editorの挙動開始

つまりisPlaying==isPlayingOrWillChangePlaymodeを見ることで実行、Editorに完全移行したかどうかが取れ、逆の場合は遷移する直前の処理が書けます

このままだとPauseボタンでも呼ばれてしまうので上記の条件が一致したらフラグを立てておくことでPauseを無視することができます でもOnDisableとOnEnableだけで上手く頑張れば出来るっぽい雰囲気 とりあえずこのプロパティと組み合わせれば厳密にStateを取れたという感じ

gist.github.com

Unity5.3でExecuteInEditModeとDontDestroyOnLoadを同時に使用した際の挙動

Unity5.3にアップデートしてかなり発見しにくいバグ?を見つけたのでメモ

問題

[ExecuteInEditMode]
public class Test : MonoBehaviour {
    void Awake() {
        DontDestroyOnLoad (gameObject);
    }
}

こんなクラスがあった時にEditor上でHierarchyにスクリプトを追加しようとすると表示されず、GameObject毎どこかに行ってしまいます。 FindObjectOfTypeを使用するとどこかに存在していることは分かるのですが、困ったことにどこにも見つかりません。

原因

原因はDontDestroyOnLoadの挙動が変更されているからのようです。 このメソッドが呼び出された直後、普段は隠蔽されている”DontDestroyOnLoad”シーンにGameObjectが移動される挙動になっていました。

gameObject.scene.name

でログを出力するとDontDestroyOnLoadシーンに飛ばされていることが分かります。

このシーンは実行直前にHierarchy上で確認することが出来ます。 f:id:tarowork:20151215221022p:plain

(実行が開始すると消えるので動画キャプチャから抜き出しました)

解決策

解決策としては実行している時のみ指定をすれば一応動作します

if (Application.isPlaying) {
    DontDestroyOnLoad (gameObject);
}

滅茶苦茶ハマりました…

ScriptableObjectのメンバリネーム

ScriptableObjectを使用している時に変数定義を変えたくなることがあると思います。
例えばpublicで定義していたけどやはりprivateのSerializeFieldにしてスクリプトからは読み込み専用にしたくなった等
その時は

[System.Serializable]
public class Data
{
  [SerializeField]
  [UnityEngine.Serialization.FormerlySerializedAs ("name")]
  private string _name;
}

これで変数名の移行が行われます。
この状態でプロジェクトの保存を行うと_nameに値が移行されていることを確認することが出来ます。
全ての関連ファイルの変更が行われたことを確認できたらFormerlySerializedAs属性は消しても大丈夫です。

※これに限らないですがPrefabと同じようにSaveProjectを実行しないと見た目は差し替わっていてもファイルに書き込まれていないため、書き込まれていることを確認してから属性削除は行う必要があります。

コマンド引数を指定しつつUnityを複数起動する方法

クローン後の初プロジェクトオープン時PC&Macでプロジェクトが開かれてしまい、そこからiOSにswitchPlatformするのも時間がかかりすぎるのでコマンドラインから起動する方法
そして複数起動も出来る方法です

open -n /Applications/Unity/Unity.app --args -buildTarget iPhone -projectPath projectpath

--args をつけるのがミソみたいです。

ターゲットの周りをくるくる回るサンプル

なんとなく作ったので記事にします
f:id:tarowork:20150630191903g:plain:w150
gist.github.com

ターゲットの周りを常に一定間隔で回るサンプルです。カメラのコンポーネントに付けてみてください
クォータニオン先輩使えば回転量定義できて座標変換が簡単に実装できます。

UnityEditorのObjectFieldでフォルダのみ入れる

もっと簡単な方法あれば教えて下さい><

Object folder;
var newFolder = EditorGUILayout.ObjectField (folder, typeof(Object), false);
var path = AssetDatabase.GetAssetPath (newFolder);
if (AssetDatabase.IsValidFolder (path)) {
	folder = newFolder;
} else {
	folder = null;
}

どこかにありそうですが、パッと見つからず、試しにそれっぽく使ってみたら上手く行ったのでメモとして残しました。

AssetBundleメモ

Unity5.1.0での話

  • AssetBundle.CreateFromFileはエラーになって動かない
  • ビルド時は出力フォルダの.manifestファイルを参照しているためファイルをリネームすると再ビルドが走る
  • AssetBundle本体のファイルが存在しているかどうかのチェックはされていないのでリネームしても可
  • AppendHashフラグを持たせるとファイル名の後にハッシュ値が付与されたファイル名になる。