簡體   English   中英

node.js多人html5游戲中的延遲越來越高

[英]increasingly high latency in node.js multiplayer html5 game

我使用node.js創建了一個網頁,表達了js,socket.io和jquery。 這是一個簡單的游戲,其中玩家加入,給自己一個名字,然后在頁面上的畫布周圍移動自己(正方形)。 我注意到的是:當更多的人加入游戲並四處走動時,就會有足夠的滯后讓游戲無法播放(只有三個人連接。兩個人並沒有多少時間)。 我無法弄清楚這是服務器端延遲還是客戶端(這是我的第一個處理多人游戲的項目)。 我正在服務器上進行所有位置計算,並將所有玩家對象的數組發送回每個套接字,以便每個客戶端都可以呈現所有玩家。 客戶端僅發送輸入並繪制玩家。

這是游戲的客戶端腳本。 這是我處理輸入和渲染的地方。

 $(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的建議,將客戶端中的sv_update處理程序移出render函數。 這會阻止玩家滯后,但新問題是服務器沒有為所有玩家發送足夠的更新,以便在任何給定的客戶端上流暢地移動。 每個客戶似乎都在順利運行,但其他客戶認為它們不穩定/滯后。

這是更新的代碼:

客戶:

 $(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;
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM