Unity3D實(shí)現(xiàn)幀同步技術(shù)

在競技類網(wǎng)絡(luò)游戲比較火刹枉,市面上也出現(xiàn)了很多這種類型的游戲競賽,提到網(wǎng)絡(luò)游戲就回避不了一個問題:同步技術(shù)岩饼,多個人在一個游戲場景圍攻一個怪物或者說多人組隊(duì)?wèi)?zhàn)斗等等氓辣。

狀態(tài)同步

現(xiàn)在在移動端的游戲由于帶寬的限制,一般采用實(shí)時(shí)同步的方式是狀態(tài)同步账蓉,也就是說角色的狀態(tài)發(fā)生改變枚碗,才會去發(fā)送消息。舉個例子:

3D角色一般的動作狀態(tài)有:Idle铸本,walk肮雨,run,attack等箱玷,玩家操作鍵盤或者觸摸屏按鈕怨规,會觸發(fā)這些動作,一個游戲場景中會有多個角色锡足,每個角色都有自己的動作狀態(tài)波丰,為了讓玩家能夠看到其他玩家在做什么,需要同步舶得,玩家默認(rèn)狀態(tài)是idle掰烟,玩家剛出現(xiàn)時(shí)是idle狀態(tài),這個時(shí)候,客戶端會把玩家的狀態(tài)纫骑,位置蝎亚,方向傳送給服務(wù)器,其他玩家也是一樣的先馆,服務(wù)器接收到信息后颖对,會把這些信息發(fā)送給除了它本人之外的其它玩家,這樣我們就可以看到其他玩家的狀態(tài)了磨隘。如果玩家從idle狀態(tài)轉(zhuǎn)化到walk狀態(tài)缤底,這表明玩家的動作狀態(tài)發(fā)生了變化,這也需要將信息發(fā)給服務(wù)器番捂,服務(wù)器進(jìn)行群發(fā)給其他玩家个唧,這樣其他玩家就可以看到角色開始walk了。接下來如果玩家繼續(xù)走设预,客戶端就不發(fā)送消息給服務(wù)器了徙歼,因?yàn)闋顟B(tài)沒發(fā)生變化,等狀態(tài)再變化時(shí)才會發(fā)送消息給服務(wù)器鳖枕,然后服務(wù)器再群發(fā)消息魄梯,在此過程中,其他客戶端會通過插值的方式把兩個狀態(tài)之間的距離實(shí)現(xiàn)出來宾符,以此類推酿秸。。魏烫。辣苏。。哄褒。這就是所說的狀態(tài)同步模式稀蟋。

幀同步模式

幀同步含義游戲客戶端接受來自網(wǎng)絡(luò)的多個客戶端的操作,如果這些操作在各個客戶端是一樣的呐赡,那么多個客戶端的顯示也就一樣了退客,這就帶來了“同步”的效果。所以在這種情況下链嘀,各個客戶端的運(yùn)算要絕對一致萌狂,不能依賴諸如本地時(shí)間、本地隨機(jī)數(shù)等等“輸入”管闷,而要一切以網(wǎng)絡(luò)來的操作數(shù)據(jù)為主粥脚。

一般來說,大多數(shù)的游戲客戶端引擎包个,都會定時(shí)調(diào)用一個接口函數(shù)刷允,這個函數(shù)由用戶填寫內(nèi)容冤留,用來修改和控制游戲中各種需要顯示的內(nèi)容。比如在在Unity里面叫Update()树灶,這類函數(shù)通常會在每幀畫面渲染前調(diào)用纤怒,當(dāng)用戶修改了游戲中的各個角色的位置、大小后天通,就在下一幀畫面中顯示出來泊窘。而在幀同步的游戲中,這個Update()函數(shù)依然是存在像寒,只不過里面大部分的內(nèi)容烘豹,需要挪到另外一個類似的函數(shù)中,我們可以稱之為UpdateNet()函數(shù)——由網(wǎng)絡(luò)層不斷的接收服務(wù)器發(fā)來的“網(wǎng)絡(luò)幀”數(shù)據(jù)包诺祸,每收到一個這樣的數(shù)據(jù)包携悯,就調(diào)用一次這個UpdateNet()函數(shù),這樣游戲就從通過本地CPU的Update()函數(shù)的驅(qū)動筷笨,改為根據(jù)網(wǎng)絡(luò)來的UpdateNet()函數(shù)驅(qū)動了憔鬼。顯然,網(wǎng)絡(luò)發(fā)過來的同步幀速度會明顯比本地CPU要慢的多胃夏,這里就對我們的游戲邏輯開發(fā)提出了更高的要求——如何同步的同時(shí)轴或,還能保證流暢?

