node.jsexpresssocket.ioserverside-javascript

SocketIO Identify what user disconnected


I am making a simple Node.js game that uses Express, Socket.io, and an Http server. All of the users are stored in a multidimensional object on the server. This is how the server-side code works:

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);

Here is the client-side code for connection:

var id;
$('#playbutton').click(function() {
  var name = document.getElementById('name').value;
  id = Math.floor(Date.now() * Math.random());
  socket.emit('new player', id, name);
});

On the client-side, in the update loop, when the game wants to tell the server your input, it emits your input like so:

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);

The function to update players just draws players based on the player list sent from the server.

My problem is that when a user disconnects, they stay in the player list. I don't understand how I should go about fixing this. I identify users by getting the ID they send from the client, but I can't get the user's id when they disconnect.

There is a lot more code, but I tried to only include the code that I thought was necessary. I am willing to include more code if that is needed.


Solution

  • You could just store the id value in the parent scope, which the disconnect event handler would have access to:

    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];
      });
    };