Unity」タグアーカイブ

[Unity]:ml-agentsのBasicデモを改良する

[検証バージョン]
Unity 2017.2.0p4
Unity ML – Agents (Beta) 0.2

Unityが提供している機械学習の仕組みに関するお話です。

Unity ML – Agents (Beta)に含まれるBasicデモが、学習させても期待通りの結果が得られなかったので、学習に使用するstateを増やしたところ概ね期待する結果が得られるようになりました。

・デモの内容
エージェントが1マスずつ左右に動き、ゴールに到達したらリワードを獲得。
ゴールは2種類あり、片方は近いがリワードは小さい、もう片方は遠いがリワードは大きい。

・変更内容
Brainが判断をするために与えられている情報(state)がエージェントの左右の位置しか無かったので、各ゴールの位置も渡すように変更。

1.BrainのStateSpaceTypeをDiscrete→Continuousに変更し、StateSizeを元々の1→3に増やす。

2.BasicAgent.cs内のCollectState()にて収集する情報を追加する。

	public override List<float> CollectState()
	{
		List<float> state = new List<float>();
		state.Add(minPosition); // 追加
		state.Add(maxPosition); // 追加
		state.Add(position); // 元々ある行
		return state;
	}

・補足
かなり単純なデモでありながら、8エージェント×10,000ステップの学習でもまだ無駄な動きがあるように見えるので、もっとパラメータや処理の調整が必要なのかもしれません。

・追記-改善案(未検証)
1.位置情報に関するstateはエージェントとの相対座標でコード化した方が良い。
Environment Design Best Practices

2.エージェントのObservationsにカメラを設定することで、視覚情報を与え学習の効率化ができるかもしれない。
Learning Environments Overviewの最後の項Additional FeaturesのComplex Visual Observations

SafariでWebGL内のファイルが保存ができない

・症状
Safari上で実行しているWebGLアプリで設定データなどが保存されず、再訪問もしくは再読み込みの度に設定データが初期状態に戻ってしまう問題が発生しました。

JavaScriptコンソールを見ると、WebGLの初期化時に
“IndexedDB is not available. Data will not persist in cache and PlayerPrefs will not be saved.”
というログが出ていました。

・対応
※ セキュリティ上の問題があるかもしれませんので、ご自身の判断で行ってください。

Safariの「開発」メニューから「クロスオリジンの制限を無効にする」設定をすると設定データを保持できるようになります。

ただ、JavaScriptコンソールに以下の警告ログが出るようになります。
“warning: FS.syncfs operations in flight at once, probably just doing extra work”
[参考]:warning: FS.syncfs operations in flight at once, probably just doing extra work

・原因
WebGLではファイルのIOにindexedDBを使用しています。
これがSafariのデフォルト設定ではセキュリティにより使用できないようになっているようです。
[参考]:
(Appleに開発者登録している方しかご覧になれないかもしれません。)
What’s New in Safari – Safari 11.0 – Security and Privacy

・補足
Unityから書き出したWebGLでファイルIOが上手くいかない問題がもともとあったようです。
[参考]:Data PersistenceSaving Games Online in Unity WebGL

ただUnity2017.2では対応がされているようです。
(実際にはだいぶ前のバージョンで対応されているようです。)
前記の警告ログはUnityのWebGLがindexedDBを同期する時に出ているものと思われます。

[Unity]:Unity1週間ゲームジャムに参加しました

unityroom主催のUnity1週間ゲームジャムに参加しました。
お題は「space」。

投稿作品:スペースクリッカー

お題を文字通りに宇宙と捉えて、以前から作ってみたかった惑星を巡って交易や採取を行うようなゲームを当初は考えたのですが、短期間で作り上げないといけないということで、得意のクリッカー系ゲームを作ることにしました。

隕石をクリックで壊してポイント稼ぐ→稼いだポイントでより隕石を壊しやすいようパワーアップ。

方針は割とすぐに決まり月曜日のうちには制作に入って、水曜日にはほぼ形になりました。

普段、一般公開向けのアプリを作る時などは拡張性などを考慮するのですが、今回は一週間で完成することを目標に「後々の拡張などは考えない」とバッサリと切り捨てて考えました。

