網絡遊戲的同步能夠作的很簡單,也能夠作的很複雜。簡單來講就是經過Http或者Socket來跟服務器同步數據。而若是往復雜了說,能夠有p2p、幀同步、航位預測等等高級課題能夠研究。php
由於咱們的項目需求----幾百個獨立單位的實時同步(帶pvp的rts),因此研究了下幀同步。不事後來發現它其實有不少問題,因此具體如何還要看其餘同事的研究成果。以我我的來講,修改遊戲方案反而是最合理的解決方案。html
首先從需求上來講,幾百個獨立單位的做戰,自己結果和士兵強弱從策劃的角度來看就是不可控制的。玩家更加不可控制。好比士兵的攻擊力增長10%或者弓箭手的射程增長50%,帶來的影響多是幾倍於預想值。這樣一個不可控制的遊戲對玩家而言,即使再獨特,其吸引力也不如卡牌遊戲。 從這點上來講,項目的需求自己就是值得商榷的。spring
幀同步的原理和實現能夠參考這些文章:服務器
http://clintonbrennan.com/2013/12/lockstep-implementation-in-unity3d/網絡
http://blog.sina.com.cn/s/blog_674f1bd20101omv7.html數據結構
大意是,遊戲運行時以10fps(100毫秒間隔,具體數值可根據實際狀況調整)運行一個邏輯幀,邏輯幀負責物理、ai、攻擊斷定等等。而動畫和實際位移由渲染幀負責。這樣動畫表現是流暢的。而客戶端每邏輯幀都會與服務器進行通訊同步客戶端的操做,當操做同步完成客戶端的邏輯幀能夠繼續向後模擬。好比運行第3幀要確保第一幀的數據是完整的。雙方客戶端接收的操做內容是一致的,初始狀態是一致的,因此運行的結果也應該是一致的。隨機數可使用肯定隨機種子的僞隨機數來解決。函數
因此關鍵問題就是要確保客戶端以一樣的輸入能夠得到一樣的運行結果。 這個是理論上可行的,不少rts遊戲也都是基於此原理。好比魔獸爭霸3 最高指揮官2 全面戰爭 星際爭霸 帝國時代 等等。 以最高指揮官(Super Commander)爲例,其所有單位有上千個,若是要實時同步他們的狀態以如今的網絡條件都是很困難的,因此這些rts同步的僅僅是操做,即點擊了什麼位置,點擊了什麼按鈕,選擇了什麼目標,按了什麼按鍵。客戶端接收到對應的操做,進行一樣的模擬,達到一樣的輸出。從而完成網絡同步。測試
魔獸爭霸的錄像機制也是基於此原理,記錄操做,而不記錄狀態。因此幾十分鐘的遊戲,其戰報只有幾百k。一樣由於這個原理,因此在出bug的時候(機率不高,可是玩家多了,仍是很容易碰到的)會形成錄像與實際玩的時候不一致。好比玩的時候劍聖暴擊殺死了對手,從而翻盤取得了經典的勝利,可是戰報播放的時候卻沒有發生暴擊,直接被對方給推了。 全面戰爭也是如此,因此也會出現戰報跟實際遊戲不一致的狀況,不過幾率確實不大,只有發生極限狀況纔可能出現這樣的問題。動畫
可是,若是拿Unity實現一個RTS手遊,要實現肯定性的模擬就很是困難了。由於Unity中的Start Awake Update等函數的調用是不受控制的,協程、SendMessage、Invoke也是不受控制的,動畫事件更加不受控制,物理使用Physic也是不保證肯定性模擬的,即OnTriggerEnter這些函數的調用或者RigidBody的運動均可能存在偏差。一開始只是很是小能夠忽略的偏差,而偏差可能逐漸積累最終的蝴蝶效應就是戰鬥結果徹底不一致。好比一開始只是一個單位的座標誤差了0.1米,可是可能影響到一個箭有沒有射中它,進而影響到它究竟死沒死,若是單位的死亡產生不一致了,那麼後續的戰鬥就徹底錯亂掉了。.net
這個就是幀同步的過程當中的「不一樣步」現象。帝國時代和最高指揮官會在每邏輯幀計算當前全部單位的屬性的crc值,幾個客戶端之間比較這個crc值,若是發現不一致,那麼就是不一樣步現象。此時能夠把不一樣步的客戶端踢出遊戲,也能夠強制同步某個單位或者是全部單位的狀態。產生不一樣步現象的緣由可能不少,好比機器卡了一下,網絡卡了一下。不管什麼緣由,可是確實是出Bug了,悲劇的是,這個Bug是很是難查的。多是使用某個特殊技能形成一個特殊效果的時候,剛好殺死了對方,這種狀況下會出Bug。也多是錯誤的使用了被內存池回收的數據,若是此時此數據已被從新分配出去,那麼就會出現Bug,若是沒有被從新分配出去,那麼能夠「正常」的運行。 當遊戲越複雜,這種Bug可能越多,而且幾乎不可查,由於只有當大量玩家玩的時候纔會暴露出這樣的問題,QA根本沒法重現這個Bug。 即使不是幀同步,「肯定性」模擬,這類Bug都是最讓人頭疼的,可能會「沒法重現」幾年,更況且對精確度要求很是高的時候。
實現一個「肯定性」模擬的客戶端,其難度很高,而且維護成本很是大。每一個添加的技能都要深思熟慮,而且要花大量的時間去測試。每一個新添加的代碼均可能形成不一樣步現象,除非戰鬥部分寫好後一百年不動,不然不管是重構仍是添加新功能都會戰戰兢兢,如履薄冰。
不光是Unity自己的問題,底層和上層都須要作相應的處理。
底層要保證浮點數的「肯定性」,這個自己就是一個高級課題,保證後還要考慮修改後的效率問題,畢竟手游上單位多了,簡單ai也會成爲大問題,若是浮點數計算的效率低了,極可能會大大的下降運行效率。數據結構如List也可能會有不穩定排序的問題。
上層的ai邏輯也要精心設計,以儘量「準確」的描述來執行行爲,好比a單位移動到b點,攻擊c,這樣的ai執行起來相對可靠。而若是是a追蹤b單位,直到x單位進入攻擊範圍則開始攻擊,這個就埋下了很大的隱患,除非全部的計算和調用都是肯定性的。
以手游來講,以幀同步來實現戰鬥同步還有一些反作用。好比要保證客戶端徹底匹配,不管是配置仍是版本,差一點兒都沒有辦法一同遊戲。因此不管是安裝包仍是配置,只要有修改就必需要讓玩家更新,不然不能進入戰鬥。 而不一樣設備、不一樣cpu,是否會形成不一樣的結果,這個不能百分百的確定,也就是說,遊戲的兼容性有很大的隱患。
總結一下就是,如今手游上使用幀同步來處理rts並不現實,迄今爲止我並無看到成功的例子。 而早期的rts遊戲,可能由於遊戲相對簡單,自研引擎相對可控,再加上大量人力物力的投入,這些跟咱們手遊使用Unity快速開發遊戲的模式並不相同。 而除開rts,我並不認爲其餘的遊戲形式如ARPG、橫版格鬥等等須要使用幀同步,正常的行爲和狀態同步足夠了。注意,幀同步的肯定性模擬這個需求是個大難題,並非幀同步自己有多難。也並非說不使用幀同步,客戶端就不能本身運行邏輯,進行動做先行或者是預測。
參考資料(這些資料都至關經典,強烈推薦閱讀):
1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond
http://www.gamasutra.com/view/feature/3094/1500_archers_on_a_288_network_.php
Syncing System of TA Spring
https://springrts.com/wiki/Syncing_System
Opinion: Synchronous RTS Engines And A Tale of Desyncs
http://www.gamasutra.com/view/news/126022/Opinion_Synchronous_RTS_Engines_And_A_Tale_of_Desyncs.php
SYNCHRONOUS RTS ENGINES 2: SYNC HARDER
http://forrestthewoods.com/synchronous-rts-engines-2-sync-harder/
Cross platform RTS synchronization and floating point indeterminism
http://gamasutra.com/blogs/MaksymHryniv/20150107/233596/Cross_platform_RTS_synchronization_and_floating_point_indeterminism.php
原文:http://blog.csdn.net/langresser_king/article/details/46756393