绘制多个套接字实例以在移动(多人)上进行canvas和更新

计划

我决定开始尝试使用Node.js和Socket.io,然后开始制作一个游戏(或者只是一个大厅,将每个玩家画成一个块)。 每当一个客户端join时,服务器就应该接受这个类,并用服务器给出的玩家详细信息实例化一个新的对象(Random)。

然后,服务器将使用socket.io并将新对象发送到连接的客户端,以便他们可以拥有该对象,然后可以使用它(在这种情况下移动)。

客户端应该做的第一件事就是将所有用户绘制到canvas上,然后将当前客户端绘制到canvas上。


问题

我已经到了事情正在工作的地步,服务器做了一个新的播放器对象,然后发送给客户端,然后客户端将能够绘制自己的canvas与属性,但我似乎不能有客户端发送在其他用户的canvas上绘制,直到我移动播放器。

当我打开多个浏览器选项卡,然后按预期的方式工作,如下所示绘制客户端:

在这里输入图像说明

但是当我移动其中的一个,那么一个客户端会成功吸引到其他客户端,但是其他客户端都会失去那个时候给予他们的对象,直到他们移动,然后在其他地方顺利移动,但其他客户端都丢失屏幕状态,你可以看到他们所在的位置。 总之,他们都在屏幕上,并相应地移动到所有浏览器中的正确位置,但是当发生这种情况时,您从不会看到所有的玩家,而只会一次显示一个玩家,而且是一个移动的玩家(在您第一次join之后也只有看到自己,直到有人移动,但你看到所有的球员只有最后一次移动,直到有人或你移动)。 在下面查看图像

在这里输入图像说明

以上显示了我关注中间选项卡和移动,日志显示发生了什么(注意其他球员都消失了,只有移动的显示)


代码

我只有2个文件,我正在使用,他们填充如下。

服务器 – nodejs

var express = require('express'), app = express(), http = require('http').createServer(app), io = require('socket.io').listen(http); http.listen(8000); //server connections and routing app.use(express.static(__dirname + '/public'), function(request, response){ if(request.url !== '/public') { response.sendFile( __dirname +'/error/index.html'); console.log('Error 404 request, User tried accessing: ' + __dirname + request.url); } }); var players = []; //Lets create a function which will help us to create multiple players function newPlayer() { this.name; this.id = 1; this.x = Math.random() * 500; this.y = Math.random() * 500; //Random colors var r = Math.random()*255>>0; var g = Math.random()*255>>0; var b = Math.random()*255>>0; this.color = "rgba(" + r + ", " + g + ", " + b + ", 0.5)"; //Random size this.radius = Math.random()*20+20; this.speed = 5; return {'name' : this.name,"x" : this.x,"y" : this.y,"color" : this.color, "radius" : this.radius,"speed" : this.speed} } //calls to the server and tracking connection of each new user io.sockets.on('connection', function(socket){ var currentPlayer = new newPlayer(); //new player made players.push(currentPlayer); //push player object into array //create the player socket.broadcast.emit('createUsers', players); socket.emit('currentUser', currentPlayer); //user moved socket.on('moved', function(data){ console.log(data); socket.broadcast.emit('moving', data); }); //disconnected socket.on('disconnect', function(){ var i = players.indexOf(currentPlayer); players.splice(i, 1); socket.broadcast.emit('user left','User: ' + currentPlayer.name + ' Left'); console.log(players); }); }); console.log('NodeJS Server started on port 8000...'); 

客户端 – HTML

 <!doctype html> <html> <head> <title>Game Dev JS - 1</title> <link href="./ui.css" rel="stylesheet"> </head> <body> <canvas id="canvas" width="500" height="500"> Your Browser Does Not Support Canvas and HTML5 </canvas> </body> <script type="text/javascript" src="/socket.io/socket.io.js"></script> <script type="text/javascript" src="/js/engine.js"></script> </html> 

