Unity - ドアを使ってSceneを移動する

SceneとSceneの間をドアで移動する。
Scene間のドアが一つだけなら前後のSceneを参照すれば事は済むが、たとえば建物と庭が表口と裏口で繋がっている場合などは単純なScene名の参照では適切な場所へプレイヤーを配置できない。
そこを解決しながらSceneを切り替える。youtu.be
たぶんもっと上手い方法があるんだろうが、とりあえず今はこうする。

■Scene移動用ドアのPrefab
f:id:DYMN:20151109005312p:plain

SceneDoor
- Aside(Object)
- Bside(Object)

両Scene間で名前は同一にする。
SceneDoor_SceneA_SceneB
SceneDoorA_SceneC_SceneD/SceneDoorB_SceneC_SceneD
みたいな感じ。

■ドアに持たせるステータス

SceneDoorStatus
- thisDoorName : string
- sceneName : string[2] (Serialized)
-------------------------------------
+ GetOppositeSceneSide(string crntSceneName) : DoorSideID
+ GetSceneNameFromSide(DoorSideID sideID) : string

■他のオブジェクト(ゲームマスター的なオブジェクト)が持つシーンローダー

SceneLoader
- nextSceneSide : DoorSideID
- tgtDoorName : string
- sceneLoadedByDoor : bool
-------------------------------------
- OnLevelWasLoaded() : void
- LevelWasLoadedByDoor() : void
+ LoadSceneByDoor(GameObject tgtSceneDoor) : void
- LoadScene(string newSceneName) : void

■使用した列挙型

+ DoorSideID : Enum / Aside, Bside

■現在Sceneの名前を取得する
Application.loadedLevelName
■Sceneをロードする
Application.LoadLevel(string sceneName)

プレイヤーのカメラ内でクリックしたオブジェクトを取得する処理を入れておき、SceneDoorが取れたら(取る方法はTagかGetComponentあたりがいい?)SceneLoaderにそのオブジェクトを引数として渡す。
あらかじめSceneDoorStatus.sceneNameには両面のSceneNameを入れておき、現在Scene名を入れると反対側Scene名が取れる関数も仕込んでおく。

ただし、実際のSceneのロードはApplication.LoadLevel実行の後次のフレームで行われるようなので、新Sceneの処理は別途OnLevelWasLoaded関数(Unity既存関数)に記述する必要がある。
ここでは新Sceneにおけるプレイヤーオブジェクトの初期位置を決定している。新Scene内でのDoorの検索はFindを使っている。たぶんこれのせいで若干遅いんだろうな……

	void OnLevelWasLoaded()
	{
		if (sceneLoadedByDoor)
		{
			LevelWasLoadedByDoor();
			sceneLoadedByDoor = false;
		}
	}

	private void LevelWasLoadedByDoor()
	{
		string sceneDoorPath = "/Door/" + tgtDoorName;
		GameObject doorInNextScene = GameObject.Find(sceneDoorPath).gameObject;

		if (doorInNextScene == null)
		{
			Debug.LogWarning("Failue to find door in next scene.");
		}
		else
		{
			string sideObjName = nextSceneSide.ToString();

			GameObject doorSideObj = doorInNextScene.transform.FindChild(sideObjName).gameObject;

			CharacterLoader charaLoader = CommonFunction.GetCharacterLoaderComponent();
			GameObject mainPlayerObj = charaLoader.MainPlayerObject;

			mainPlayerObj.transform.position = doorSideObj.transform.position;
		}
	}

Scene名を入れたりする部分がStringの手打ちになって不安なので、このへんなんとかしたいけどScene型の変数は無いから別途他の手段を探す必要がありそうだ。