简体   繁体   中英

Socket.io receiving data from multiple sockets in Node

I started developing in Node just a couple of days ago. I'm currently developing an online game that uses Node as server-side application. This application simply provides the .html and .js files to the client and handles the logic of the game. I'm using Socket.io to exchange data with the clients. When a new client connects to the server through Socket.io the program looks for a room (array of objects containing the sockets for the two users and the game object that handles the logic) that has an empty space and places the user (registering the socket) in it. I've been able to correctly send to each client the position of the sprites, but I have a problem with retrieving data from each socket: If I try to send some data from the client to the server, that data flows through only one of the two sockets, no matter which client is sending that.

Initializing the room array

for(var i = 0; i < roomsNumber; i++) {
  //player1 and player 2 are going to store the sockets
  rooms[i] = { player1 : null, player2 : null, game: null};
}

Socket.io handling the connections

var io = require('socket.io')(server);

io.on('connection', function(socket){
  console.log("We have a new client: " + socket.id);
  insertPlayer(socket);

  socket.on('disconnect', function() {
    console.log("Client has disconnected: " + socket.id);
    removePlayer(socket);
  });
});

Adding the clients to rooms

function insertPlayer(socket) { //Check for an empty spot in a room
  for(var i = 0; i < rooms.length; i++) {
    if(!rooms[i].player1) {
      rooms[i].player1 = socket; //Register the socket to the room
      checkRooms();
      return;
    }
    if(!rooms[i].player2) {
      rooms[i].player2 = socket; //Register the socket to the room
      checkRooms();
      return;
    }
  }
}

Creating the Game object when a room if full (and destructing it when a player leaves)

function checkRooms() { //Checks if a room is full to initialize the game
  for(var i = 0; i < rooms.length; i++) {
    if(rooms[i].player1 && rooms[i].player2 && !rooms[i].game) {
      rooms[i].game = new Game([rooms[i].player1, rooms[i].player2]); //The constructor passes the sockets
      console.log('New game started');
    }
    if((!rooms[i].player1 || !rooms[i].player2) && rooms[i].game) {
      rooms[i].game.endGame();
      rooms[i].game = null;
      console.log('Game stopped');
    }
  }
}

Receiving data in the Game class

constructor(sockets) {
  this.sockets = sockets;
  this.snakes = [];
  var self = this;

  for(var i = 0; i < this.sockets.length; i++) {
    this.snakes[i] = new Snake(i*100 + 100, 200);
    var currentSnake = this.snakes[i];
    var currentSocket = this.sockets[i];

  currentSocket.on('keyPressed', function(data) {
    currentSnake.updateDirection(data); //Calls a Game method that updates the direction of the sprite 
    console.log(currentSocket.id + " - " + data);
  });
}

I see a problem with the currentSnake variable in your Game constructor. That variable is scoped to your whole constructor so there's only one variable there, but you're trying to have a separate variable for each player and that isn't working. Thus, every time you get the keyPressed message, you operation on the same snake, no matter which player the key came from.

If you're using node.js v6+, then change var currentSnake in that constructor to let currentSnake so that the variable is separately scoped to each invocation of the for loop.

constructor(sockets) {
  this.sockets = sockets;
  this.snakes = [];
  var self = this;

  for(var i = 0; i < this.sockets.length; i++) {
    this.snakes[i] = new Snake(i*100 + 100, 200);
    // change these to be declared with let so they are separately scoped 
    //   for each invocation of the for loop
    let currentSnake = this.snakes[i];
    let currentSocket = this.sockets[i];

    currentSocket.on('keyPressed', function(data) {
      currentSnake.updateDirection(data); //Calls a Game method that updates the direction of the sprite 
      console.log(currentSocket.id + " - " + data);
    });
  }
}

Or, if you are running an older version of node.js, switch to .forEach() to replace the for loop as this will also make a new separate scope for each invocation of the loop.

constructor(sockets) {
  this.sockets = sockets;
  this.snakes = [];
  var self = this;

  this.sockets.forEach(function(currentSocket, i) {
    this.snakes[i] = new Snake(i*100 + 100, 200);
    var currentSnake = this.snakes[i];

    currentSocket.on('keyPressed', function(data) {
      currentSnake.updateDirection(data); //Calls a Game method that updates the direction of the sprite 
      console.log(currentSocket.id + " - " + data);
    });
  });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM