本文介绍了如何在 Socket.io、Nodejs 中为每个房间设置计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用 socket.io 和 nodejs 创建一个回合制游戏.有一些房间,每个 房间应该有自己的计时器,因为玩家的动作有时间限制,所以我想知道我该如何处理这,也许为每个房间设置一个计时器是愚蠢的方式还是不切实际的?!!!我不知道 .请指导我:)

I want to create a turn based game with socket.io and nodejs . There is some rooms and every room should has it's own timer because players have time limitation for their movements so I want to know how can I handle this , maybe it's stupid way or also impractical to set a timer for each room ?!!! I don't know . please guide me :)

有我的玩家移动和其他代码:

There is my code for player movement and other things :

var server = require('http').Server();
var socketIO = require('socket.io');
var io = socketIO.listen(server);


//var redis = require("redis"),
//client = redis.createClient();
var Room = require("./Room.js").Room;

var server_port = process.env.OPENSHIFT_NODEJS_PORT || 8080;
var server_ip_address = process.env.OPENSHIFT_NODEJS_IP || '127.0.0.1';


var connected_players = 0;
var players = {};
var rooms = {};

io.sockets.on('connection', function(socket){
  connected_players = connected_players + 1;
  console.log("New Player Connected :) \n" + "Total Number of Connected Players = " + connected_players );
  players[socket.id] = socket;
  socket.emit("sessionEv", {"session_id" : socket.id});
  socket.on("joining", function(data){


//SOME CODE FOR JOINING !!

  });

  socket.on('disconnect', function(){

      console.log("disconnect" + this.id + " ; playerid = " + connected_players);
      delete players[socket.id];

      connected_players = connected_players - 1 ;


  });

  socket.on("move", function(data){
    var tempRoom = rooms[socket.room_name];
    var current_turn = tempRoom.Turn;
    console.log("on Move :" + data.handId + ":" + data.moveType);
    if (current_turn == data.handId ){ 
      console.log("correct move from :" + data.handId);
      //Calculating next turn;
      if(data.moveType == 1){
        while(true){
          current_turn = current_turn + tempRoom.Clock_Flag ;

          if(current_turn > tempRoom.Max*2){
            current_turn = current_turn%(tempRoom.Max * 2);
          }

          if(current_turn === 0){
            current_turn = tempRoom.Max * 2 ;
          }

          if(!checkLoseHand(current_turn, tempRoom)){
            break;
          }
        }
      }
      if(data.moveType === 2){
        tempRoom.Clock_Flag = tempRoom.Clock_Flag * - 1;
        while(true){
          current_turn = current_turn + tempRoom.Clock_Flag ;

          if(current_turn > tempRoom.Max*2){
            current_turn = current_turn%(tempRoom.Max * 2);
          }


          if(current_turn === 0){
            current_turn = tempRoom.Max * 2 ;

          }
          if(!checkLoseHand(current_turn, tempRoom)){
            break;
          }
        }
      }
      if(data.moveType == 3 ){
        while(true){
          current_turn = current_turn + tempRoom.Clock_Flag ;

          if(current_turn > tempRoom.Max * 2){
            current_turn = current_turn%(tempRoom.Max * 2);
          }


          if(current_turn === 0){
            current_turn = tempRoom.Max * 2 ;
          }

          if(!checkLoseHand(current_turn, tempRoom)){
            break;
          }
        }  
        while(true){
          current_turn = current_turn + tempRoom.Clock_Flag ;

          if(current_turn > tempRoom.Max * 2){
            current_turn = current_turn%(tempRoom.Max * 2);
          }


          if(current_turn === 0){
            current_turn = tempRoom.Max * 2 ;
          }

          if(!checkLoseHand(current_turn, tempRoom)){
            break;
          }

        }





    }
    tempRoom.Turn = current_turn;
    var d = new Date();
    var n = d.getSeconds();
    tempRoom.lastmove = n;
    tempRoom.start = true;
    console.log("next turn = " + current_turn);
    io.sockets.in(socket.room_name).emit("move", {"handId" : data.handId , "moveType" : data.moveType, "turn" : current_turn});




  }
    else{
      io.sockets.in(socket.room_name).emit('lose', {"handId" : data.handId} );
      socket.broadcast.to(socket.room_name).volatile.emit("move", {"handId" : data.handId , "moveType" : data.moveType, "turn" : current_turn});
      tempRoom.losers_hand.push(data.handId);

    }
  //}
  });

});

server.listen(server_port , server_ip_address);



playerById =  function(id) {
  var i;
  for (i = 0; i < players.length; i++) {
    if (players[i].id == id)
      return players[i];
  }

  return false;
};

checkLoseHand = function(id, tempRoom ){
  for (i = 0; i < tempRoom.losers_hand.length; i++) {
    if( tempRoom.losers_hand[i] == id){
      return true; 
    }

  }
  return false;
};

function get_users_by_room(nsp, room) {
  var users = [];
  for (var id in io.of(nsp).adapter.rooms[room]) {
    users.push(io.of(nsp).adapter.nsp.connected[id]);
  }
  return users.length;
}

setInterval(function(){
    var d = new Date();
    for (var key in rooms)
    {
        console.log(key);
        console.log(d.getSeconds());
        console.log(rooms[key].lastmove);
        if(Math.abs(d.getSeconds() - rooms[key].lastmove) > 5 && rooms[key].start )
        {
            io.sockets.in(key).emit('lose', {"handId" : rooms[key].Turn } );
            //inja bayad turn badi ham ersal she .
        }
    } 
    //console.log("here");
}, 1000);

当收到 MOVE EVENT 时,我将该移动发送给其他玩家并计算下一回合(现在计时器应该开始为当前回合玩家计算秒数)如果玩家进入允许的时间什么都不会发生,但如果没有,他必须离开游戏室.

when a MOVE EVENT receive I send that move to other players and calculating next turn (NOW timer should start to count seconds for current turn player) and if player move in allowed time nothing happen but if not he must leave the game room .

正如你所看到的,我在代码末尾写了一个 SetInteval 函数.这个功能只是每秒检查每个房间的时间限制,如果房间太多,我认为服务器负载很重所以我正在寻找更好的方法.

And as you can see I wrote a SetInteval function at the end of the code . This function just check that time limitation for every room in every second that I think it have heavy load on server if there are too many rooms so I'm seeking a better way .

谢谢

推荐答案

如果您打算扩展到 Node.js,如果您想要可扩展的精确计时,setInterval 可能不是理想的解决方案.

If you intend to scale to Node.js and setInterval is likely not an ideal solution if you want scalable precise timings.

现在遍历所有房间可能没问题,因为在此阻塞迭代导致性能问题之前,您将需要大量房间.

Iterating through all the rooms will likely be fine for now, as you will need a very large number of rooms before this blocking iteration causes performance issues.

缓解这些问题的一些方法是水平扩展 Node 集群并在多个 Node 进程之间分配房间,或者通过检查移动事件侦听器中的移动是否无效来实现对无效移动的延迟检查,而不是让一个 setInterval.

Some ways of mitigating those issues would be scaling your Node cluster horizontally and distributing the rooms across multiple Node processes, or implementing a lazy-check for invalid moves by checking if a move is invalid within the move event listener, rather than having a setInterval.

这篇关于如何在 Socket.io、Nodejs 中为每个房间设置计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-26 16:59