《球球大作战》源码解析(8):消息广播

作者:罗培羽 2019-03-27


系列文章
《球球大作战》源码解析——(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网络游戏实战》充分的讲解怎样开发一款网络游戏,特别对网络框架设计、网络协议、数据处理等方面都有详细的描述,相信会是一本好书的。


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

最新评论
暂无评论
参与评论

商务合作 查看更多

编辑推荐 查看更多