我使用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');
});
});
SERVER:
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();
});
非常感谢您的帮助:)
答案 0 :(得分:0)
从客户端的渲染功能移动下面的代码。
//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;
});