8 - プレイヤーのインスタンス化
このセクションではネットワーク上の「プレイヤー」プレハブのインスタンス化を説明します。プレイ中の自動シーン切替に必要となる様々な機能を実装します。
プレイヤーのインスタンス化
「プレイヤー」プレハブのインスタンス化は非常に簡単です。
ルームに入室した際にインスタンス化を行うと、アリーナを読み込んだことを示すGameManagerのスクリプトStart()
メッセージに依存できるようになります。これは私たちの設計ではルームをルームに入ったことを意味します。
GameManager
スクリプトを開きます。Public Fieldsリージョンで以下の変数を追加します。
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.LogFormat("We are Instantiating LocalPlayer from {0}", 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()
でインスタンス化します。(「プレイヤー」プレハブが参照されていると適切な確認をした後)
床よりだいぶ上の位置をインスタンス化していることに留意してください。(プレイヤーは2ユニットの高さですが、インスタンスは5ユニットの高さです。)
これは、新しいプレイヤーがルームに参加する際の衝突を防ぐ方法のひとつです。プレイヤーがアリーナの中央付近で既に移動している可能性があるので、突然の衝突を避けることができます。 「落下中」のプレイヤーはゲームでの新しいエンティティを意味します。
今回の場合はそれでは不十分です。 他のプレイヤーが参加する場合、異なるシーンが読み込まれます。その際、1人のプレイヤーの退室によって既存のプレイヤーが破棄されることを防ぎ、一貫性を維持する必要があります。そのため、作成したインスタンスを破棄しないようUnityに伝える必要があります。つまり、シーンが読み込まれたときにインスタンス化が必要かどうかを確認する必要があります。
プレイヤーインスタンスをトラッキングする
PlayerManager
スクリプトを開きます。「Public Fields」リージョンに以下を追加します。
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.LogFormat("We are Instantiating LocalPlayer from {0}", SceneManagerHelper.ActiveSceneName); // 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.LogFormat("Ignoring scene load for {0}", SceneManagerHelper.ActiveSceneName); }
GameManager
スクリプトを保存します。
アリーナ外でプレイヤーの位置を管理
もう1つ留意する点があります。
アリーナの大きさはプレイヤー数に応じて変わります。つまり、プレイヤーが退出して他のプレイヤーが現在のアリーナサイズの限界に近づいた場合、読み込み時に小さい方サイズのアリーナの外に出てしまうことがあります。この場合は、プレイヤーをアリーナの中心に戻す必要があります。これは、ゲームプレイやレベルの設計に特有の問題です。
Unityが「シーン管理」を改訂し、Unity5.4では一部のコールバックが軽視されているため、すべてのUnityバージョン(Unity 4.7から最新まで)で作動するコードを作成することは若干難しくなっています。このため、Unityのバージョンによってコードの組み方を変える必要があります。
これはPhotonネットワーキングとは関連がありませんが、プロジェクトをアップデートに対応させるためにマスターしておくことが大事です。
PlayerManager
スクリプトを開きます。Start()
メソッドの最後に以下のコードを追加します。C#
#if UNITY_5_4_OR_NEWER // Unity 5.4 has a new scene management. register a method to call CalledOnLevelWasLoaded. UnityEngine.SceneManagement.SceneManager.sceneLoaded += (scene, loadingMode) => { this.CalledOnLevelWasLoaded(scene.buildIndex); }; #endif
「MonoBehaviour CallBacks」リージョンに以下の2つのメソッドを追加します。
C#
#if !UNITY_5_4_OR_NEWER /// <summary>See CalledOnLevelWasLoaded. Outdated in Unity 5.4.</summary> void OnLevelWasLoaded(int level) { this.CalledOnLevelWasLoaded(level); } #endif void CalledOnLevelWasLoaded(int level) { // check if we are outside the Arena and if it's the case, spawn around the center of the arena in a safe zone if (!Physics.Raycast(transform.position, -Vector3.up, 5f)) { transform.position = new Vector3(0f, 5f, 0f); } }
PlayerManager
スクリプトを保存します。
この新しいコードによって、読み込まれるレベルが監視されるのに加えて、プレイヤーの現在の位置が下方に再計算されてなにかに衝突するか確認されます。 衝突しない場合にはアリーナの地面にいないことを意味し、中央に再配置される必要があります。これは、ルームに初めて入室した場合とちょうど同様です。
もしUnity5.4バージョンよりも前のバージョンを使用している場合は、 UnityコールバックOnLevelWasLoaded
を使用します。
Unity 5.4以上を使用している場合、OnLevelWasLoaded
は 今後使用できません。その代わりに、新しい SceneManagementシステムを利用する必要があります。 最後に、コードの複製を防ぐためOnLevelWasLoaded
またはSceneManager.sceneLoaded
コールバックから呼ばれるCalledOnLevelWasLoaded
メソッドがあります。