8-プレイヤーのインスタンス化
このセクションでは、ネットワーク上の「プレイヤー」プレハブのインスタンス化について説明します。プレイ中の自動シーン切り替えに必要となる様々な機能を実装します。
プレイヤーのインスタンス化
「プレイヤー」プレハブのインスタンス化は非常に簡単です。
ルームに入室した際にインスタンス化する必要があり、アリーナを読み込んだことを示すGameManager script's Start()
メソッドに依存することができます。これは、私たちの設計ではルームに入ったことを意味します。
GameManager
スクリプトを開きます。Variablesリージョンで以下の変数を追加します。
C#
[Tooltip("The prefab to use for representing the player")] public GameObject playerPrefab;
Start()メソッドで、以下を追加して
GameManager
スクリプトを保存します。C#
if (playerPrefab == null) { Debug.LogError("<Color=Red><a>Missing</a></Color> playerPrefab Reference. Please set it up in GameObject 'Game Manager'",this); } else { Debug.Log("We are Instantiating LocalPlayer from "+Application.loadedLevelName); // we're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate PhotonNetwork.Instantiate(this.playerPrefab.name, new Vector3(0f,5f,0f), Quaternion.identity, 0); }
GameManager
スクリプトを保存します。
これにより「プレイヤー」プレハブを参照するパブリックフィールドが公開されます。
このパブリックフィールドではプレイヤープレハブはアセットで、また参照がそのまま保持されるため(プレハブが同じシーンでインスタンス化した場合のみ行うことができる、階層でのGameObjectの参照ではなく)、各シーンではなくGameManagerプレハブに直接ドラッグアンドドロップできて便利です。
次にStart()
でインスタンス化します (「Player」プレハブが参照されていることを正常に確認した後)
床よりだいぶ上の位置でインスタンス化していることに留意してください(プレイヤーは2ユニットの高さですが、インスタンスは5ユニットの高さです)。
これは、新しいプレイヤーがルームに参加する際の衝突を防ぐ方法のひとつです。プレイヤーがアリーナの中央付近で既に移動している可能性があるので、突然の衝突を避けることができます。
「落下中」のプレイヤーはゲームでの新しいエンティティを意味します。
今回の場合はそれでは不十分です。
他のプレイヤーが参加する場合、異なるシーンが読み込まれます。その際、1人のプレイヤーの退室によって既存のプレイヤーが破棄されることを防ぎ、一貫性を維持する必要があります。そのため、作成したインスタンスを破棄しないようUnityに伝える必要があります。つまり、シーンが読み込まれたときにインスタンス化が必要かどうかを確認する必要があります。
プレイヤーインスタンスをトラッキング
PlayerManager
スクリプトを開きます。"Public Variables"リージョンに以下を追加します。
C#
[Tooltip("The local player instance. Use this to know if the local player is represented in the Scene")] public static GameObject LocalPlayerInstance;
Awake()
メソッドで、以下を追加します。C#
// #Important // used in GameManager.cs: we keep track of the localPlayer instance to prevent instantiation when levels are synchronized if ( photonView.isMine) { PlayerManager.LocalPlayerInstance = this.gameObject; } // #Critical // we flag as don't destroy on load so that instance survives level synchronization, thus giving a seamless experience when levels load. DontDestroyOnLoad(this.gameObject);
PlayerManager
スクリプトを保存します。
これらの変更により、GameManager
スクリプト内で必要な場合にのみインスタンス化するためのチェックを実装することができます。
GameManager
スクリプトを開きます。if文でインスタンス化コールを囲みます。
C#
if (PlayerManager.LocalPlayerInstance==null) { Debug.Log("We are Instantiating LocalPlayer from "+Application.loadedLevelName); // we're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate PhotonNetwork.Instantiate(this.playerPrefab.name, new Vector3(0f,5f,0f), Quaternion.identity, 0); } else { Debug.Log("Ignoring scene load for "+Application.loadedLevelName); }
GameManager
スクリプトを保存します。
これによってPlayerManager
がlocalPlayer
の既存インスタンスを参照をしない場合のみ、インスタンス化するようになります。
アリーナ外でプレイヤーの位置を管理
もう1つ留意すべき点があります。
アリーナのサイズはプレイヤーの数にもとづいて変化します。つまり、一人のプレイヤーが退室して他のプレイヤーが現在のアリーナサイズの限界に近づいた場合、読み込み時に小さいほうのアリーナの外に出てしまうことがあります。この場合はプレイヤーをアリーナの中心に戻す必要があります。これは、ゲームプレイやレベルの設計に特有の問題です。
現在、Unityが「シーン管理」を改良したばかりで、またUnity 5.4では一部のコールバックが軽視されているため、すべてのUnityバージョン(Unity 4.7から最新まで)で作動するコードを作成することは若干難しくなっています。このため、Unityバージョンに応じて異なるコードが必要です。
1.PlayerManager
スクリプトを開きます。
2. Start()
メソッドの最後に以下のコードを追加します。
#endif
```
3.「MonoBehaviour CallBacks」リージョンに以下の2つのメソッドを追加します。
///
void OnLevelWasLoaded(int level)
{
this.CalledOnLevelWasLoaded(level);
}
#endif
PlayerManager
スクリプトを保存します。
この新しいコードによって、読み込まれるレベルが監視されるのに加えて、プレイヤーの現在の位置が下方に再計算されてなにかに衝突するか確認されます。
衝突しない場合にはアリーナの地面にいないことを意味し、中央に再配置される必要があります。これは、ルームに初めて入室した場合とちょうど同様です。
Unity 5.4以下のUnityバージョンを使用している場合には、UnityのコールバックOnLevelWasLoaded
を使用します。
Unity 5.4以上を使用している場合、OnLevelWasLoaded
は今後使用できません。その代わりに、新しいSceneManagementシステムを利用する必要があります。
最後に、コードの複製を防ぐためOnLevelWasLoaded
またはSceneManager.sceneLoaded
コールバックから呼ばれるCalledOnLevelWasLoaded
メソッドがあります。