一番悩んだポイントはゲームの進行に伴って難易度をどう変化させていくか。
本来なら外出しの設定ファイルにして隕石の出現データを作るところですが、思い切って単純化して…

・隕石10個ごとに難易度アップ
・序盤は難易度アップする度により大きな隕石が出現
・全種類の隕石が出揃ったら隕石の耐久度を2倍、3倍…としていく

またパワーアップの内容・コストも同様の理由で線形で増えていくようになっています。
本来なら外部ファイルにしないまでも配列データかもう少し複雑な計算式にしたと思います。

○ 使用アセット紹介
最初はもちろんキューブやスフィアでプロトタイプを作ったのですが、そこからどのように肉付け・修正していったのか、導入した順で使用したアセットを紹介します。

・Asteroid Pack – by Pixel Make

まず最初に、本ゲームのメインとなる隕石をスフィアから置き換えました。
隕石アセットは無料でも色々ありますが、リアルよりの表現と隕石の種類の多さから選定しました。
S〜XXLの5種類の隕石+配布者のロゴ入り隕石がオマケに付いてきますw

このアセットの導入により隕石の種類は大きさにより5種類と決定しました。
モデルの導入に伴い、隕石の大きさによりコライダの大きさを調整したり、HUD(耐久度表示のバーとテキスト)の位置を調整しました。

またスフィアからモデルに置き換えたことで隕石を回転させた方が見た目が良い事に気付きました。
実際に回転させてみるとuGUIのWorld Spaceで隕石に追随させていたHUDが一緒に回転する問題が発生し、常にカメラの方を向くようスクリプトを追加して調整が必要でした。

・SCI-FI Modular Pack Free

次にゲーム画面の手前側に置いてある基地をキューブから置き換えました。
隕石・基地と見栄えの部分が変わるとゲームが出来てきた!って感じになりますからね^^;

このアセットは細かいパーツを組み合わせて使うのですが、今回の基地はデモシーンにあるものをそのまま流用させてもらいました。
電光掲示板風のパーティクルが含まれてまして、非常に気になったのですが今回は活用できませんでした^^;

・Universal Sound FX

音が付くとゲームらしさがぐっと上がるので、早い段階で音を鳴らす仕組みを実装して、音源は仮でも良いので入れておくと良いと思います。

このアセットは効果音を探す時に一番最初に見るアセットです。
まめに音源追加のアップデートがされており、現在は$40で5,000以上の音源を収録しています。
これだけあればという訳にはいかないのですが、かなり良心的で良いサウンド集だと思います。

見た目と音が出来たところで、演出・効果を追加していきます。

・War FX

隕石破壊時のパーティクルエフェクトに使用。
パーティクルには苦手意識があって、普段アプリ開発でもあまり使わないのですが、このパーティクル集はデモもしっかりしててプレファブをインスタンス化するだけで使えたので楽でした。

・iTween

隕石が基地に激突した時に画面が揺れる演出を追加。
やって見たら非常に簡単でiTweenのShakeRotation()でカメラを揺らしただけです。
最近はDOTweenが主流になりつつありますが、まだしっかり使いこなせていなくて…
iTweenは使い慣れているため、サクッと作りたい今回は助かりました^^;

・SmartPool

一通りゲームが完成したところで、初のwebGLビルド、unityroomへの投稿はすんなりいったのですが、ゲームがたまに止まる!

本来なら早い段階から実機・実際に稼働させる環境で試すべきでしたが、今回は製作期間も短いので油断していました。

止まるタイミング的に、隕石や爆発パーティクルを都度生成しているのがいけないと思い込んで、プーリングの仕組みを導入。
プーリングの仕組みをちゃんと使ったのは初めてだったのですが、このアセットはシンプルでREADMEとデモシーンを見て5分ほどですぐ使えました。

プーリングを導入した結果、ゲームの停止は大幅に改善したものの依然として少し止まります^^;
本来ならちゃんとプロファイリングなどして原因を特定してから対処すべきでした。

今回は見込みは外れてなかったものの、他にも原因がありそうということで。
おそらく隕石クリック時に光らせるのにマテリアルをいじっているので、そこが原因かと(ちゃんと調べてない…)

