使用node.js创建多人游戏

回到学习节点时,我使用WebSockets构建了一个简单的多人游戏。 由于我对它进行编码很有趣,所以我决定创建本教程,解释开发类似内容的关键。

游戏是关于坦克的。 玩家进入游戏的网站,选择用户名和三种可用的坦克模型之一。

如果网站上还有其他玩家,他们可以通过向对方发射炮弹来战斗,直到其中之一失去所有能量并爆炸。

(如果没有人在线,您始终可以通过在两个不同的标签或浏览器窗口中打开它进行测试)

如何在本地运行“坦克”

首先,您需要安装node.js。 它几乎适用于任何版本的节点。 所以最新应该没问题。

接下来,您需要通过在项目的文件夹上运行npm install来安装项目的依赖项。

有关npm依赖项的更多信息,请阅读此内容

安装依赖项后,运行npm start
启动服务器。 它将开始在端口8082上运行。然后在浏览器中转到http:// localhost:8082。 您应该看到游戏的开始屏幕。

代码结构

该代码包含两个主要部分: 服务器客户端 。 这两个通过WebSockets进行通信。

服务器

这是一个node.js脚本,它执行两个主要任务:

1.使用 Express提供 在线玩游戏所需的静态文件

  var express = require('express'); 
var app = express();
  //静态资源服务器 
app.use(express.static(__ dirname +'/ www'));
  var server = app.listen(8082,function(){ 
var port = server.address()。port;
console.log('服务器在端口%s上运行',端口);
});

如您所见,所有静态文件都位于www文件夹中,并且在8082端口上运行。

2.使用 socket.io 创建与客户端异步通信所需的WebSockets

  var io = require('socket.io')(server); 
  / *连接事件* / 
  io.on('connection',function(client){ 
console.log('用户已连接');
  client.on('joinGame',function(tank){ 
console.log(tank.id +'加入游戏');
var initX = getRandomInt(40,900);
var initY = getRandomInt(40,500);
client.emit('addTank',{id:tank.id,类型:tank.type,isLocal:true,x:initX,y:initY,hp:TANK_INIT_HP});
client.broadcast.emit('addTank',{id:tank.id,type:tank.type,isLocal:false,x:initX,y:initY,hp:TANK_INIT_HP});
  game.addTank({id:tank.id,type:tank.type,hp:TANK_INIT_HP}); 
});

socket.io基于事件启用服务器与客户端之间的通信。 如您在代码段中所见,有一个joinGame事件,当新用户访问该网站时,该事件将从客户端触发。 然后,服务器使用game.addTank()事件将新的Tank添加到游戏中。

客户端

在每个玩家的浏览器中运行的客户端脚本侦听键盘和鼠标事件,以更新坦克和弹丸的状态。
客户端代码位于www / js文件夹中。

在此代码段中,我们可以看到客户端代码的主循环以及sendData()方法,该方法用于将信息与服务器同步:

  mainLoop:function(){ 
if(this.localTank!=未定义){
this.sendData(); //将有关本地坦克的数据发送到服务器
}
  if(this.localTank!=未定义){ 
//移动本地坦克
this.localTank.move();
}
  }, 

该主循环每50毫秒执行一次。

  var INTERVAL = 50; 
  setInterval(function(){ 
g.mainLoop();
},INTERVAL);

游戏主要逻辑

游戏的一些逻辑是在客户端。
特别是在tanks.js文件上。
其余逻辑在服务器端(index.js)

有一个Game对象,一个Tank对象和一个Ball对象,分别代表游戏的每个元素。

服务器和客户端都有一系列的坦克和球,它们在WebSocket事件中是同步的。

为了计算大炮的角度和弹丸的轨迹,我使用了一些三角函数。

每次鼠标移动时,我们都需要更新加农炮的角度, mxmy代表鼠标指针的坐标。 然后,我们使用三角逆切线函数来计算鼠标坐标点与水箱中心之间的角度。

  setCannonAngle:function(mx,my){ 
var tank = {x:this.x,y:this.y};
var mouse = {x:mx,y:my};
var deltaX = mouse.x-tank.x;
var deltaY = mouse.y-tank.y;
this.cannonAngle = Math.atan2(deltaY,deltaX)* 180 / Math.PI;
this.cannonAngle + = 90;
},

为了计算每个弹丸的轨迹,我们在服务器端进行计算。

  Ball.prototype = { 
 飞:function(){ 
//移至托盘部门
var speedX = BALL_SPEED * Math.sin(this.alpha);
var speedY = -BALL_SPEED * Math.cos(this.alpha);
this.x + = speedX;
this.y + = speedY;
}
  } 

Ball对象的每个实例都包含大炮射击时的角度。 并且我们使用sin和cos函数来获取每个矢量分量的速度。

这样,我们可以每50毫秒更新每个炮弹的位置,并检测与任何坦克的碰撞。

改善游戏

“坦克”是一款非常简单的游戏,可以通过许多不同的方式进行改进。 随意分叉仓库,并在仓库之上工作,以创建自己的超赞版本的游戏。

如果您有任何疑问或想法,请给我评论。 谢谢阅读!