6-25 Synchronizing Player Position To Server
前幾章稍微離題了,都在講效能優化的內容。本章開始要回到網路相關的內容啦,如果有人看到這篇文章卻不懂範例中使用的架構的話,請先將第6章的文章再複習一遍唷!
6-5 Sending Request And Response
上述是Unity的Client實作過程,接著我們進行PhotonServer端的開發。
新增一個SyncOtherPlayerHandler,繼承我們自定義的BaseHandler物件,並覆寫OnOperationRequest方法。
OnOperationRequest的實作如下,透過Parameters取得座標x, y, z的資料,然後使用logger顯示出來。

最後,記得要在NoliahFantasyServer.cs中添加Handler到handlerDict中。
從PhotonServer的Log檔中可見確實收到新的x, y, z資料。
6-5 Sending Request And Response
6-7 Sending Request And Response And Event With Parameters
6-14 Using Dictionary To Manage All Request
6-15 Using Handler To Respond Requisition In Photon Server
6-16 Finishing Sign Up Mechanism
接著繼續實作位置同步的功能,首先,我們先說明本次功能需要添加的OperationCode與ParameterCode。如下圖,OperationCode新增SyncPosition。
ParameterCode新增x, y, z。
接著,新增一個Script,名為SyncPositionRequest,繼承我們自定義的Request。覆寫抽象方法OnDefaultRequest後,建立Dictionary物件來儲存position資料,最後使用PhotonEngine的OpCustom方法傳送Request給Server。
Request物件建立好以後,我們還需要一個物件來管理所有『同步位置』的相關功能。所以,請大家再新增一個Script,名為SyncPosition。於SyncPosition中使用GetComponent取得SyncPositionRequest,然後紀錄Player的初始位置。接著用StartCoroutine呼叫同步功能。
此處使用StartCoroutine是為了實行每秒定時更新位置資訊,如下圖,每隔0.2秒同步一次,使用Vector3.Distance判斷玩家是否有移動,有移動再呼叫SyncPositionRequest的OnDefaultRequest方法。
回到場景中,建立SyncPotision物件。
在GameObject內加入SyncPosition與SyncPositionRequest兩個腳本,接著需要從Inspector中選擇Operation Code,此處選擇Sync Position。
上述是Unity的Client實作過程,接著我們進行PhotonServer端的開發。
新增一個SyncOtherPlayerHandler,繼承我們自定義的BaseHandler物件,並覆寫OnOperationRequest方法。
OnOperationRequest的實作如下,透過Parameters取得座標x, y, z的資料,然後使用logger顯示出來。

最後,記得要在NoliahFantasyServer.cs中添加Handler到handlerDict中。

