プレイヤーキャラクタの出現処理と単体テスト

目次

  概要
  プレイヤーキャラクタを登場させる
  ここまでのNetworkControlの内容
  単独で動作テストをする
  エラーの原因を特定し、修正を加える
  ここまでのThirdPersonCameraの内容
  起動時のカメラの位置も変更する
  再度、単独で動作テストをする


概要

プレイヤーキャラクタを出現させ、単体での動作確認を行なう

  ネットワークの接続・切断、およびルームへの入退室が組み込み終わりました。
  では改めてプレイヤーキャラクタを登場させてみましょう。

注記:このページの途中から、実行ボタンを押して動作確認できます。

  長らく作業が続きましたが、お待たせしました。
  「このページの途中から」ですが、ようやくプレイすることができます。


プレイヤーキャラクタを登場させる

プレイヤーキャラクタを保持する変数を用意する

  NetworkControl の 10 行目に、以下の変数を宣言します。
	/** プレイヤーキャラクタ. */
	private GameObject playerObject = null;
	
  上記のように、プレハブから生成されたプレイヤーキャラクタの GameObject を保持する変数を用意します。

プレイヤーキャラクタを「全てのクライアントでほぼ同時に」出現させる

  NetworkControl の 22 行目から、以下のコードを記述します。
	// Update is called once per frame
	void Update()
	{
		// MUNサーバに接続しており、かつルームに入室している場合
		if (MonobitNetwork.isConnect && MonobitNetwork.inRoom)
		{
			// プレイヤーキャラクタが未登場の場合に登場させる
			if (playerObject == null)
			{
				playerObject = MonobitNetwork.Instantiate("Player", Vector3.zero, Quaternion.identity, 0);
			}
		}
	}
	
  MUNサーバに接続している状態で、かつルームに入室しており、プレイヤーキャラクタが未登場の場合(playerObject にまだ値が設定されていない場合)に、
  MonobitNetwork.Instantiate() メソッドを使い、ネットワーク越しに全てのクライアントに対し、自身のプレイヤーキャラクタを登場させます。

  MonobitNetwork.Instantiate() メソッドは以下のパラメータを持ちます。
第一引数
("Player")
GameObjectとして生成される元データの、プレハブの名前を指定します。
注意すべき点として、読み込み対象となるprefabファイルが、Resources フォルダに存在する必要があります。
第二引数
(Vector3.zero)
GameObjectを出現させる座標値について、Vector3型で指定します。
第三引数
(Quaternion.identity)
GameObjectを出現させるときの回転量について、Quaternion型で指定します。
第四引数
(0)
その GameObject が所属する、MUNネットワーク上のグループIDを指定します。
通常は0を指定します。


ここまでのNetworkControlの内容


  改めて触れますが、ここまでの NetworkControl.cs の内容は以下の通りです。
using UnityEngine;
using System.Collections;
using MonobitEngine;

public class NetworkControl : MonobitEngine.MonoBehaviour {

	/** ルーム名. */
	private string roomName = "";

	/** プレイヤーキャラクタ. */
	private GameObject playerObject = null;

	// Use this for initialization
	void Start () {
		// デフォルトロビーへの自動入室を許可する
		MonobitNetwork.autoJoinLobby = true;

		// MUNサーバに接続する
		MonobitNetwork.ConnectServer("Bearpocalypse_v1.0");
	}

	// Update is called once per frame
	void Update()
	{
		// MUNサーバに接続しており、かつルームに入室している場合
		if (MonobitNetwork.isConnect && MonobitNetwork.inRoom)
		{
			// プレイヤーキャラクタが未登場の場合に登場させる
			if (playerObject == null)
			{
				playerObject = MonobitNetwork.Instantiate("Player", Vector3.zero, Quaternion.identity, 0);
			}
		}
	}