参考:
色を変えるがドローコールを増やさない場合 – テラシュールブログ
「ちなみに、こっちは余り知られていないかもしれないが、マテリアルに値を突っ込んだ際にインスタンス化したマテリアルは、親オブジェクトをDestroyしても破棄されない。」

【Unity】マテリアルやSetPassを増やさずテクスチャのUVを変える – テラシュールブログ

○ あとがき
短い期間で仕様考えたり、今まで使ったことないものを勉強して使ってみたり、とっても勉強と刺激になりました!
実は今年の春ごろにつくっていたアプリをエターナらせてしまいまして^^;
それから悶々と現実逃避してGame of warやらオーシャン&エンパイアとか色々なものに時間を費やしてしまいまして。
今回の一週間ゲームジャムが現実復帰の第一号になりました^^;

できればエターナったゲームもunityroomに上げて、さらにできることであれば、手を入れて完成まで持っていきたいと思っています。

[Unity]:プレファブのYAMLを直接編集して子を削除する

[検証バージョン] Unity 5.5.1p3

直接編集はファイルの破損などの危険があるため、各自で判断の上、バックアップをちゃんととってお試しください。

追記:

ヒエラルキービュー上でプレファブの子を削除するとプレファブとの関連付けが解かれたように見えますが、実はその状態でApplyをすることができます。
Twitterでご教示いただきました。ありがとうございます!


階層構造を持つオブジェクト群をプレファブ化した場合、その子の一部を消すことってできませんよね?

プロジェクトビューからは子の一部を削除することはできないし、ヒエラルキービューで子を削除しようとするとプレファブとの関連が解けてしまいます。
子を追加してApplyはできるけど、削除はできないんです。

※ もしUnityの通常の操作でプレファブの一部の子だけを消すことができるのでしたら教えてください。

なんとかならないかと思い、まずはプレファブのインスタンスが置かれているシーンファイルをのぞいてみました。
(シーンファイルはデフォルト設定ではバイナリになっているので、Editor SettingsでAsset SerializationのModeをForce Textにしないと中身を見ることができません)

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
 ・
 ・
 ・
(ライティングなどのシーン設定に関する記述)
 ・
 ・
 ・
--- !u!1001 &1314774805
Prefab:
  m_ObjectHideFlags: 0
  serializedVersion: 2
  m_Modification:
    m_TransformParent: {fileID: 0}
    m_Modifications:
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalPosition.x
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalPosition.y
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalPosition.z
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalRotation.x
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalRotation.y
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalRotation.z
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalRotation.w
      value: 1
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_RootOrder
      value: 0
      objectReference: {fileID: 0}
    m_RemovedComponents: []
  m_ParentPrefab: {fileID: 100100000, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
  m_IsPrefabParent: 0

どうやらプレファブとの関連付けが記述されているだけで、プレファブファイルの方を直接編集してやれば上手くいきそうです。

※ ただし、以下の場合は関連付け以外の情報がシーンファイルに含まれるので注意が必要です。
・プレファブ化した元のオブジェクトがそのままシーンに残っている場合
・プレファブをインスタンス化したものにコンポーネントや子オブジェクトを追加した場合。

それではプレファブのファイルを編集してみます。

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &100100000
Prefab:
  m_ObjectHideFlags: 1
  serializedVersion: 2
  m_Modification:
    m_TransformParent: {fileID: 0}
    m_Modifications: []
    m_RemovedComponents: []
  m_ParentPrefab: {fileID: 0}
  m_RootGameObject: {fileID: 1006150272106676}
  m_IsPrefabParent: 1
--- !u!1 &1006150272106676
GameObject:
  m_ObjectHideFlags: 0
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  serializedVersion: 5
  m_Component:
  - component: {fileID: 4721125990716184}
  m_Layer: 0
  m_Name: GameObject
  m_TagString: Untagged
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
--- !u!1 &1271471559630830
GameObject:
  m_ObjectHideFlags: 0
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  serializedVersion: 5
  m_Component:
  - component: {fileID: 4955832607490314}
  - component: {fileID: 33287708229778766}
  - component: {fileID: 65699820418463966}
  - component: {fileID: 23228631480229132}
  m_Layer: 0
  m_Name: Cube
  m_TagString: Untagged
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
--- !u!4 &4721125990716184
Transform:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1006150272106676}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: 0, y: 0, z: 0}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_Children:
  - {fileID: 4955832607490314}
  m_Father: {fileID: 0}
  m_RootOrder: 0
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!4 &4955832607490314
Transform:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1271471559630830}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: 0, y: 0, z: 0}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_Children: []
  m_Father: {fileID: 4721125990716184}
  m_RootOrder: 0
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!23 &23228631480229132
MeshRenderer:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1271471559630830}
  m_Enabled: 1
  m_CastShadows: 1
  m_ReceiveShadows: 1
  m_MotionVectors: 1
  m_LightProbeUsage: 1
  m_ReflectionProbeUsage: 1
  m_Materials:
  - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
  m_StaticBatchInfo:
    firstSubMesh: 0
    subMeshCount: 0
  m_StaticBatchRoot: {fileID: 0}
  m_ProbeAnchor: {fileID: 0}
  m_LightProbeVolumeOverride: {fileID: 0}
  m_ScaleInLightmap: 1
  m_PreserveUVs: 1
  m_IgnoreNormalsForChartDetection: 0
  m_ImportantGI: 0
  m_SelectedEditorRenderState: 3
  m_MinimumChartSize: 4
  m_AutoUVMaxDistance: 0.5
  m_AutoUVMaxAngle: 89
  m_LightmapParameters: {fileID: 0}
  m_SortingLayerID: 0
  m_SortingOrder: 0
