Unity(C#)初心者・入門者向けチュートリアル ひよこのたまご

AndroidやiOS向けアプリを簡単に作れるゲーム開発環境Unity(ユニティ)の使い方を、チュートリアル方式で一緒に学びましょう!

【Unity9】UNETのネットワークトラフィックを軽減し、効率化する【UNET3】

Unity5.1.1p3 Personal(2015年7月)


前回の続きです〜


相手プレイヤーの位置と傾きを同期し、なめらかに表示させるところまできました〜
今回は少しだけ効率化をしていくそうです〜



UNET Part 3 - Being a bit more efficient - YouTube

【目標】UNETを効率化する

①デバッグログをとってみる

まずはDebug.Logを記述して、スクリプト中の非効率的な部分を確認してみましょう〜


Player_SyncPositionスクリプトの、CmdProvidePositionToServerメソッド内のログを取得します〜

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class Player_SyncPosition : NetworkBehaviour {
	
	[SyncVar]
	private Vector3 syncPos;
	[SerializeField] Transform myTransform;
	[SerializeField] float lerpRate = 15;

	void FixedUpdate ()
	{
		TransmitPosition(); 
		LerpPosition();
	}
	
	void LerpPosition ()
	{
		if (!isLocalPlayer) {
			myTransform.position = Vector3.Lerp(myTransform.position, syncPos, Time.deltaTime * lerpRate);
		}
	}

	[Command]
	void CmdProvidePositionToServer (Vector3 pos)
	{
		syncPos = pos;
//********** 開始 **********//
		//自分がホストの時は毎フレーム呼ばれる
		//クライアント数だけ倍増していく
		//自分がクライアントの時は全く呼ばれない
		Debug.Log("Command");
//********** 終了 **********//
	}
	
	[ClientCallback]
	void TransmitPosition ()
	{
		if (isLocalPlayer) {
			CmdProvidePositionToServer(myTransform.position);
			lastPos = myTransform.position;
		}	
	}
}

Player_SyncPosition.cs


この状態でホストとしてログインすると、毎フレームログが取得され、またクライアントがログインすると2倍のログが取得されます〜


f:id:hiyotama:20150707132443p:plain
アッという間に1000以上のログ取得

②スクリプトの効率化(Player_SyncPosition)

この状態だとネットワーク・トラフィックが大きくなり、ネットワークの交通渋滞が起こる可能性が高いため、Playerが動いた時のみCmdProvidePositionToServerメソッドを呼ぶようにしていきます〜以下修正ソースです〜

using UnityEngine;
using System.Collections;
using UnityEngine.Networking;

public class Player_SyncPosition : NetworkBehaviour {
	
	[SyncVar]
	private Vector3 syncPos;
	[SerializeField] Transform myTransform;
	[SerializeField] float lerpRate = 15;

//********** 開始 **********//
	//前フレームの最終位置
	private Vector3 lastPos;
	//threshold: しきい値、境目となる値のこと
	//0.5unitを超えなければ移動していないこととする
	private float threshold = 0.5f;
//********** 終了 **********//

	void FixedUpdate ()
	{
		TransmitPosition(); 
		LerpPosition();
	}
	
	void LerpPosition ()
	{
		if (!isLocalPlayer) {
			myTransform.position = Vector3.Lerp(myTransform.position, syncPos, Time.deltaTime * lerpRate);
		}
	}

	[Command]
	void CmdProvidePositionToServer (Vector3 pos)
	{
		syncPos = pos;
//********** 開始 **********//
		Debug.Log("Command");
//********** 終了 **********//
	}
	
	[ClientCallback]
	void TransmitPosition ()
	{
//********** 開始 **********//
		//自プレイヤー且つ、現在位置と前フレームの最終位置との距離がthresholdより大きい時
		if (isLocalPlayer && Vector3.Distance(myTransform.position, lastPos) > threshold) {
//********** 終了 **********//
			CmdProvidePositionToServer(myTransform.position);
//********** 開始 **********//
			//現在位置を最終位置として保存
			lastPos = myTransform.position;
//********** 終了 **********//
		}
	}
}

Player_SyncPosition.cs


しきい値を設定し、前フレームの最終位置と現在位置との距離がしきい値を超えていた時にのみ、CmdProvidePositionToServerメソッドを呼び出すようにしました〜


これにより、ネットワークの交通渋滞が起きにくくなりました〜


f:id:hiyotama:20150707133425p:plain
Playerが動いた時のみメソッドが呼ばれる

②スクリプトの効率化(Player_SyncRotation)

同様の処理をPlayer_SyncRotationスクリプトにも追加し、ネットワーク・トラフィックを軽減していきましょう〜以下ソースです〜

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class Player_SyncRotation : NetworkBehaviour {

	[SyncVar] private Quaternion syncPlayerRotation;
	[SyncVar] private Quaternion syncCamRotation;
	
	[SerializeField] private Transform playerTransform;
	[SerializeField] private Transform camTransform;
	[SerializeField] private float lerpRate = 15;
	
//********** 開始 **********//
	//前フレームの最終角度
	private Quaternion lastPlayerRot;
	private Quaternion lastCamRot;
	//しきい値は5。5度以上動いた時のみメソッドを実行
	private float threshold = 5;
//********** 終了 **********//
	
	void Start () {
	
	}
	
	void FixedUpdate () {
		TransmitRotations();
		LerpRotations();
	}
	
	void LerpRotations ()
	{
		if (!isLocalPlayer){
			playerTransform.rotation = Quaternion.Lerp (playerTransform.rotation,
				syncPlayerRotation, Time.deltaTime * lerpRate);
			camTransform.rotation = Quaternion.Lerp (camTransform.rotation,
				syncCamRotation, Time.deltaTime * lerpRate);
		}
	}
	
	[Command]
	void CmdProvideRotationsToServer (Quaternion playerRot, Quaternion camRot)
	{
		syncPlayerRotation = playerRot;
		syncCamRotation = camRot;
//********** 開始 **********//
		Debug.Log("Command for angle");
//********** 終了 **********//
	}
	
	[Client]
	void TransmitRotations ()
	{
		if (isLocalPlayer) {
//********** 開始 **********//
			if (Quaternion.Angle (playerTransform.rotation, lastPlayerRot) > threshold ||
			   Quaternion.Angle (camTransform.rotation, lastCamRot) > threshold) {
//********** 終了 **********//
				CmdProvideRotationsToServer (playerTransform.rotation, camTransform.rotation);
//********** 開始 **********//
				lastPlayerRot = playerTransform.rotation;
				lastCamRot = camTransform.rotation;
			}
//********** 終了 **********//
		}
	}	
}

Player_SyncRotation.cs


Positionの時と同様に、しきい値を設定し、前フレームの角度と現在角度との差分がしきい値を超えていた時にのみ、CmdProvideRotationsToServerメソッドを実行しています〜


メソッドを呼び出したあとは、現在角度を最終角度として保存します〜


それでは確認してみましょう〜
確認前に、Player_SyncPositionスクリプトのほうのデバッグはコメントアウトしておいたほうが分かりやすいです〜


f:id:hiyotama:20150707140151p:plain
マウスを動かして角度が変わった時のみメソッド呼び出し


もちろんクライアントの角度が変わった時にもログは呼び出されます〜


確認が終了したら、Debug.Logはコメントアウトして、今回は終わりにしましょう〜

ありがとうございました〜


【Unity9】UNETでマルチプレイヤーなオンラインゲーム開発【UNET1】
【Unity9】UNETでプレイヤーの動きを補間し、なめらかな動きを実現する【UNET1-2】
【Unity9】UNETでネットワーク越しに傾き(Rotation)を同期させる【UNET2】
【Unity9】UNETでオンライン開始時のプレイヤー生成位置を変更する【UNET2-2】
【Unity9】UNETのネットワークトラフィックを軽減し、効率化する【UNET3】
【Unity9】UNETのlatency(遅延時間)を改善する【UNET4】
【Unity9】UNETのlatency(遅延時間)を表示して、ちょっとだけ改善する【UNET4-2】
【Unity9】UNETのSyncVarのhookの使用例と、前時代の同期方法【UNET5】
【Unity9】UNETを使ってRotationを同期させる【UNET6】
【Unity9】UNETで各プレイヤーにPlayerIDを設定する【UNET7】
【Unity9】UNETで敵プレイヤーにダメージを与える!【UNET8】
【Unity9】UNETでHPを画面に表示し、Playerへダメージを与える【UNET9】
【Unity9】UNETでHPが0以下になった時、Playerを破壊する!【UNET10】
【Unity9】UNETで死んだPlayerを生き返らせる!【UNET11】
【Unity9】UNETでゾンビAIを出現させる!【UNET12】
【Unity9】UNETでゾンビ生成時にユニークなIDを付ける!【UNET13】
【Unity9】UNETでゾンビを撃つ!【UNET14】
【Unity9】UNETでゾンビに攻撃させる!【UNET15】
【Unity9】UNETでゾンビの動きをスムーズにシンクロさせる!【UNET16】
【Unity9】UNETでゾンビ発生地点を増やす【UNET17】
【Unity9】UNETで発生したバグを取り除く【UNET18】
【Unity9】Unity MultiPlayerを使ってネットワーク越しにマッチメイキング!【UNET19】
【Unity9】GUIを改善して、Network Managerを見やすくする!【UNET20】
【Unity9】表示したGUI(Network Manager)を機能させる!【UNET20-2】
【Unity9】UNETでAnimationを同期させる!【UNET21】