客户端 – CSS

 body{ margin: 0 auto; width: auto; background: #fff; text-align: center; } #canvas { margin: 15px; background: #000; } 

客户端 – Javascript

 var socket = io.connect(); //add socket object //initializing the canvas var canvas = document.getElementById("canvas"), ctx = canvas.getContext('2d'), W = window.innerWidth, H = window.innerHeight; var keys = {}; window.addEventListener('keydown', function(e){ keys[e.keyCode] = true; }, false); //check if ke is not being pressed or has lifted up window.addEventListener('keyup', function(e){ delete keys[e.keyCode]; }, false); socket.on('currentUser', function(newUser){ ctx.fillStyle = newUser.color; ctx.fillRect(newUser.x, newUser.y, 25, 25); function update(){ //moving player if(keys[38]){ newUser.y -= newUser.speed; socket.emit('moved', newUser); console.clear(); console.log('You Moving'); console.log(newUser); ctx.clearRect(0, 0, W, H); ctx.fillStyle = newUser.color; ctx.fillRect(newUser.x, newUser.y, 25, 25); } if(keys[40]){ newUser.y += newUser.speed; socket.emit('moved', newUser); console.clear(); console.log('You Moving'); console.log(newUser); ctx.clearRect(0, 0, W, H); ctx.fillStyle = newUser.color; ctx.fillRect(newUser.x, newUser.y, 25, 25); } if(keys[37]){ newUser.x -= newUser.speed; socket.emit('moved', newUser); console.clear(); console.log('You Moving'); console.log(newUser); ctx.clearRect(0, 0, W, H); ctx.fillStyle = newUser.color; ctx.fillRect(newUser.x, newUser.y, 25, 25); } if(keys[39]){ newUser.x += newUser.speed; socket.emit('moved', newUser); console.clear(); console.log('You Moving'); console.log(newUser); ctx.clearRect(0, 0, W, H); ctx.fillStyle = newUser.color; ctx.fillRect(newUser.x, newUser.y, 25, 25); } window.requestAnimationFrame(update); } update(); }); //moving player and updating on other clients socket.on('moving', function(moveTo){ ctx.clearRect(0, 0, W, H); ctx.fillStyle = moveTo.color; ctx.fillRect(moveTo.x, moveTo.y, 25, 25); console.clear(); console.log('A Player Moved'); console.log(moveTo); }); 

笔记

我将它托pipe在一个小提琴的地方,你可以玩,但我不知道任何允许我用node.js服务器进行testing,并允许你在JS小提琴同时看看代码。 我还是新的Node和Socket.io,这是我的第一次尝试任何帮助将是我的奖金。 一旦主要function正常,我将着手重构代码。

如果你安装了npm并且你安装了socket.io,那么你应该可以复制和粘贴这个,它应该可以工作。 我的文件夹结构如下 – 这没有任何问题,因为一切正常加载

在这里输入图像说明

提前致谢

您的moving事件的客户端监听者将永远只允许客户端一次绘制一个玩家的位置。 您正在清除整个屏幕,擦除所有其他位置,但只会重新绘制移动的玩家。

我会推荐阅读罗伯特Nystrom的优秀游戏编程模式电子书http://gameprogrammingpatterns.com/contents.html 。 它不包括这个特定的情况,但是你可以从观察者,游戏循环和更新的部分推断很多。 在你的情况下,你可能希望服务器运行权威的游戏循环和状态,使用观察者来更新客户端/服务器之间的状态,以及将用户自己的独立游戏循环显示给用户的状态。

看到我从来没有得到答复,以帮助validation我的问题。 我设法阅读了本书(或上面的@JCD部分),并设法查看其他应用程序以及如何使用节点pipe理其应用程序。

我知道在节点服务器上做任何计算是不好的做法,所以我重新查看了我的客户端和服务器的代码并更新了它。


判决书


客户端:

我决定让客户端只显示当前客户端及其属性以及连接到服务器的其他客户端。 使用一个循环,客户端将遍历由服务器(连接到服务器的所有套接字)生成的一组JSON对象。 客户端将使用canvas将对象绘制到canvas上。 当新客户端join时,数组也会自动更新,使得客户端自动出现在其他客户端的正确位置。 我正在使用请求animation框来检查客户端是否按下一个键,然后发送和更新客户端属性,而服务器只是相应地进行广播(客户端将循环绘制到canvas的更新的数组)。

服务器端:

服务器将负责等待客户端向服务器发送密钥,如果满足条件,它将使用新的属性更新分配给该客户端的对象(当正确的密钥通过时移动 – 获取通过RequestAnimationFrame()发送到服务器)。


码:

客户端(HTML – 没有改变):

 <!doctype html> <html> <head> <title>Game Dev JS - 1</title> <link href="./ui.css" rel="stylesheet"> </head> <body> <canvas id="canvas" width="500" height="500"> Your Browser Does Not Support Canvas and HTML5 </canvas> </body> <script type="text/javascript" src="/socket.io/socket.io.js"></script> <script type="text/javascript" src="/js/engine.js"></script> </html> 

客户端(JS – 更新):

 var socket = io.connect(); //add socket object //initializing the canvas var canvas = document.getElementById("canvas"), ctx = canvas.getContext('2d'), W = window.innerWidth, H = window.innerHeight; var keys = {}; window.addEventListener('keydown', function(e){ keys[e.keyCode] = true; }, false); //check if key is not being pressed or has lifted up window.addEventListener('keyup', function(e){ delete keys[e.keyCode]; }, false); //game loop to make the game smoother function gameLoop() { if(keys[38]) { socket.emit('pressed', 38); console.log('You are UP'); } if(keys[40]) { socket.emit('pressed', 40); console.log('You are DOWN'); } if(keys[37]) { socket.emit('pressed', 37); console.log('You are LEFT'); } if(keys[39]) { socket.emit('pressed', 39); console.log('You are RIGHT'); } window.requestAnimationFrame(gameLoop); } window.requestAnimationFrame(gameLoop); //the connected user joins and gets all the players on server socket.on('welcome', function(currentUser, currentUsers){ console.log(currentUser); ctx.globalCompositeOperation = "source-over"; //Lets reduce the opacity of the BG paint to give the final touch ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; ctx.fillRect(0, 0, W, H); //Lets blend the particle with the BG ctx.globalCompositeOperation = "lighter"; //players in lobby for(var i = 0; i < currentUsers.length; i++){ ctx.beginPath(); //Time for some colors var gradient = ctx.createRadialGradient(currentUsers[i].x, currentUsers[i].y, 0, currentUsers[i].x, currentUsers[i].y, currentUsers[i].radius); gradient.addColorStop(0, "white"); gradient.addColorStop(0.4, "white"); gradient.addColorStop(0.4, currentUsers[i].color); gradient.addColorStop(1, "black"); ctx.fillStyle = gradient; ctx.arc(currentUsers[i].x, currentUsers[i].y, currentUsers[i].radius, Math.PI*2, false); ctx.fill(); } //player ctx.beginPath(); //Time for some colors var gradient = ctx.createRadialGradient(currentUser.x, currentUser.y, 0, currentUser.x, currentUser.y, currentUser.radius); gradient.addColorStop(0, "white"); gradient.addColorStop(0.4, "white"); gradient.addColorStop(0.4, currentUser.color); gradient.addColorStop(1, "black"); ctx.fillStyle = gradient; ctx.arc(currentUser.x, currentUser.y, currentUser.radius, Math.PI*2, false); ctx.fill(); }); //other users get updated with new players when teh new player joins socket.on('currentUsers', function(currentUsers){ ctx.globalCompositeOperation = "source-over"; //Lets reduce the opacity of the BG paint to give the final touch ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; //Lets blend the particle with the BG ctx.globalCompositeOperation = "lighter"; for(var i = 0; i < currentUsers.length; i++){ ctx.beginPath(); //Time for some colors var gradient = ctx.createRadialGradient(currentUsers[i].x, currentUsers[i].y, 0, currentUsers[i].x, currentUsers[i].y, currentUsers[i].radius); gradient.addColorStop(0, "white"); gradient.addColorStop(0.4, "white"); gradient.addColorStop(0.4, currentUsers[i].color); gradient.addColorStop(1, "black"); ctx.fillStyle = gradient; ctx.arc(currentUsers[i].x, currentUsers[i].y, currentUsers[i].radius, Math.PI*2, false); ctx.fill(); } console.log('A new User has joined'); }); //if a player leaves, everyone gets new set of players socket.on('playerLeft', function(currentUsers){ ctx.fillRect(0, 0, W, H); ctx.globalCompositeOperation = "source-over"; //Lets reduce the opacity of the BG paint to give the final touch ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; //Lets blend the particle with the BG ctx.globalCompositeOperation = "lighter"; for(var i = 0; i < currentUsers.length; i++){ ctx.beginPath(); //Time for some colors var gradient = ctx.createRadialGradient(currentUsers[i].x, currentUsers[i].y, 0, currentUsers[i].x, currentUsers[i].y, currentUsers[i].radius); gradient.addColorStop(0, "white"); gradient.addColorStop(0.4, "white"); gradient.addColorStop(0.4, currentUsers[i].color); gradient.addColorStop(1, "black"); ctx.fillStyle = gradient; ctx.arc(currentUsers[i].x, currentUsers[i].y, currentUsers[i].radius, Math.PI*2, false); ctx.fill(); } console.log('A Player Has left'); }); socket.on('PlayersMoving', function(players){ ctx.globalCompositeOperation = "source-over"; //Lets reduce the opacity of the BG paint to give the final touch ctx.fillStyle = "rgba(0, 0, 0, 0.3)"; ctx.fillRect(0, 0, W, H); //Lets blend the particle with the BG ctx.globalCompositeOperation = "lighter"; var players = players; var i = 0; function allPlayers(){ for(i; i < players.length; i ++) { ctx.beginPath(); //Time for some colors var gradient = ctx.createRadialGradient(players[i].x, players[i].y, 0, players[i].x, players[i].y, players[i].radius); gradient.addColorStop(0.5, "white"); gradient.addColorStop(0.5, players[i].color); gradient.addColorStop(1, "black"); ctx.fillStyle = gradient; ctx.arc(players[i].x, players[i].y, players[i].radius, Math.PI*2, false); ctx.fill(); } } allPlayers(); }); 

服务器端(NodeJS – 更新):

 var express = require('express'), app = express(), http = require('http').createServer(app), io = require('socket.io').listen(http); http.listen(3000); //server connections and routing app.use(express.static(__dirname + '/public'), function(request, response){ if(request.url !== '/public') { response.sendFile( __dirname +'/error/index.html'); console.log('Error 404 request, User tried accessing: ' + __dirname + request.url); } }); var players = []; //Lets create a function which will help us to create multiple players function newPlayer() { this.name; this.id = 1; this.x = Math.random() * 500; this.y = Math.random() * 500; //Random colors var r = Math.random()*255>>0; var g = Math.random()*255>>0; var b = Math.random()*255>>0; this.color = "rgba(" + r + ", " + g + ", " + b + ", 0.5)"; //Random size this.radius = Math.random()*20+20; this.speed = 5; return {'name' : this.name,"x" : this.x,"y" : this.y,"color" : this.color, "radius" : this.radius,"speed" : this.speed} } //calls to the server and tracking connection of each new user io.sockets.on('connection', function(socket){ var currentPlayer = new newPlayer(); //new player made players.push(currentPlayer); //push player object into array //create the players Array socket.broadcast.emit('currentUsers', players); socket.emit('welcome', currentPlayer, players); //disconnected socket.on('disconnect', function(){ players.splice(players.indexOf(currentPlayer), 1); console.log(players); socket.broadcast.emit('playerLeft', players); }); socket.on('pressed', function(key){ if(key === 38){ currentPlayer.y -= currentPlayer.speed; socket.emit('PlayersMoving', players); socket.broadcast.emit('PlayersMoving', players); } if(key === 40){ currentPlayer.y += currentPlayer.speed; socket.emit('PlayersMoving', players); socket.broadcast.emit('PlayersMoving', players); } if(key === 37){ currentPlayer.x -= currentPlayer.speed; socket.emit('PlayersMoving', players); socket.broadcast.emit('PlayersMoving', players); } if(key === 39){ currentPlayer.x += currentPlayer.speed; socket.emit('PlayersMoving', players); socket.broadcast.emit('PlayersMoving', players); } }); }); console.log('NodeJS Server started on port 3000...'); 

在这里输入图像说明


我知道它不是最干净的做事方式,但这是一个原型,我希望它可以在不久的将来帮助某个人成为一个垫脚石,可以解决同样的问题,而不必经历同样的麻烦。

谢谢