--- !u!33 &33287708229778766
MeshFilter:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1271471559630830}
  m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
--- !u!65 &65699820418463966
BoxCollider:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1271471559630830}
  m_Material: {fileID: 0}
  m_IsTrigger: 0
  m_Enabled: 1
  serializedVersion: 2
  m_Size: {x: 1, y: 1, z: 1}
  m_Center: {x: 0, y: 0, z: 0}

「— !u!1001 &100100000」のような記述から始まるひとかたまりが一つのオブジェクトやコンポーネントを表しているのがわかります。
前半がオブジェクトに関する記述、後半がコンポーネント。親子関係はTransformコンポーネントの部分に記述されています。

「m_Name:」にオブジェクト名が書かれているので、今回消したい子オブジェクト’Cube’を探します。

--- !u!1 &1271471559630830
GameObject:
  m_ObjectHideFlags: 0
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  serializedVersion: 5
  m_Component:
  - component: {fileID: 4955832607490314}
  - component: {fileID: 33287708229778766}
  - component: {fileID: 65699820418463966}
  - component: {fileID: 23228631480229132}
  m_Layer: 0
  m_Name: Cube
  m_TagString: Untagged
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1

先頭に書かれている「— !u!1 &1271471559630830」の「1271471559630830」がこのオブジェクトの固有のIDです。
このIDでファイル内を検索すると4つのコンポーネントが付いていることがわかります。

そのうちの一つTransformコンポーネントに関する記述をみてみます。

--- !u!4 &4955832607490314
Transform:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1271471559630830}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: 0, y: 0, z: 0}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_Children: []
  m_Father: {fileID: 4721125990716184}
  m_RootOrder: 0
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

今度はこのTransformコンポーネントのID「4955832607490314」で検索すると、親のTransformの記述が見つかります。

--- !u!4 &4721125990716184
Transform:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1006150272106676}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: 0, y: 0, z: 0}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_Children:
  - {fileID: 4955832607490314}
  m_Father: {fileID: 0}
  m_RootOrder: 0
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

ここの「m_Children:」というところに子のTransformのIDが書かれているので、この行を削除してしまいます。

--- !u!4 &4721125990716184
Transform:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1006150272106676}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: 0, y: 0, z: 0}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_Children:
  m_Father: {fileID: 0}
  m_RootOrder: 0
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

あとは、先ほど見つけたオブジェクトに関する記述と4箇所のコンポーネントに関する記述を消すだけです。

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &100100000
Prefab:
  m_ObjectHideFlags: 1
  serializedVersion: 2
  m_Modification:
    m_TransformParent: {fileID: 0}
    m_Modifications: []
    m_RemovedComponents: []
  m_ParentPrefab: {fileID: 0}
  m_RootGameObject: {fileID: 1006150272106676}
  m_IsPrefabParent: 1
