Unity - Playモード中に生成したオブジェクトをSceneに残す

Game Play中に生成したオブジェクトをSceneに残す方法。

Scene中でオブジェクトを配置するとき、同じようなものが散らばっている状況がほしい場合、一つ一つ設置・位置調整という手順をいちいち行うのは面倒。
スクリプトから乱数で適当に配置したものをSceneに残し、その後手動で微調整するのがたぶん楽。
ただし通常、プレイモード終了時には開始時の状態に戻るため、一手間必要。

http://dymn.hatenablog.com/entry/2014/02/21/205409

で解説したオブジェクトが残る現象を逆に利用する。
f:id:DYMN:20151113232956p:plain
今回はこんな感じで室内に散らばった本を作りたい。

もっとスマートな方法があるのかもしれないが、知らぬ。

for( int ii = 0 ; ii < booksAmount ; ii++ )
{
	bookKind = Random.Range(0, booksObjPrefab.Length);

	bookPosition.x = Random.Range(xMin, xMax);
	bookPosition.z = Random.Range(zMin, zMax);

	bookRotate.eulerAngles = new Vector3(0.0f, Random.Range(0.0f, 360.0f), 90.0f);

	thisBook = (GameObject)Instantiate(booksObjPrefab[bookKind], bookPosition, bookRotate);
	thisBook.transform.parent = bookFolder.transform;

	bookLocation[ii].kind = bookKind;
	bookLocation[ii].pos  = bookPosition;
	bookLocation[ii].rot  = bookRotate;
}

オブジェクトのランダム配置は基礎的な知識で対応できるだろうから省略する。
今回の場合は本Objectを設置するにあたり、「本の種類」「位置」「回転」が重要なのでその3つを保存しておく。
Quaternionを使うときは事前に「Quaternion bookRotate = new Quaternion()」を忘れずに。

private class SetBookData
{
	public int kind;
	public Vector3 pos;
	public Quaternion rot;
}

private SetBookData[] bookLocation;

bookLocation = new SetBookData[booksAmount];

for (int ii = 0; ii < bookLocation.Length ; ii++)
{
	bookLocation[ii] = new SetBookData();
}

データクラスはこんな感じ。C#の場合初期化で配列各要素に対しコンストラクタを呼び出しておかないとエラーが出る。

void OnDestroy()
{
	if (saveFlag)
	{
		bookFolder = CreateFolder("Book");

		for (int ii = 0; ii < booksAmount; ii++)
		{
			GameObject thisBook = (GameObject)Instantiate(booksObjPrefab[bookLocation[ii].kind], bookLocation[ii].pos, bookLocation[ii].rot);
			thisBook.transform.parent = bookFolder.transform;
		}
	}
}

以前はOnDestroy中でオブジェクトを生成したからSceneに残ったが、今回はあえてOnDestroy中にインスタンスを生成する。
保存しておいた本の情報に従い、再度本オブジェクトを生成。プレイモードを終了するとScene中に残っているのが確認できる。
(エラーが出るが、今回はオブジェクトを残すのが目的なので甘受する)

ただし、プレイモード中に生成したオブジェクトを残した場合、終了直後のSceneではHierarchyで当該オブジェクトを確認できないケースがある。
この場合再度プレイモードを実行し、すぐに終了すれば確認できるようになる。
なので生成処理はプレイモードに入ったら自働で行うより、ボタン等のイベントで起こす形にした方がよい。
(Scene側で手動でスクリプトをON/OFFするならその限りではないが)
f:id:DYMN:20151113234528p:plain