	// OnGUI is called for rendering and handling GUI events
	void OnGUI() {
		// デフォルトのボタンと被らないように、段下げを行なう。
		GUILayout.Space(24);

		// MUNサーバに接続している場合
		if (MonobitNetwork.isConnect)
		{
			// ボタン入力でサーバから切断&シーンリセット
			if (GUILayout.Button("Disconnect", GUILayout.Width(150)))
			{
				// サーバから切断する
				MonobitNetwork.DisconnectServer();

				// シーンをリロードする
				Application.LoadLevel(Application.loadedLevelName);
			}

			// ルームに入室している場合
			if (MonobitNetwork.inRoom)
			{
				// ボタン入力でルームから退室
				if (GUILayout.Button("Leave Room", GUILayout.Width(150)))
				{
					MonobitNetwork.LeaveRoom();
				}
			}

			// ルームに入室していない場合
			if (!MonobitNetwork.inRoom)
			{
				GUILayout.BeginHorizontal();

				// ルーム名の入力
				GUILayout.Label("RoomName : ");
				roomName = GUILayout.TextField(roomName, GUILayout.Width(200));

				// ボタン入力でルーム作成
				if (GUILayout.Button("Create Room", GUILayout.Width(150)))
				{
					MonobitNetwork.CreateRoom(roomName);
				}

				GUILayout.EndHorizontal();

				// 現在存在するルームからランダムに入室する
				if (GUILayout.Button("Join Random Room", GUILayout.Width(200)))
				{
					MonobitNetwork.JoinRandomRoom();
				}

				// ルーム一覧から選択式で入室する
				foreach (RoomData room in MonobitNetwork.GetRoomData())
				{
					if (GUILayout.Button("Enter Room : " + room.name + "(" + room.playerCount + "/" + ((room.maxPlayers == 0) ? "-" : room.maxPlayers.ToString()) + ")"))
					{
						MonobitNetwork.JoinRoom(room.name);
					}
				}
			}
		}
	}
}



単独で動作テストをする

プレイヤーキャラクタがきちんと動作するかどうかを確認する

  ここまで組み込んだところで、プレイヤーキャラクタがきちんと動作するか確認をしてみましょう。
  Unityエディタ上の実行ボタンを押してください。
  実行して少し待つとGUIが現れるのですが、白色の背景に溶け込んで、「Room Name : 」の文字が見えないようです。
  [Create Room] ボタンの左隣にあるのは、「ルーム名入力用のテキストボックス」ですので、
  まずはそこにルーム名を入力し、[Create Room] ボタンを押しましょう。
  ボタンを押すとプレイヤーが登場しますが、カメラが後ろに回り込みません。
  一応、カーソルキーで移動したりスライディングしたりするのは確認できるようです。
  Unityエディタのコンソールログを見ると、エラーが発生しているようです。
  これが原因で、動作がおかしくなっている可能性が高そうです。


エラーの原因を特定し、修正を加える

コンソールでエラーが表示されている箇所をダブルクリックする

  コンソールでエラーが発生している原因を特定しましょう。

  まず、Unityエディタ上でコンソールウィンドウに切り替えてください。
  通常は Project タブの隣に Console タブがあり、それをクリックすれば切り替えられます。
  見当たらない場合には Unity のメニューから Window > Console を選んで開いてください。
  コンソールウィンドウが表示されたら、その中にある
     「NullReferenceException : Object reference not set an instance of an object」
  と記述されている箇所をダブルクリックして、原因を特定します。
※ 環境によっては、下図のように
    「NpShape::setFlag(s):triangle mesh and heightfield triggers are not supported!」
  と表示されますが、こちらはどうしようもないので無視します。

エラーの原因を特定する

  ダブルクリックすると、エラーが出ているのが、ThirdPersonCamera.cs の 18 行目(下記の赤枠)であることが分かります。
  ここまでの状況を十分に把握していないとエラーの原因が分からないと思いますが、
  このエラーがなぜ発生しているかについて解説すると、以下のことが言えます。