--- !u!1 &1006150272106676
GameObject:
  m_ObjectHideFlags: 0
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  serializedVersion: 5
  m_Component:
  - component: {fileID: 4721125990716184}
  m_Layer: 0
  m_Name: GameObject
  m_TagString: Untagged
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
--- !u!4 &4721125990716184
Transform:
  m_ObjectHideFlags: 1
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 100100000}
  m_GameObject: {fileID: 1006150272106676}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: 0, y: 0, z: 0}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_Children:
  m_Father: {fileID: 0}
  m_RootOrder: 0
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

これでプレファブファイルがUnityで読み込まれたタイミングでプレファブと全てのインスタンス化されたオブジェクトから子オブジェクト’Cube’が消えます。

インスタンス化してシーンに置かれたオブジェクトに個別に編集を行なっている場合にはシーンファイルにゴミが残る可能性があるので、くれぐれもご注意ください。

以前にUnityのYAMLを読んでみようみたいな記事を見かけたことがあったのですが、まさか本当に自分が読むことになるとは思ってもいませんでした^^;
しかし実際にのぞいてみるとかなりシンプルで分かりやすいですね。
ちなみにプレファブをインスタンス化したものに施した変更はシーンファイルの中の「Prefab:」のところに追記される形で記述されます。

警告はしましたが実際はコンポーネントのパラメータを変更したり、コンポーネントを削除してる場合は今回の編集では影響受けないみたいです。
ただし削除するオブジェクトにコンポーネントを追加していたり、配下にさらに子を追加したりしているとシーンファイルにゴミが残るみたいです。

以下は削除したCubeオブジェクトに適当なスクリプトを追加、また配下にSphereを追加していた場合のシーンファイルです。

