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 () { Dictionarydata = 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 DictionaryhandlerDict = 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資料。
留言
張貼留言