實(shí)現(xiàn)UpdateNet函數(shù)內(nèi)容仰禀,其實(shí)就是定義一個堆棧用于存放網(wǎng)絡(luò)發(fā)過來的消息照雁,通過幀監(jiān)測將其數(shù)據(jù)拿出來使用,因?yàn)閁pdate函數(shù)明顯比UpdateNet快的多悼瘾,這就需要我們定義一個時(shí)間間隔用于消息的發(fā)送囊榜,比如50毫秒或者100毫米等审胸。

private float AccumilatedTime = 0f;

private float FrameLength = 0.05f; //50 miliseconds   
//called once per unity frame   
public void Update()
{
    //Basically same logic as FixedUpdate, but we can scale it by adjusting FrameLength   
    AccumilatedTime = AccumilatedTime + Time.deltaTime;

    //in case the FPS is too slow, we may need to update the game multiple times a frame   
    while (AccumilatedTime > FrameLength)
    {
        GameFrameTurn();
        AccumilatedTime = AccumilatedTime - FrameLength;
    }
}
private void GameFrameTurn()
{
    //first frame is used to process actions   
    if (GameFrame == 0)
    {
        if (LockStepTurn())
        {
            GameFrame++;
        }
    }
    else
    {
        //update game   
        SceneManager.Manager.TwoDPhysics.Update(GameFramesPerSecond);

        List<IHasGameFrame> finished = new List<IHasGameFrame>();
        foreach (IHasGameFrame obj in SceneManager.Manager.GameFrameObjects)
        {
            obj.GameFrameTurn(GameFramesPerSecond);
            if (obj.Finished)
            {
                finished.Add(obj);
            }
        }

        foreach (IHasGameFrame obj in finished)
        {
            SceneManager.Manager.GameFrameObjects.Remove(obj);
        }

        GameFrame++;
        if (GameFrame == GameFramesPerLocksetpTurn)
        {
            GameFrame = 0;
        }
    }
}

幀同步游戲中亥宿,由于需要“每一幀”都要廣播數(shù)據(jù),所以廣播的頻率非常高砂沛,這就要求每次廣播的數(shù)據(jù)要足夠的小烫扼。最好每一個網(wǎng)絡(luò)幀,能在一個MTU以下碍庵,這樣才能有效降低底層網(wǎng)絡(luò)的延遲映企。同樣的理由,我們?yōu)榱颂岣邔?shí)時(shí)性静浴,一般也傾向于使用UDP而不是TCP協(xié)議堰氓,這樣底層的處理會更高效。但是苹享,這樣也會帶來了丟包双絮、亂序的可能性。因此我們常常會以冗余的方式——比如每個幀數(shù)據(jù)包,實(shí)際上是包含了過去2幀的數(shù)據(jù)囤攀,也就是每次發(fā)3幀的數(shù)據(jù)软免,來對抗丟包。也就是說三個包里面只要有一個包沒丟焚挠,就不影響游戲膏萧。

幀同步實(shí)現(xiàn)的過程有個很重要的地方就是邏輯層和表現(xiàn)層一定要分開,表現(xiàn)層先行蝌衔,邏輯層等發(fā)到服務(wù)端的指令再處理榛泛。幀與幀之間的播放頻率,則由服務(wù)器統(tǒng)一控制噩斟,但由于網(wǎng)絡(luò)抖動等影響挟鸠,幀的頻率并不是太穩(wěn)定,為避免播放抖動亩冬,幀數(shù)控制器需要進(jìn)行一定的平滑處理艘希。