--- !u!1001 &1314774805
Prefab:
  m_ObjectHideFlags: 0
  serializedVersion: 2
  m_Modification:
    m_TransformParent: {fileID: 0}
    m_Modifications:
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalPosition.x
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalPosition.y
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalPosition.z
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalRotation.x
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalRotation.y
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalRotation.z
      value: 0
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_LocalRotation.w
      value: 1
      objectReference: {fileID: 0}
    - target: {fileID: 4721125990716184, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
      propertyPath: m_RootOrder
      value: 0
      objectReference: {fileID: 0}
    m_RemovedComponents: []
  m_ParentPrefab: {fileID: 100100000, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884, type: 2}
  m_IsPrefabParent: 0
--- !u!1 &1314774806 stripped
GameObject:
  m_PrefabParentObject: {fileID: 1271471559630830, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884,
    type: 2}
  m_PrefabInternal: {fileID: 1314774805}
--- !u!114 &1314774807
MonoBehaviour:
  m_ObjectHideFlags: 0
  m_PrefabParentObject: {fileID: 0}
  m_PrefabInternal: {fileID: 0}
  m_GameObject: {fileID: 1314774806}
  m_Enabled: 1
  m_EditorHideFlags: 0
  m_Script: {fileID: 11500000, guid: c75fe1ad4fe3e493ab421c02f41fed06, type: 3}
  m_Name: 
  m_EditorClassIdentifier: 
--- !u!4 &1314774808 stripped
Transform:
  m_PrefabParentObject: {fileID: 4955832607490314, guid: 6071afa7dc4674b5ebaa3a0fa0c5c884,
    type: 2}
  m_PrefabInternal: {fileID: 1314774805}

Unityのヒエラルキービュー上では問題なさそうに見えますが、シーンファイルにはしっかりゴミが残っているようです。

[Unity]:MonoBehaviour.OnApplicationPause()の挙動

[検証バージョン]
Unity 5.1.2p2
iOSシミュレータ 8.4
Android Genymotion 4.2.2 API 17

アプリがバックグラウンドに入った時・および復帰した時の処理を記述するMonoBehaviour.OnApplicationPause()

この中に記述する処理が重く時間がかかり途中でアプリが強制終了された場合、どのような挙動になるのか検証してみた。

・検証方法
OnApplicationPauseでバックグラウンド退避時の処理中に数秒待機してデバッグプリントを行う。

using UnityEngine;

public class GameController : MonoBehaviour {
	void OnApplicationPause(bool isPause) {
		if (isPause) {
			Debug.Log("OnApplicationPause()");
			System.Threading.Thread.Sleep(3000);
			Debug.Log("3 seconds lator..");
		}
	}
}

・iOSの場合
アプリ起動中にホームボタン2度押し→アプリを終了

-> applicationWillResignActive()
OnApplicationPause()
3 seconds lator..
-> applicationDidEnterBackground()
-> applicationWillTerminate()

ちゃんと3秒後にデバッグプリントされた後に、バックグラウンド→終了となっている。

ただし、OnApplicationPauseをコルーチンにした場合はバックグラウンドに入った時点で処理が一時停止してしまうので注意が必要。

・Androidの場合
ハードウェアボタンでアプリの一覧を表示→アプリを終了

OnApplicationPause()のデバッグプリントのみで、処理は途中で中断されてしまった?

Androidの場合は、OnApplicationPause()での処理には注意が必要みたい。

[Unity, NGUI]:スクロールビューにスクロールバーを追加する

[検証バージョン]
Unity 5.1.2p2
NGUI 3.9.1

スクロールビューの基本についてはこちらをどうぞ。

1.スクロールバーの背景となる部分とつまみの部分、計2つのスプライトを作成。
スクロールバーのスプライトを追加

ヒエラルキー上での配置はスクロールビューの配下以外であればどこでも大丈夫。

垂直方向のスクロールバーの場合は2つのスプライトの高さを合わせておく必要がある。
見た目的につまみ部分が前面に表示されるようにDepthの設定もお忘れなく。

2.スプライトにコライダーを設定
スクロールバーの背景部分をクリックして移動する機能が必要なければ、背景用のスプライトにはコライダーを設定しなくても大丈夫。
コライダーの設定は目的のスプライトを選択した状態で、メニューバーから「NGUI」-「Attach」-「Collider」とするのが簡単。

3.適当なオブジェクトにUIScrollBarコンポーネントを追加
UIScrollBar

UIScrollBarコンポーネント用にNGUI Widgetを作ってその配下に先ほど作成したスプライトを配置しておくのが綺麗だと思う。
目的のオブジェクトを選択した状態でメニューバーから「NGUI」-「Attach」-「Scroll Bar Script」。

UIWidgetではなく適当なオブジェクトでも大丈夫だが、UIScrollView自体にUIScrollBarコンポーネントを追加するとスクロールバーの挙動がおかしくなる。

4.UIScrollBarの設定
UIScrollBarの設定

Foreground, Backgroundにそれぞれつまみ用・背景用のスプライトを設定。
Directionも適切に。

5.スクロールビューにスクロールバーを設定
UIScrollViewにスクロールバーを設定

スクロールビューのインスペクタにScroll Barsの項目があるので、Horizontal/Vertical目的の方にスクロールバーを設定。

ここで一度実行すると、UIScrollBarのValueなどの値が反映されるので、そこでスクロールバーの初期位置などを設定できる。
UIScrollBarの設定

Sizeが、スクロールビュー配下の全体サイズに対する表示範囲。スクロールビューに対して2倍のサイズのものを配置していれば0.5となる。
Valueがつまみの初期位置、0〜1。

[Unity, NGUI]:スクロールビューの基本

[検証バージョン]
Unity 5.1.2p2
NGUI 3.9.1

・基本的な考え方
ヒエラルキー上でスクロールビューの配下に配置されているUIをスクロールビューの範囲に限定して表示する。

スプライトがスクロールビュー配下にない場合

スプライトがスクロールビュー配下にない場合

スプライトがスクロールビュー配下にある場合

スプライトがスクロールビュー配下にある場合

またその名の通り、スクロールビュー配下に配置されたUIは、実行時にドラッグなどにより見える範囲を動かすことができる。

よくグリッドビューと組み合わせて紹介されることが多いが、グリッドビューはあくまで多数の項目を整列するだけのもので、スクロールビュー自体とは特に関係ない。

・作り方
UI Rootが存在する状態で、メニューバーから「NGUI」-「Create」-「Scroll View」を選択する。
作成されたScroll Viewの配下にUIを配置する。

ドラッグでスクロールさせたい場合は、配下のUIにコライダーとUIDragScrollViewを追加する。
コライダーの追加は目的のUIを選択した状態でメニューバーから「NGUI」-「Attach」-「Collider」とするのが簡単。
UIDragScrollViewの追加は目的のUIのインスペクタで「Add Component」-「NGUI」-「Interaction」-「Drag Scroll View」を選択。

スクロールビューのインスペクタでドラッグで動かせる方向などを指定できる。
スクロールビューのインスペクタ

[Unity, PlayMaker]:DontDestroyOnLoadの不具合

PlayMaker 1.7.8.2

アクションカテゴリ「Level」のアクション「DontDestroyOnLoad」で指定したGameObjectがシーンロード時に消えてしまいます。

DontDestroyOnLoadアクションのソースを見てみると…

// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved.

using System.Collections;
using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
	[ActionCategory(ActionCategory.Level)]
	[Tooltip("Makes the Game Object not be destroyed automatically when loading a new scene.")]
	public class DontDestroyOnLoad : FsmStateAction
	{
		[RequiredField]
        [Tooltip("GameObject to mark as DontDestroyOnLoad.")]
		public FsmOwnerDefault gameObject;

		public override void Reset()
		{
			gameObject = null;
		}

		public override void OnEnter()
		{
			// Have to get the root, since the game object will be destroyed if any of its parents are destroyed.
			
			Object.DontDestroyOnLoad(Owner.transform.root.gameObject);

			Finish();
		}
	}
}