以下提供本次修改的完整程式碼:
以下提供Client端原始碼:
ParameterCode.cs:
public enum ParameterCode : byte
{
Acccount,
Password,
x,
y,
z
}
OperationCode.cs:
public enum OperationCode : byte
{
Login,
Signup,
SyncPosition
}
SyncPosition.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Character;
using RPG.Core;
public class SyncPosition : MonoBehaviour {
GameObject player;
SyncPositionRequest syncPosiRequest;
Vector3 lastPosition;
void Start () {
syncPosiRequest = GetComponent();
player = Game.Instance.playerMovement.gameObject;
// 初始化Player位置
lastPosition = player.transform.position;
// 每段時間同步玩家位置
StartCoroutine (UploadPosition ());
}
IEnumerator UploadPosition(){
while (true) {
// 每秒同步五次
yield return new WaitForSeconds (0.2f);
// 判斷是否有移動,若Player沒有在移動便不需要同步
Vector3 nowPosition = player.transform.position;
if(Vector3.Distance(nowPosition, lastPosition) > 0.1f){
lastPosition = nowPosition;
syncPosiRequest.position = nowPosition;
// 發送位置更新訊息
syncPosiRequest.OnDefaultRequest ();
}
}
}
}
SyncPositionRequest.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using ExitGames.Client.Photon;
public class SyncPositionRequest : Request {
[HideInInspector] public Vector3 position;
public override void OnDefaultRequest ()
{
Dictionary data = new Dictionary ();
data.Add((byte)ParameterCode.x, position.x);
data.Add((byte)ParameterCode.y, position.y);
data.Add((byte)ParameterCode.z, position.z);
// 向Server發出Request,true代表建立可靠連接
PhotonEngine.Instance.GetPeer().OpCustom((byte)operationCode, data, true);
}
public override void OnOperationResponse (OperationResponse operationResponse)
{
}
}
以下提供Server端原始碼:
NoliahFantasyServer.cs:
using System.IO;
using System.Collections.Generic;
using Photon.SocketServer;
using ExitGames.Logging;
using log4net.Config;
using NoliahFantasyServer.Constant;
using NoliahFantasyServer.Handler;
namespace NoliahFantasyServer
{
public class NoliahFantasyServer : ApplicationBase
{
public static readonly ILogger logger = LogManager.GetCurrentClassLogger();
public static Dictionary handlerDict =
new Dictionary();
// 透過PeerList,可向任何一個客戶端發送數據
public static List peerList = new List();
// 當Client端發出Request的時候
protected override PeerBase CreatePeer(InitRequest initRequest)
{
MyClientPeer peer = new MyClientPeer(initRequest);
peerList.Add(peer);
return peer;
}
// Server端啟動的時候初始化
protected override void Setup()
{
InitLogger();
InitHandler();
}
// Server端關閉的時候
protected override void TearDown()
{
}
void InitLogger()
{
// 日誌初始化
log4net.GlobalContext.Properties["Photon:ApplicationLogPath"] =
Path.Combine(this.ApplicationRootPath, "bin_Win64", "log");
FileInfo loggerConfig = new FileInfo(Path.Combine(this.BinaryPath, "log4net.config"));
if (loggerConfig.Exists)
{
// 設置使用log4net的Log功能
LogManager.SetLoggerFactory(ExitGames.Logging.Log4Net.Log4NetLoggerFactory.Instance);
// 讓log4net讀取config
XmlConfigurator.ConfigureAndWatch(loggerConfig);
}
logger.Info("Setup Log4Net Compeleted!");
}
void InitHandler(){
LoginHandler loginHandler = new LoginHandler();
handlerDict.Add(loginHandler.operationCode, loginHandler);
SignupHandler signupHandler = new SignupHandler();
handlerDict.Add(signupHandler.operationCode, signupHandler);
SyncPositionHandler syncPositionHandler = new SyncPositionHandler();
handlerDict.Add(syncPositionHandler.operationCode, syncPositionHandler);
SyncOtherPlayerHandler syncOtherPlayerHandler = new SyncOtherPlayerHandler();
handlerDict.Add(syncOtherPlayerHandler.operationCode, syncOtherPlayerHandler);
}
}
}
SyncPositionHandler.cs:
using System;
using System.Collections.Generic;
using Photon.SocketServer;
using NoliahFantasyServer.Constant;
namespace NoliahFantasyServer.Handler
{
public class SyncPositionHandler : BaseHandler
{
public SyncPositionHandler()
{
operationCode = OperationCode.SyncPosition;
}
public override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters, MyClientPeer myClientPeer)
{
object xPosition;
operationRequest.Parameters.TryGetValue((byte)ParameterCode.x, out xPosition);
object yPosition;
operationRequest.Parameters.TryGetValue((byte)ParameterCode.y, out yPosition);
object zPosition;
operationRequest.Parameters.TryGetValue((byte)ParameterCode.z, out zPosition);
NoliahFantasyServer.logger.Info("Client端Position資料X:" + xPosition);
NoliahFantasyServer.logger.Info("Client端Position資料Y:" + yPosition);
NoliahFantasyServer.logger.Info("Client端Position資料Z:" + zPosition);
myClientPeer.xPosition = (float)xPosition;
myClientPeer.yPosition = (float)yPosition;
myClientPeer.zPosition = (float)zPosition;
}
}
}
執行遊戲看看吧,移動一下玩家的位置。
接著下一章繼續實作同步其他登入玩家的Position資料。










留言
張貼留言