我正在制作一个简单的Node.js游戏,它使用Express,Socket.io 和Http服务器。所有用户都存储在服务器上的多维对象中。这是服务器端代码的工作方式:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.use(express.static(__dirname + '/'));
var playerList = {};
createPlayer = function(array,width,height,spdx,spdy,x,y,color,name,id) {
var player = {
width:width,
height:height,
spdx:spdx,
spdy:spdy,
x:x,
y:y,
wKeyDown:false,
aKeyDown:false,
sKeyDown:false,
dKeyDown:false,
color:color,
name:name,
id:id
}
array[id] = player;
}
io.on('connection', function(socket) {
socket.on('new player', function(id, name) {
id = parseInt(id);
if (!playerList[id]) {
createPlayer(playerList,25,25,4,4,Math.round(Math.random() * 800),Math.round(Math.random() * 600),randomColor(),name,id);
}
socket.on('pressW', function(id, keyDown) {
playerList[id].wKeyDown = keyDown;
});
socket.on('pressA', function(id, keyDown) {
playerList[id].aKeyDown = keyDown;
});
socket.on('pressS', function(id, keyDown) {
playerList[id].sKeyDown = keyDown;
});
socket.on('pressD', function(id, keyDown) {
playerList[id].dKeyDown = keyDown;
});
});
socket.on('disconnect', function() {
});
};
sendPlayerList = function() {
//newPlayerList is used to prevent client from seeing other users IDs
var newPlayerList = {};
var count = 0;
for (var q in playerList) {
player = {
x:playerList[q].x,
y:playerList[q].y,
width:playerList[q].width,
height:playerList[q].height,
color:playerList[q].color,
name:playerList[q].name,
}
newPlayerList[count] = player;
count++;
}
io.emit('edit playerlist', newPlayerList);
}
SPLInterval = setInterval(sendPlayerList, 1000);
以下是用于连接的客户端代码:
var id;
$('#playbutton').click(function() {
var name = document.getElementById('name').value;
id = Math.floor(Date.now() * Math.random());
socket.emit('new player', id, name);
});
在客户端,在更新循环中,当游戏想要告诉服务器你的输入时,它会发出你的输入,如下所示:
update = function() {
ctx.clearRect(0,0,canvas.width,canvas.height);
if (document.hasFocus()) {
socket.emit('pressD', id, dKeyDown);
socket.emit('pressS', id, sKeyDown);
socket.emit('pressA', id, aKeyDown);
socket.emit('pressW', id, wKeyDown);
}else{
socket.emit('pressD', id, false);
socket.emit('pressS', id, false);
socket.emit('pressA', id, false);
socket.emit('pressW', id, false);
}
clientUpdatePlayer();
updatePlayers();
}
}
var updateInterval = setInterval(update, 31.25);
更新玩家的功能只是根据服务器发送的玩家列表绘制玩家。
我的问题是,当用户断开连接时,他们会留在玩家列表中。我不明白我应该如何解决这个问题。我通过获取用户从客户端发送的 ID 来识别用户,但在用户断开连接时无法获取用户的 ID。
还有更多的代码,但我试图只包含我认为必要的代码。如果需要,我愿意包含更多代码。
您可以将id
值存储在父作用域中,disconnect
事件处理程序将有权访问该范围:
io.on('connection', function(socket) {
var userId;
socket.on('new player', function(id, name) {
userId = id = parseInt(id);
// ...
});
socket.on('disconnect', function() {
delete playerList[userId];
});
};
也许我参加聚会迟到了,但我被类似的东西困住了,发现它很难,这可能会帮助某人。
检测用户是否断开连接的最佳方法是首先在套接字会话中设置用户名。
发出时从客户端发送名称
socket.emit("newUser", username);
和在服务器上
socket.on('newUser',function (username) {
// we store the username in the socket session for this client
socket.username = username;
});
当用户断开连接时,在断开连接事件中找到它
socket.on('disconnect', function () {
var connectionMessage = socket.username + " Disconnected from Socket " + socket.id;
console.log(connectionMessage);
});
你可以从那里拿走它。
这对我有用:
在每个联机的新连接或用户上生成一个套接字 ID,将其添加到用户对象,并将其添加到所有联机用户的数组中。
const users = [];
io.on('connection', (socket) => {
const socketId = socket.id;
socket.on('user online', (data) => {
users.push({ ...data, socketId });
io.emit('view user online', user);
});
然后在 disconnect
中,使用 forEach
遍历数组中的每个对象,然后使用 for
遍历并delete
对象中的每个键:
socket.on('disconnect', () => {
users.forEach((user) => {
if (user.socketId === socket.id) {
for (const key in user) {
delete user[key];
}
}
});
logger(`A user has disconnected`);
});
});
});
调整到您想要的方式。
var users = [];
socket.on('newUser', (username) => {
users.push({
id: socket.id,
username: username
});
});
socket.on('disconnect', () => {
const presentUser = users.find(user => user.id == socket.id);
users = users.filter(user => user != presentUser);
});
我们可以使用套接字 ID 将数据作为引用存储在 playerList 中。 每当用户断开连接时,您都可以根据套接字ID从对象中删除元素
var playerList = {};
io.on("connection", socket => {
if (!Object.values(playerList).includes(playername) && playername != null) {
var U_data = {
[socket.id]: playername
};
playerList = { ...playerList, ...U_data };
}
socket.on("disconnect", function(e, id) {
console.log(socket.id);
delete playerList[socket.id];
io.emit("broadcast", Object.values(playerList));
});
}