せっかく引数で指定したgameObjectが指定されていません。
代わりにこのアクションを実行しているFSMを持つGameObjectがDontDestroyOnLoadになっているようです。

25行目を以下のように変更します。

			if (gameObject != null) Object.DontDestroyOnLoad(gameObject.GameObject.Value);

[Unity]:Unity5対応でハマった点

Unity4.5.5で作成した「あ〜ちゃ〜の大冒険」をUnity5対応する時にハマった点。

Unityバージョン4.5.5f1 -> 5.0.0p2

・シーン全体が暗くなった
アンビエントライトのせい。
メニュー「Window」-「Lighting」を開き調整する。

Unity5-lighting

・NavMeshAgentの挙動がおかしい
具体的には、あ〜ちゃ〜が一度立ち止まると、その後、移動しなくなる。
従来はNavMeshAgent.Stop()後にSetDestination()で座標を設定すると動いていたのだが、Resume()を呼び出す必要がある。

[Unity, PlayMaker]:Androidビルドで勝手にパーミッションが追加される

検証バージョン:Unity 4.5.5f1, PlayMaker 1.7.7f6

PlayMakerをインポートしたプロジェクトをAndroid向けにビルドすると、以下の権限(パーミッション)が勝手に追加されます。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

Unity自体が、特定のAPIを使用した場合にビルド時に自動的に権限を追加する仕様になっています。
一旦Androidプロジェクトを吐き出してからビルドする場合は変更できますが、直接apkを書き出す場合は厄介です。

もし該当する機能を使っていないのならば、PlayMakerのアクションを記述してあるスクリプトファイルを最初に削除してしまえば済むことです。

・android.permission.INTERNET
/PlayMaker/Actions/Network フォルダごと削除

・android.permission.VIBRATE
/PlayMaker/Actions/DeviceVibrate.cs

・android.permission.ACCESS_FINE_LOCATION
/PlayMaker/Actions/GetLocationInfo.cs
/PlayMaker/Actions/StartLocationServiceUpdates.cs
/PlayMaker/Actions/StopLocationServiceUpdates.cs

・android.permission.WAKE_LOCK
/PlayMaker/Actions/DevicePlayFullScreenMovie.cs

[参考]:apkに付与されている権限を調べる方法
aaptというADT付属のツールで調べることが出来ます。
詳しくはこちらを参考にさせて頂きました。
Yukiの枝折 – 「apkからマニフェストの内容を読み取る方法」