image

網(wǎng)絡(luò)抖動的產(chǎn)生原因:在網(wǎng)絡(luò)游戲中,各個客戶端的運(yùn)行條件和環(huán)境往往千差萬別硅急,有的硬件好一些覆享,有的差一些,各方的網(wǎng)絡(luò)情況也不一致营袜;時(shí)不時(shí)玩家的網(wǎng)絡(luò)還會在游戲過程中撒顿,發(fā)生臨時(shí)的擁堵,我們稱之為“網(wǎng)絡(luò)抖動”荚板》锉冢可能導(dǎo)致客戶端收到“過去時(shí)間”里的一堆網(wǎng)絡(luò)幀,客戶端需要拿出一定的時(shí)間去處理這些堆積的網(wǎng)絡(luò)幀跪另,因此拧抖,客戶端必須要有處理這些堆積起來的網(wǎng)絡(luò)數(shù)據(jù)的能力。

實(shí)時(shí)同步游戲最重要的是流暢免绿,然而影響游戲流暢的因素很多唧席,網(wǎng)絡(luò)帶寬的限制,CPU運(yùn)算和渲染效率的限制嘲驾。一般玩家控制的角色的動作淌哟,包括當(dāng)前客戶端控制的角色,還是應(yīng)該從網(wǎng)絡(luò)幀里面獲得行為數(shù)據(jù)辽故,因?yàn)槿绻婕覑劭刂平巧灰恢碌奶嗤讲郑麄€游戲場面就會差更多。很多游戲中的怪物AI都是根據(jù)玩家角色來設(shè)定的誊垢,所以一旦玩家角色的行為是同步的掉弛,那么大多數(shù)的怪物的表現(xiàn)還是一致的喻杈。

幀同步游戲技術(shù),并不存在一種可以讓游戲流暢的通用做法狰晚,而是需要和游戲具體做很多結(jié)合筒饰,在減少數(shù)據(jù)包,優(yōu)化游戲快進(jìn)體驗(yàn)壁晒,控制發(fā)包速度上盡量調(diào)優(yōu)瓷们。同時(shí)還需要和游戲產(chǎn)品策劃一起,平衡一致性秒咐、實(shí)時(shí)性谬晕、公平性的策略,才能真正達(dá)到流暢游戲的目的携取。

鏈接
demo下載地址
關(guān)于幀同步和網(wǎng)游游戲開發(fā)的一些心得

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末攒钳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子雷滋,更是在濱河造成了極大的恐慌不撑,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晤斩,死亡現(xiàn)場離奇詭異焕檬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)澳泵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門实愚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兔辅,你說我怎么就攤上這事腊敲。” “怎么了维苔?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵碰辅,是天一觀的道長。 經(jīng)常有香客問我蕉鸳,道長乎赴,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任潮尝,我火速辦了婚禮,結(jié)果婚禮上饿序,老公的妹妹穿的比我還像新娘勉失。我一直安慰自己,他們只是感情好原探,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布乱凿。 她就那樣靜靜地躺著顽素,像睡著了一般。 火紅的嫁衣襯著肌膚如雪徒蟆。 梳的紋絲不亂的頭發(fā)上胁出,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音段审,去河邊找鬼全蝶。 笑死,一個胖子當(dāng)著我的面吹牛寺枉,可吹牛的內(nèi)容都是我干的抑淫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼姥闪,長吁一口氣:“原來是場噩夢啊……” “哼始苇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起筐喳,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤催式,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后避归,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蓄氧,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年槐脏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喉童。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡顿天,死狀恐怖堂氯,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情牌废,我是刑警寧澤咽白,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站鸟缕,受9級特大地震影響晶框,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜懂从,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一授段、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧番甩,春花似錦侵贵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卡睦。三九已至,卻和暖如春漱抓,著一層夾襖步出監(jiān)牢的瞬間表锻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工乞娄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瞬逊,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓补胚,卻偏偏與公主長得像码耐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子溶其,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評論 2 354