owned this note
owned this note
Published
Linked with GitHub
# Socket多人連線、接資料,與遊戲設計 - 同步移動邏輯梳理
整體同步過程:
進入遊戲時,給予「生成的角色」並且「攝影機追隨角色」。
開始遊戲時,針對「生成的角色」,給予他「移動、攻擊腳本」、「同步腳本」。
如下圖,在GameFacade內:
![](https://i.imgur.com/aupljqk.png)
在GameFacade內會呼叫PlayerManager去做上述所提的那些事情。
PlayerManager內有這兩個函式:
* **AddControlScript - 針對角色**
給予角色PlayerMove(移動腳本)、playerAttack(攻擊腳本)、區分是紅藍方玩家(根據角色種類給予角色資訊)、給予特定方玩家特定的箭。
這部分角色移動跟攻擊比較簡單,同步比較複雜。
* **CreateSyncRequest - 針對同步**
創造一個空遊戲物件,作為同步的橋樑。
添加MoveRequest(同步移動的請求)並設置本地端角色(設置位置跟移動腳本)。也要設置遠端的角色(設置位置)。
再來添加攻擊請求(負責叫後端扣受攻擊玩家的血)跟射擊請求(負責箭)。
```C#
public void AddControlScript() //針對動畫控制器的函式
{
currentRoleGameObject.AddComponent<PlayerMove>();//目前的遊戲物件要增加PlayerMove腳本(讓物件動起來)
PlayerAttack playerAttack = currentRoleGameObject.AddComponent<PlayerAttack>();
RoleType rt = currentRoleGameObject.GetComponent<PlayerInfo>().roleType;
RoleData rd = GetRoleData(rt);
playerAttack.arrowPrefab = rd.ArrowPrefab;
playerAttack.SetPlayerMng(this);
}
public void CreateSyncRequest() //創造同步 //把這個當成雙方同步的橋樑
{
playerSyncRequest=new GameObject("PlayerSyncRequest");//創造一個GameObject
playerSyncRequest.AddComponent<MoveRequest>().SetLocalPlayer(currentRoleGameObject.transform, currentRoleGameObject.GetComponent<PlayerMove>())
.SetRemotePlayer(remoteRoleGameObject.transform);
//給這個GameObje這個添加MoveRequest(同步移動的請求)並設置本地端角色(設置位置跟移動腳本)
//也要設置遠端的角色(設置位置)
//再來添加攻擊請求(負責叫後端扣受攻擊玩家的血)跟射擊請求(負責箭)
shootRequest=playerSyncRequest.AddComponent<ShootRequest>();
shootRequest.playerMng = this;
attackRequest = playerSyncRequest.AddComponent<AttackRequest>();
}
```
---
## 同步邏輯梳理
同步比較複雜,所以會特別梳理一下同步的邏輯如何建立:
1. 腳本一開始執行,就要狂**傳送本地端角色位置給後端**。
傳Request後,接收Response。就開始同步。
```C#
private void Start()//遊戲一開始,對遊戲角色掛載此腳本後,就狂傳本地端位置資訊給後端
{
InvokeRepeating("SyncLocalPlayer", 1f, 1f / syncRate);//重複調用SyncLocalPlayer函式
//此函式是傳本地端角色的位置跟旋轉角度給後端
}
//下面這個函式會馬上一直被重複調用
private void SyncLocalPlayer()//此函式是傳本地端角色的位置跟旋轉角度給後端
{
SendRequest(localPlayerTransform.position.x, localPlayerTransform.position.y, localPlayerTransform.position.z,
localPlayerTransform.eulerAngles.x, localPlayerTransform.eulerAngles.y, localPlayerTransform.eulerAngles.z,
localPlayerMove.forward);
}
//上方的函式又會執行這個函式
//傳位置跟旋轉角度給後端 //傳Request
private void SendRequest(float x,float y,float z,float rotationX,float rotationY,float rotationZ,float forward)
{
string data = string.Format("{0},{1},{2}|{3},{4},{5}|{6}", x, y, z, rotationX, rotationY, rotationZ, forward);
base.SendRequest(data);
}
//傳Request後,接收Response
public override void OnResponse(string data) //從後端接收後回應
{//27.75,0,1.41-0,0,0-0
//print(data);
string[] strs = data.Split('|');
pos = UnityTools.ParseVector3(strs[0]);//要接收位置,利用UnityTools轉成Vector3
rotation = UnityTools.ParseVector3(strs[1]);//要接收旋轉角度,轉成Vector3
forward = float.Parse(strs[2]);
isSyncRemotePlayer = true; //開始同步
}
```
2. 一開始也要先,**建立本地端跟遠端腳色的位置跟角度**
在PlayerManager腳本內的CreateSyncRequest()函式內就會叫MoveRequest去建立好這兩個角色的初始位置、角度。
```C#
public MoveRequest SetLocalPlayer(Transform localPlayerTransform, PlayerMove localPlayerMove)
{
this.localPlayerTransform = localPlayerTransform;
this.localPlayerMove = localPlayerMove;
return this;
}
public MoveRequest SetRemotePlayer(Transform remotePlayerTransform)
{
this.remotePlayerTransform = remotePlayerTransform;
this.remotePlayerAnim = remotePlayerTransform.GetComponent<Animator>();
return this;
}
```
3. 偵測到開始同步後,```isSyncRemotePlayer = true; ```,開始同步遠端角色位置、角度。
```C#
private void FixedUpdate()
{
if (isSyncRemotePlayer) //isSyncRemotePlayer會在後端傳回資訊時,轉為true
{
SyncRemotePlayer();//也同步遠端角色
isSyncRemotePlayer = false;
}
}
private void SyncRemotePlayer()
{
remotePlayerTransform.position = pos;
remotePlayerTransform.eulerAngles = rotation;
remotePlayerAnim.SetFloat("Forward", forward);
}
```