> For the complete documentation index, see [llms.txt](https://docs.proudnet.com/proudnet.cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.proudnet.com/proudnet.cn/proudnet-note/notes/character_sync.md).

# 同步角色位置

參與多人遊戲的所有遊戲主機在遊戲中所有角色的位置都要看起來相同,爲此需要角色位置同步化。

通常互聯網會產生從一個主機向另一個主機發送消息所需的時間（延遲）。 由於延遲和通信量的限制，發送角色的位置的次數和速度存在侷限性。 因此,作爲同步移動角色位置的代表性方法,使用[**推測導航 (dead reckoning)**](/proudnet.cn/proudnet-note/dictionary.md#dead-reckoning)。

在一個遊戲世界中少數用戶喜歡玩遊戲的休閒遊戲中,將各用戶操縱的角色信息發送到其他主機時,將遊戲世界的所有用戶捆綁爲一個P2P組,他們之間進行P2P間的多對多通信即可。

但是,在遊戲世界裏,多數用戶喜歡玩遊戲時,如果像上述方式一樣對所有用戶的信息進行多點通信,通信量就會呈幾何級數增長。 因此，不是以上述方式，而是應該將進入各用戶視野的角色限制爲同步範圍。

## 少數主機之間的遊戲玩法同步

很多休閒遊戲，一個遊戲世界融合了少數（一般不超過15個）的遊戲客戶端，讓玩家享受遊戲樂趣。 在這種情況下,即使客戶端之間通過P2P將各自的角色信息相互進行[**multicast**](/proudnet.cn/proudnet-note/dictionary.md#undefined-1),也不會引起通信量上的大問題,可以順利地享受遊戲。

#### 主要程序摘要

> * **進入遊戲世界 :** \
>   伺服器將使用者加入P2P群組。 <mark style="color:orange;">CreateP2PGroup</mark>或<mark style="color:orange;">JoinP2PGroup</mark><br>
> * **退出遊戲世界：**\
>   呼叫 <mark style="color:orange;">LeaveP2PGroup</mark> 將離開的使用者從 P2P 群組中刪除，或離開 <mark style="color:orange;">Proud.INetServerEvent.OnClientLeave</mark> 在使用者與伺服器斷開連線時自動將使用者從 P2P 群組中刪除。<br>
> * **同步每個使用者的位置：**\
>   每個使用者透過RMI將自己的角色資訊傳送到上面的P2P群組。

<table data-full-width="true"><thead><tr><th width="330">C++ 11 函數</th><th width="366">C# 函數</th><th>註釋</th></tr></thead><tbody><tr><td>Proud.CNetServer.CreateP2PGroup</td><td>Nettention.Proud.NetServer.CreateP2PGroup</td><td>創建 P2P 組。</td></tr><tr><td>Proud.CNetServer.JoinP2PGroup</td><td>Nettention.Proud.NetServer.JoinP2PGroup</td><td>將peer添加到已經存在的P2P組中。</td></tr><tr><td>Proud.CNetServer.LeaveP2PGroup</td><td>Nettention.Proud.NetServer.LeaveP2PGroup</td><td>讓P2P組合的成員退場。</td></tr><tr><td>Proud.CNetServer.OnClientLeave</td><td>Nettention.Proud.NetServer.ClientLeaveHandler</td><td>客戶端關閉連接時發生的事件。</td></tr></tbody></table>

## 多個主機之間的遊戲玩法同步

在大型多人在線遊戲或大型戰地遊戲（MMO）中，許多遊戲客戶端在一個遊戲世界（如一個大型區域）中融合在一起享受遊戲樂趣。

在這種環境下,如果將各角色信息發送到其他所有客戶端P2P,通信量就會出現幾何級數增加的問題。 因此，在大規模戰遊戲中，將角色的位置發送給客戶端，但最好只將角色發送給視線的客戶端。

在下圖中操縱角色的客戶端B向服務器發送角色的狀態（位置等）。 那麼服務器會發送角色的位置，但只把士兵發送給視野中的客戶端A、C。 客戶端D沒有將士兵放在視野中，因此不會發送角色的位置，從而節省通信量。

這被稱爲<mark style="color:orange;">可見區域過濾</mark>。

<figure><img src="/files/EX1vLVqVgwauVKbbYWk4" alt=""><figcaption><p>大規模遊戲中的可見區域過濾( 服務器經由方式)</p></figcaption></figure>

現將<mark style="color:orange;">可見區域過濾</mark>整理如下。

> * 從客戶端向服務器發送自己的角色狀態。
> * 服務器接收並保留每個角色狀態。 然後選擇其他可以查看角色的客戶端，只向他們發送角色信息。

以上<mark style="color:orange;">可見區域過濾</mark>是通過服務器進行通信的傳統方式,所有多播都由服務器負責,因此存在超負荷的缺點。

ProudNet透過極快、高效能的P2P分組和P2P通訊技術解決了這個問題，這種技術稱為<mark style="color:orange;">混合階段組網技術(註冊專利第10-0812019號)</mark>。

該技術是將角色位置不通過服務器進行多播,而是直接通過P2P傳送給其他客戶端,將多播範圍限制在可視領域的方法,僅限於使用ProudNet的項目。

<figure><img src="/files/0cPq7nQjfaHj4OEUJDEs" alt=""><figcaption><p>大規模戰爭遊戲中的可見區域過濾（混合階段網路方法）</p></figcaption></figure>

## 應用ProudNet和混合相位網路的同步方法

> 1. 伺服器必須有空間來儲存每個客戶端控制的角色的位置。<br>
> 2. 客戶端設置自己的角色和其他客戶端的同步角色，服務器設置<mark style="color:orange;">Proud.HostID</mark>變量，該變量將每個角色<mark style="color:orange;">可查看角色的客戶端</mark>組合成P2P組。<br>
> 3. 客戶端將自身角色定位每隔一段時間發送給服務器，\
>    服務器接收並保存它。<br>
> 4. 服務器每隔一段時間檢查客戶端操縱的角色是否在其他客戶端的可見區域。 此時,服務器每次確認角色進入或脫離可視領域時,都要將該角色的出現或消失信息以RMI發送給該客戶端,並將該角色添加到<mark style="color:orange;">可查看角色的客戶端</mark>或刪除。<br>
> 5. 當角色確定客戶端進入可見區域時，將出現 RMI 發送給相應的客戶端，並將其添加到<mark style="color:orange;">可查看角色的客戶端</mark>中。<br>
> 6. 當角色確定客戶端脫離可見區域時，會向相應客戶端發送消失的RMI，並從<mark style="color:orange;">可查看角色的客戶端</mark>中刪除。<br>
> 7. 當客戶端第一次進入遊戲世界時，它必須獲得一個P2P組ID，該ID指向<mark style="color:orange;">可查看角色的客戶端</mark>。\
>    基於此值，客戶端每隔一段時間將自身角色的位置傳輸到P2P時，需要一種[**推測導航 (dead reckoning)**](/proudnet.cn/proudnet-note/dictionary.md#dead-reckoning)技術。<br>
> 8. 客戶端的自身角色出現在遊戲世界的情況與<mark style="color:orange;">角色進入客戶端可視區域</mark>的情況相同。\
>    相反，客戶端的自身角色從遊戲世界中刪除時，<mark style="color:orange;">角色與客戶端可視區域脫離</mark>的情況相同。

{% hint style="info" %}
在混合相位網絡方式下，客戶端的發送量可能會過大，導致客戶端的發送量過大。

爲了防止這種情況發生,請參考[**發送量自動調節功能 (Throttling)**](/proudnet.cn/proudnet/using_pn/tong-xun-xun-xi.md#throttling)及[**P2P 通信**](/proudnet.cn/proudnet/using_pn/p2p.md)。
{% endhint %}
