在node.js多人游戏html5游戏中越来越高的延迟

我使用node.js创build了一个网页,表示js,socket.io和jquery。 这是一个简单的游戏,玩家join,给自己一个名字,然后在页面上的一个canvas上移动自己(一个正方形)。 我注意到的是:当有更多的人join游戏并且四处走动的时候,有足够的时间让游戏变得无法玩(只有三个人连接在一起,两个人并没有太大的差距)。 我无法弄清楚这是服务器端延迟还是客户端(这是我第一个处理多人游戏的项目)。 我正在做服务器上的所有位置计算,并将所有玩家对象的数组发送回每个套接字,以便每个客户端可以渲染所有玩家。 客户端只发送input并绘制玩家。

这是游戏的客户端脚本。 这是我处理input和渲染的地方。

$(document).ready(function() { var socket = io.connect(); var canvas = document.getElementById("canvas_html"); var ctx = canvas.getContext("2d"); canvas.width = 512; canvas.height = 480; document.body.appendChild(canvas); var player = { id: '', is_it: false, x: canvas.width / 2, y: canvas.height / 2, velx: 0, vely: 0 } //tell the server to initialize this client as a new player socket.emit('init_client', player); var client_player_list = []; //receive a list of the player objects from the server socket.on('load_players', function(players) { client_player_list = players; }); var keysDown = {}; addEventListener('keydown', function(e) { keysDown[e.keyCode] = true; }, false); addEventListener('keyup', function(e) { delete keysDown[e.keyCode]; }, false); //take input from keys and send input to server var update = function() { if(87 in keysDown)//player holding w socket.emit('up'); if(83 in keysDown)//player holding s socket.emit('down'); if(65 in keysDown)//player holding a socket.emit('left'); if(68 in keysDown)//player holding d socket.emit('right'); if(74 in keysDown)//player holding j socket.emit('tag'); }; //render all players, update players when server updates var render = function() { //ctx.clearColor = "rgba(0, 0, 0, .3)"; ctx.clearRect( 0, 0, canvas.width, canvas.height); ctx.fillStyle = "#079641"; ctx.textAlign = 'center'; //loop through the players array and render each one for(var i = 0; i < client_player_list.length; i++) { //if the player is_it, render them as red if(client_player_list[i].is_it) { ctx.fillStyle = "#8F0E0E"; ctx.fillRect(client_player_list[i].x, client_player_list[i].y, 20, 20); //draw the players name above them ctx.fillStyle = "#FFF"; ctx.font="15px Arial"; ctx.fillText(client_player_list[i].name, client_player_list[i].x + 8, client_player_list[i].y - 3); continue; } //if the player !is_it, render them as green ctx.fillStyle = "#079641"; ctx.fillRect(client_player_list[i].x, client_player_list[i].y, 20, 20); //draw the players name above them ctx.fillStyle = "#FFF"; ctx.font="15px Arial"; ctx.fillText(client_player_list[i].name, client_player_list[i].x + 8, client_player_list[i].y - 3); } //when the server sends an update, replace the current players array with the one that the server just sent socket.on('sv_update', function(players) { client_player_list = players; }); }; //main loop var main = function() { setInterval(function() { update(); render(); }, 1000/60); }; main(); //trigger the disconnect event when a page refreshes or unloads $(window).bind('beforeunload', function() { socket.emit('disconnect'); }); }); 

下面,我已经包含了我的游戏的app.js文件(服务器端脚本)。 我不确定问题出在哪里,所以我想我只是把整个事情发布。

 var express = require('express'); var http = require('http'); var io = require('socket.io', { rememberTransport: false, transports: ['WebSocket', 'Flash Socket', 'AJAX long-polling'] }); var app = express(); var server = http.createServer(app); server.listen(8080); app.use(express.static('public')); io = io.listen(server); //Declare variables for working with the client-side var player_speed = 5; var player_size = 20; var vel_increment = 0.5; var canvas_height = 480; var canvas_width = 512; //Declare list of players connected var players = []; io.sockets.on('connection', function(socket) { var socket_id = socket.id; var player_index, player_exists = false; var this_player; var check_bounds = function() { //Keep player in the canvas if(this_player.y < 0) this_player.y = 0; if(this_player.y + player_size > canvas_height) this_player.y = canvas_height - player_size; if(this_player.x < 0) this_player.x = 0; if(this_player.x + player_size > canvas_width) this_player.x = canvas_width - player_size; //Keep velocity between -5 and 5 if(this_player.vely > player_speed) this_player.vely = player_speed; if(this_player.velx > player_speed) this_player.velx = player_speed; if(this_player.vely < -player_speed) this_player.vely = -player_speed; if(this_player.velx < -player_speed) this_player.velx = -player_speed; }; var sv_update = function() { io.sockets.emit('sv_update', players); if(player_exists) { if(players.length == 1) this_player.is_it = true; check_bounds(); } }; //When a client connects, add them to players[] //Then update all clients socket.on('init_client', function(player) { player.id = socket.id; players.push(player); for(var i = 0; i < players.length; i++) if(players[i].id == socket_id) player_index = i; player_exists = true; this_player = players[player_index]; sv_update(); socket.emit('load_players', players); console.log(players); }); //====================CHAT==========================// var address = socket.request.connection.remoteAddress; socket.on('new user', function(data, callback) { if(player_exists) { this_player.name = data; console.log(address + " has connected as '" + data + "'."); callback(); } }); socket.on('send message', function(data) { io.sockets.emit('broadcast', this_player.name, data); }); //====================CHAT==========================// //if player is_it and is within another player, hitting 'j' will make the other player is_it. socket.on('tag', function() { if(player_exists) { for(var i = 0; i < players.length; i++) { if((this_player.x + player_size >= players[i].x && this_player.x + player_size <= players[i].x + player_size )|| (this_player.x <= players[i].x + player_size && this_player.x + player_size >= players[i].x)) if((this_player.y + player_size >= players[i].y && this_player.y + player_size <= players[i].y + player_size )|| (this_player.y <= players[i].y + player_size && this_player.y + player_size >= players[i].y)) { if(this_player.is_it) { this_player.is_it = false; players[i].is_it = true; } } } sv_update(); } }); //Gather key input from users... socket.on('up', function() { if(player_exists) { this_player.y -= player_speed; sv_update(); } }); //Gather key input from users... socket.on('down', function() { if(player_exists) { this_player.y += player_speed; sv_update(); } }); //Gather key input from users... socket.on('left', function() { if(player_exists) { this_player.x -= player_speed; sv_update(); } }); //Gather key input from users... socket.on('right', function() { if(player_exists) { this_player.x += player_speed; sv_update(); } }); //When a player disconnects, remove them from players[] //Then update all clients socket.on('disconnect', function() { for(var i = 0; i < players.length; i++) { if(players[i].id == socket.id) { players.splice(i, 1); } } sv_update(); }); }); 

————————————————– ——-编辑—————————————— ————————我把RuslanasBalčiūnas的build议是把客户端中的sv_update处理程序移出渲染函数。 这阻止了玩家落后,但新的问题是,服务器没有发送足够的更新让所有的玩家在任何给定的客户端stream动。 每个客户似乎都在为自己的顺利运作,但其他客户看到他们作为起伏/落后。

这里是更新的代码:

客户:

 $(document).ready(function() { var socket = io.connect(); var canvas = document.getElementById("canvas_html"); var ctx = canvas.getContext("2d"); canvas.width = 512; canvas.height = 480; document.body.appendChild(canvas); var player = { id: '', name: '', is_it: false, x: canvas.width / 2, y: canvas.height / 2, velx: 0, vely: 0 }; var client_player_list = []; socket.on('load_players', function(players) { client_player_list = players; }); var keysDown = {}; addEventListener('keydown', function(e) { keysDown[e.keyCode] = true; }, false); addEventListener('keyup', function(e) { delete keysDown[e.keyCode]; }, false); //take input from keys and send input to server var update = function() { if(87 in keysDown)//player holding w socket.emit('input', 'up'); if(83 in keysDown)//player holding s socket.emit('input', 'down'); if(65 in keysDown)//player holding a socket.emit('input', 'left'); if(68 in keysDown)//player holding d socket.emit('input', 'right'); if(74 in keysDown) socket.emit('input', 'tag'); }; //render all players, update players when server updates var render = function() { //ctx.clearColor = "rgba(0, 0, 0, .3)"; ctx.clearRect( 0, 0, canvas.width, canvas.height); ctx.fillStyle = "#079641"; ctx.textAlign = 'center'; for(var i = 0; i < client_player_list.length; i++) { if(client_player_list[i].is_it) ctx.fillStyle = "#8F0E0E"; else ctx.fillStyle = "#079641"; ctx.fillRect(client_player_list[i].x, client_player_list[i].y, 25, 25); ctx.fillStyle = "#FFF"; ctx.font="15px Arial"; ctx.fillText(client_player_list[i].name, client_player_list[i].x + 8, client_player_list[i].y - 3); } }; socket.on('sv_update', function(players) { client_player_list = players; }); //main loop var main = function() { setInterval(function() { update(); render(); }, 1000/60); }; main(); //---- Chat stuff ---- var toggle = 1; $('#users').fadeIn(1000); $('#name_field').focus(); $('#user_form').submit(function(e) { console.log('ezpz'); e.preventDefault(); socket.emit('init_client', player, $('#name_field').val(), function() { $('#users').fadeOut('slow'); window.setTimeout(function(){$('#chat').fadeIn('slow');$('#canvas_html').fadeIn('slow');$('#info').fadeIn('slow')}, 1000); }); }); $('#desk').submit(function(e) { e.preventDefault(); socket.emit('send message', $('#message').val()); $('#message').val(''); }); socket.on('broadcast', function(name, data) { $('#message_window').append('<p class="p' + toggle + '">' + name + ": " + data + '</p>'); $('#message_window')[0].scrollTop = $('#message_window')[0].scrollHeight; if(toggle == 1) toggle = 2; else toggle = 1; }); //trigger the disconnect event when a page refreshes or unloads $(window).bind('beforeunload', function() { socket.emit('disconnect'); }); }); 

服务器:

 var express = require('express'); var http = require('http'); var io = require('socket.io', { rememberTransport: false, transports: ['WebSocket', 'Flash Socket', 'AJAX long-polling'] }); var app = express(); var server = http.createServer(app); server.listen(8080); app.use(express.static('public')); io = io.listen(server); //Declare variables for working with the client-side var player_speed = 5; var player_size = 25; var canvas_height = 480; var canvas_width = 512; //Declare list of players connected var players = []; io.sockets.on('connection', function(socket) { var socket_id = socket.id; var player_index, this_player, player_exists = false; //When a client connects, add them to players[] //Then update all clients socket.on('init_client', function(player, name, callback) { player.id = socket.id; players.push(player); for(var i = 0; i < players.length; i++) if(players[i].id == socket_id) player_index = i; player_exists = true; this_player = players[player_index]; this_player.name = name; callback(); sv_update(); socket.emit('load_players', players); }); socket.on('send message', function(data) { io.sockets.emit('broadcast', this_player.name, data); }); //Gather key input from users... socket.on('input', function(key) { if(player_exists) { if(key == 'up') this_player.y -= player_speed; else if(key == 'down') this_player.y += player_speed; else if(key == 'left') this_player.x -= player_speed; else if(key == 'right') this_player.x += player_speed; else if(key == 'tag') for(var i = 0; i < players.length; i++) if(can_tag(players[i])) { this_player.is_it = false; players[i].is_it = true; } sv_update(); } }); //When a player disconnects, remove them from players[] //Then update all clients socket.on('disconnect', function() { for(var i = 0; i < players.length; i++) if(players[i].id == socket.id) players.splice(i, 1); sv_update(); }); var check_bounds = function() { //Keep player in the canvas if(this_player.y < 0) this_player.y = 0; if(this_player.y + player_size > canvas_height) this_player.y = canvas_height - player_size; if(this_player.x < 0) this_player.x = 0; if(this_player.x + player_size > canvas_width) this_player.x = canvas_width - player_size; }; var sv_update = function() { io.sockets.emit('sv_update', players); if(player_exists) { if(players.length == 1) this_player.is_it = true; check_bounds(); } }; var can_tag = function(target) { if(this_player.x < target.x + player_size && this_player.x + player_size > target.x && this_player.y < target.y + player_size && player_size + this_player.y > target.y && this_player.is_it) return true; } sv_update(); }); 

你的帮助将不胜感激:)

从客户端的渲染函数移动到代码下面。

 //when the server sends an update, replace the current players array with the one that the server just sent socket.on('sv_update', function(players) { client_player_list = players; });