第一部分主要是基本物件的多人連線,先上影片
由於以前唯一寫過網路方面的東西是文字聊天室和簡單的網頁前後端,對於遊戲這方面的網路連線完全沒有概念,又不想抄別人的東西,因此以下是我煩Discord裡的其他有經驗的人+自己邊寫邊改後產生的想法,有什麼建議歡迎討論~
由於這只是篇心得文,不是教學文(我目前也沒這能力寫這方面的教學文),因此我只寫我的想法,不會放太多程式碼。
最一開始的規劃是,遊戲機制客戶端個別運算,再透過伺服器互相溝通,但仔細想想,若每個客戶端算出來的結果不一樣,那該以誰為準?
於是就改成遊戲機制全部交由伺服器處理,玩家在客戶端做什麼更動再傳給伺服器,最後分發到其他客戶端。
接下來說說我的遊戲物件好了,內容大致長這樣
public abstract class GameObject extends Entity
{
protected int entityID;
protected int omID;
protected Vector3f directionVector;
protected float velocity;
}
GameObject主要是存放在負責遊戲機制的地方,而它繼承自另一個物件Entity
public abstract class Entity
{
protected int modelID;
protected Vector3f position, rotation, scale;
protected float transparency;
}
Entity這個東西主要是放在渲染器那邊,也就是說同一個物件,分別以不同的身分(class),放在不同的地方。
其實這也是這次重做引擎主要的主要目的之一,之前舊引擎是同一個遊戲世界裡的物體,分成多個Object,只有裡面的幾個參數是存reference,而現在則是改成一個物體只有一個Object,多個reference放在多個地方。
這樣做的好處是,無論是從遊戲機制或渲染器那邊,都可以直接存取到物件的所有內容,對物件更新也會及時反映在另一邊。
在多人連線中對遊戲物件的操作,我主要分成三個部分,建立、更新和刪除
建立
假設客戶端中的某個遊戲機制要求建立GameObject,那勢必要經歷以下步驟:
遊戲機制建立GameObject > 傳給伺服器 > 伺服器分發給所有客戶端 > 放進遊戲機制裡 > 放進渲染器裡
但是,在GameObject裡有個東西叫做omID,它是這個遊戲物件在遊戲機制裡的識別ID,但這東西牽扯到網路傳輸就會有一個大問題...
假設兩個客戶端A和B,它們同時建立了一個GameObject,並發配給他一個omID,這時A檢查自己遊戲機制的GameObject列表,發現"1"這個ID還沒被用過,於是便將這ID發配給這個新建的GameObject,而在B這邊也同樣如此,並同時向伺服器發出請求。
這時伺服器將收到兩個ID為"1"的建立請求,當然,伺服器可以比較誰的訊息更早收到,然後重新分配一個omID給比較慢到GameObject,最後叫比較慢的客戶端改它那邊的omID,但這時又會有新的問題...
要求客戶端改它的omID其實對於客戶端而言完全沒有影響,因為依照上面的步驟,客戶端是在收到伺服器回應後,才會真正地建立新的GameObject,而原先要求建立GameObject的遊戲機制手中只有omID,下一次這個遊戲機制要從GameObject列表中找那個GameObject時就會對不上。
因此,此時應該將步驟改成:遊戲機制建立GameObject > 放進遊戲機制裡 > 放進渲染器裡 > 傳給伺服器 > 伺服器分發給其他客戶端
不管伺服器那邊如何,客戶端先建立再說。這時要求建立GameObject的遊戲機制手上拿著整個GameObject物件,即使伺服端那邊因為omID衝突,要改客戶端這邊的ID也可以直接改。
更新
這部分因為omID在建立時就已經溝通好了,不管要改什麼都是直接用omID來找人,原以為沒什麼太大的問題,直到我要GameObject持續移動時,伺服器直接爆炸...
最前面有提到,遊戲機制是由伺服器處理,玩家有做什麼改動再跟伺服器講,伺服器更新的頻率是每秒60次,而每次更新都要把每一個有變動的GameObject傳給每個客戶端,這種負荷導致只要GameObject累積到一定數量,伺服器就很容易吃不消。
我目前的解決辦法是,把所有更新分成兩種,分別是是每次更新都會使GameObject產生變動的常態更新,和只有玩家操作或某些特定事件發生時才會改變的主動更新。
常態更新在GameObject建立後便交由每個客戶端自己跑自己的,伺服端也會跑自己的結果,每隔一段時間再把伺服器的資料發送到客戶端做校正。
而主動更新因為頻率不高,因此維持原本的模式沒出什麼問題。
刪除
這部分其實就和主動更新的做法一樣,客戶端傳要求給伺服器,伺服器再分發給各個客戶端。
原本中秋節連假就要發這篇的,只是中途發現一些Bug,修一修就拖到現在了 。第一部分大概是這樣,有想到別的再補。