プレイヤーキャラクタをプレハブ化した結果、ThirdPersonCamera.Start() メソッドの実行時(ゲームスタート時)に
プレイヤーキャラクタが存在せず、GameObject.FindWithTag("Player") の結果が null になってしまうから。
  よって、エラーを回避するためにプログラムを修正する必要が出ます。

エラーを修正する

  このエラーを修正するために、ThirdPersonCamera.cs に修正を加えます。
  まず、ThirdPersonCamera.cs の 18 行目をコメントアウトします。
		//follow = GameObject.FindWithTag ("Player").transform;	
  このままでは ThirdPersonCamera.cs の LateUpdate() メソッドでエラーが発生してしまいますので、
  ThirdPersonCamera.cs の LateUpdate() メソッドを、以下のように書き換えます。
	void LateUpdate ()
	{
		// follow に値が入っていない場合
		if ( follow == null )
		{
			// プレイヤーが存在したら、その transform を follow にセット
			GameObject gameObject = GameObject.FindWithTag("Player");
			if( gameObject != null )
			{
				follow = GameObject.FindWithTag("Player").transform;
			}
		}
		else
		{
			// setting the target position to be the correct offset from the 
			m_TargetPosition = follow.position + Vector3.up * distanceUp - follow.forward * distanceAway;

			// making a smooth transition between it's current position and the position it wants to be in
			transform.position = Vector3.Lerp(transform.position, m_TargetPosition, Time.deltaTime * smooth);

			// make sure the camera is looking the right way!
			transform.LookAt(follow);
		}
	}


ここまでのThirdPersonCameraの内容


  改めて触れますが、ここまでの ThirdPersonCamera.cs の内容は以下の通りです。
using UnityEngine;
using System.Collections;

/// <summary>
/// Third person camera.
/// </summary>
public class ThirdPersonCamera : MonoBehaviour
{
	public float distanceAway;			
	public float distanceUp;			
	public float smooth;				// how smooth the camera movement is
		
	private Vector3 m_TargetPosition;		// the position the camera is trying to be in)
	
	Transform follow;
	
	void Start(){
		//follow = GameObject.FindWithTag ("Player").transform;	
	}
	
	void LateUpdate ()
	{
		// follow に値が入っていない場合
		if ( follow == null )
		{
			// プレイヤーが存在したら、その transform を follow にセット
			GameObject gameObject = GameObject.FindWithTag("Player");
			if( gameObject != null )
			{
				follow = GameObject.FindWithTag("Player").transform;
			}
		}
		else
		{
			// setting the target position to be the correct offset from the 
			m_TargetPosition = follow.position + Vector3.up * distanceUp - follow.forward * distanceAway;

			// making a smooth transition between it's current position and the position it wants to be in
			transform.position = Vector3.Lerp(transform.position, m_TargetPosition, Time.deltaTime * smooth);

			// make sure the camera is looking the right way!
			transform.LookAt(follow);
		}
	}
}


起動時のカメラの位置も変更する

Projectビュー内の「Camera」の位置・姿勢を変更する

  ついでに、起動時のカメラビューのままでは、こちらが用意したGUIが良く見えないので、カメラ位置を調整してしまいましょう。
  Projectビューにある「Camera」を選択してください。
  シーンビュー内に Camera Preview が表示されますので、本来であれば、それを見ながら調整します。
  今回は面倒ですので、Inspector に、以下の値を直接入力してください。


再度、単独で動作テストをする

改めて、プレイヤーキャラクタがきちんと動作するかどうかを確認する

  改めて、プレイヤーキャラクタがきちんと動作するか確認をしてみましょう。
  Unityエディタ上の実行ボタンを押してください。
  実行して少し待つとGUIが現れます。さきほどよりも、少しは見やすくなりました。
  "RoomName : " の右隣にあるテキストボックスにルーム名を入力し、[Create Room] ボタンを押しましょう。
  ボタンを押すとプレイヤーが登場し、カメラが即座に後ろに回り込みます。
  カーソルキーで移動したりスライディングしたりしている間も、カメラが追随してくれます。
  NullReferenceException のエラー表示も消えています。問題ありませんね。