《球球大作戰》原始碼解析(8):訊息廣播

遊資網發表於2019-03-27
《球球大作戰》原始碼解析(8):訊息廣播


系列文章
《球球大作戰》原始碼解析——(1)執行起來
《球球大作戰》原始碼解析:伺服器與客戶端架構
《球球大作戰》原始碼解析:移動演算法
《球球大作戰》原始碼解析(6):碰撞處理

《球球大作戰》原始碼解析(7):遊戲迴圈
《球球大作戰》原始碼解析(8):訊息廣播


服務端程式中有3個定時器函式,前幾篇分別解析了處理玩家移動的moveloop方法、以及處理排行榜、食物生成等遊戲邏輯的gameloop。最後一個定時器函式為sendUpdates,呼叫語句是:setInterval(sendUpdates, 1000 / c.networkUpdateFactor),其中networkUpdateFactor預設值為40,即是每秒執行40次sendUpdates,處理訊息的廣播。sendUpdates會對每個玩家都做操作,具體的結構如下。

  1. function sendUpdates() {

  2.     users.forEach( function(u) {

  3.        ……

  4.     }

  5. }

複製程式碼

同步食物列表

那麼看看foreach裡面的內容,先獲取對該使用者可見的食物資訊,這裡通過範圍判斷,獲取該使用者視野範圍內的食物,然後組合成visibleFood列表。後面只要把visibleFood的資訊傳送給該使用者就好了,其他看不見的就不管了。

  1.         var visibleFood  = food

  2.             .map(function(f) {

  3.                 if ( f.x > u.x - u.screenWidth/2 - 20 &&

  4.                     f.x < u.x + u.screenWidth/2 + 20 &&

  5.                     f.y > u.y - u.screenHeight/2 - 20 &&

  6.                     f.y < u.y + u.screenHeight/2 + 20) {

  7.                     return f;

  8.                 }

  9.             })

  10.             .filter(function(f) { return f; });
複製程式碼

同步病毒列表

使用同樣的方法計算可見的病毒,產生同步列表visibleVirus。

  1.         var visibleVirus  = virus

  2.             .map(function(f) {

  3.                 if ( f.x > u.x - u.screenWidth/2 - f.radius &&

  4.                     f.x < u.x + u.screenWidth/2 + f.radius &&

  5.                     f.y > u.y - u.screenHeight/2 - f.radius &&

  6.                     f.y < u.y + u.screenHeight/2 + f.radius) {

  7.                     return f;

  8.                 }

  9.             })

  10.             .filter(function(f) { return f; });
複製程式碼

同步massFood列表

使用同樣的方法計算可見的massFood,產生同步列表visibleMass。

  1.         var visibleMass = massFood

  2.             .map(function(f) {

  3.                 if ( f.x+f.radius > u.x - u.screenWidth/2 - 20 &&

  4.                     f.x-f.radius < u.x + u.screenWidth/2 + 20 &&

  5.                     f.y+f.radius > u.y - u.screenHeight/2 - 20 &&

  6.                     f.y-f.radius < u.y + u.screenHeight/2 + 20) {

  7.                     return f;

  8.                 }

  9.             })

  10.             .filter(function(f) { return f; });
複製程式碼

同步其他玩家

用類似的方法計算玩家可以看到的其他玩家,因為其他玩家可能有多個分身,這裡對每個分身做處理。如果分身在可見範圍內,就把相關的資訊放到visibleCells 列表裡面。列表裡包括玩家自己的資訊和其他玩家的資訊,如果是其他玩家,還要加上他們的名字和id。

  1. var visibleCells  = users

  2.             .map(function(f) {

  3.                 for(var z=0; z<f.cells.length; z++)

  4.                 {

  5.                     if ( f.cells[z].x+f.cells[z].radius > u.x - u.screenWidth/2 - 20 &&

  6.                         f.cells[z].x-f.cells[z].radius < u.x + u.screenWidth/2 + 20 &&

  7.                         f.cells[z].y+f.cells[z].radius > u.y - u.screenHeight/2 - 20 &&

  8.                         f.cells[z].y-f.cells[z].radius < u.y + u.screenHeight/2 + 20) {

  9.                         z = f.cells.lenth;

  10.                         if(f.id !== U.ID) {

  11.                             return {

  12.                                 id: f.id,

  13.                                 x: f.x,

  14.                                 y: f.y,

  15.                                 cells: f.cells,

  16.                                 massTotal: Math.round(f.massTotal),

  17.                                 hue: f.hue,

  18.                                 name: f.name

  19.                             };

  20.                         } else {

  21.                             //console.log("Nombre: " + f.name + " Es Usuario");

  22.                             return {

  23.                                 x: f.x,

  24.                                 y: f.y,

  25.                                 cells: f.cells,

  26.                                 massTotal: Math.round(f.massTotal),

  27.                                 hue: f.hue,

  28.                             };

  29.                         }

  30.                     }

  31.                 }

  32.             })

  33.             .filter(function(f) { return f; });
複製程式碼

傳送資料

最後就是傳送資料了,服務端傳送serverTellPlayerMove協議,並且把可見食物、可見其他玩家部位、可見的mass和病毒發過去。如果排行榜發生了變化,還通過leaderboard協議把排行榜資料傳送出去。客戶端收到協議後,更新畫面。

  1.         sockets[U.ID].emit('serverTellPlayerMove', visibleCells, visibleFood, visibleMass, visibleVirus);

  2.         if (leaderboardChanged) {

  3.             sockets[U.ID].emit('leaderboard', {

  4.                 players: users.length,

  5.                 leaderboard: leaderboard

  6.             });

  7.         }

  8.     });

  9.     leaderboardChanged = false;
複製程式碼

還是放個廣告吧,筆者出版的一本書《Unity3D網路遊戲實戰》充分的講解怎樣開發一款網路遊戲,特別對網路框架設計、網路協議、資料處理等方面都有詳細的描述,相信會是一本好書的。

《球球大作戰》原始碼解析(8):訊息廣播

作者:羅培羽
原地址:https://zhuanlan.zhihu.com/p/29733789

相關文章