简体   繁体   English

修复socket.io多人游戏中的滞后问题

[英]Fix lag in socket.io multiplayer game

i'm trying to reproduce a simple game in multiplayer (max 2 players).I'm using javascript,node.js,socket.io and express to do that. 我试图在多人游戏中重现一个简单的游戏(最多2个玩家)。我正在使用javascript,node.js,socket.io和express来做到这一点。 It was all good but from when i activated the main cycle in the server and in the clients the game begin so fluid but after 2 or 3 second the lag and the freeze increase exponentially. 这一切都很好,但是当我在服务器和客户端激活主循环时,游戏开始如此流畅,但在2或3秒之后,滞后和冻结呈指数增长。 I know that this is for the infinity of event listener that i call in the infinite cycles.....How can i avoid that? 我知道这是为了我在无限循环中调用的无限事件监听器......我怎么能避免这种情况?

Here's the cycle of the server: 这是服务器的循环:

function updateGameArea(){

    frameNo+=1;  
    if (players.length < 2){
            if (players[0]!=socket.id){
                console.log('Logged',socket.id);
                players.push(socket.id);
            }

    }
    for (i=0;i<players.length;i++){
        if (socket.id==players[i]){

            var c=i;
        }
    }
    if (!id1 || !id0){
    socket.emit('id',{'id':c});
    }




    socket.on('info',(data)=>{

        if (data.c==0){

            myGamePiece=data.x;
            info0=true;
        }
        else {

            yourGamePiece=data.x;
            info1=true;
        }
    })

    socket.on('id0',()=>{
        id0=true;

    })

    socket.on('id1',()=>{

        id1=true;
    })


    if (id0 & id1 & info0 & info1){
    socket.emit('go');
    socket.emit('frame',{'f':frameNo});
    socket.on('newpos',(data)=>{
        console.log('Wroking');
        if (data.c==0){
            myGamePiece.newPos();
            socket.emit('info0',{'o':myGamePiece.gravitySpeed,'x':myGamePiece.x,'y':myGamePiece.y,'sy':myGamePiece.speedY});
        }
        else if(data.c==1){
            yourGamePiece.newPos();
            socket.emit('info1',{'o':yourGamePiece.gravitySpeed,'x':yourGamePiece.x,'y':yourGamePiece.y,'sy':yourGamePiece.speedY});
        }
    })

    socket.on('numob',(data)=>{
       myObstacles[myObstacles.length-1]=data.i;
       myObstacles[myObstacles.length-1]=data.l;
    })

    if (frameNo ==1 || everyinterval(150)){
        socket.emit('createob');                          
    }

    for (i=0;i<myObstacles.length;i+=1){
        myObstacles[i].x += -1 ;
        socket.emit('agobj',{'i':i});
    }

    for (i=0;i<myObstacles.length; i+=1){
        if (myGamePiece.crashWith(myObstacles[i])){
            socket.emit('dead0');
        }
        else if(yourGamePiece.crashWith(myObstacles[i])){
            socket.emit('dead1');
        }   
    }


    socket.on('push',(data)=>{
        var l=speed(data.id);
        if (l=0){
            var id=0;
            y=-3.5
            socket.emit('pushinf',{'y':y,'id':id})
        }
        else{
           var  id=1;
            y=-3.5;
            socket.emit('pushinf',{'y':y,'id':id})
        }
    })

    socket.on('disconnect',() => {
        console.log('id attivo',socket.id);
        console.log('disconnected!',socket.id);
        for (i=0;i<players.length;i++){
            if (players[i]==socket.id){
                players.splice(i,1);
            }   
        }

    });
}

Here's the client cycle: 这是客户周期:

function updateGameArea(){

    socket.on('connect', function() {
            console.log("connected from the client side");
    });

    socket.on('id',function(data){
        console.log('server sent info id to me')
      console.log(data.id)
        var id=data.id;
        console.log(id);
        if (id==0){
        socket.emit('id0');
        }
        else {
            socket.emit('id1');
        }   
        socket.emit('info',{'x':myGamePiece,'c':id});
    });
    socket.on('go',function(){
        go=true;
    })
    if (go){
            socket.on('frame',function(data){
                frameNo=data.f;
            })
            socket.on('createob',function(){
              x=myGameArea.canvas.width;
              minHeight=60;
              maxHeight=140;
              height=Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);
              minGap=60;
              maxGap=90;
              var gap=Math.floor(Math.random()*(maxGap-minGap+1)+minGap);     
              myObstacles.push(new component(10,height,"green",x,0));
              myObstacles.push(new component(10,x-height-gap,"green",x,height + gap));
              socket.emit('numob',{'l':myObstacles[myObstacles.length],'i':myObstacles[myObstacles.length-1]})
             });
            socket.emit('newpos',{'c':id});
            socket.on('info0',function(data){
                if (id==0){
                    myGamePiece.gravitySpeed=data.o
                    myGamePiece.x=data.x;
                    myGamePiece.y=data.y;
                    myGamePiece.speedY=data.sy;
                }
                else{
                  yourGamePiece.gravitySpeed=data.o;
                  yourGamePiece.x=data.x;
                  yourGamePiece.y=data.y;
                  yourGamePiece.speedY=data.sy;
                }
            })
            socket.on('info1',function(data){
              if (id==1){
                    myGamePiece.gravitySpeed=data.o;
                    myGamePiece.x=data.x;
                    myGamePiece.y=data.y;
                    myGamePiece.speedY=data.sy;
                }
                else{
                  yourGamePiece.gravitySpeed=data.o;
                  yourGamePiece.x=data.x;
                  yourGamePiece.y=data.y;
                  yourGamePiece.speedY=data.sy;
                }
            })

            socket.on('dead0',function(){
              if (id==0){
                myGameArea.stop();
                mySound.play();
                GameO=true;
              }
              else{
                mySound.play();
                yourGamePiece.gravitySpeed==3.5;
              }
            })
            socket.on('dead1',function(){
              if (id==1){
                myGameArea.stop();
                mySound.play();
                GameO=true;
              }
              else{
                mySound.play();
                yourGamePiece.gravitySpeed==3.5;
              }
            })
            socket.on('agobj',function(data){
              myObstacles[data.i].x+=1;
            })
            myGameArea.canvas.addEventListener('click',function(){
              socket.emit('push',{'id':id});
              if (mSoundw.sound.pausedy) {
                        mySoundw.sound.play();
                    }
                    else{
                        mySoundw.sound.currentTime = 0
                    }

              socket.on('pushinf',function(data){
                    if (id==data.c){
                          myGamePiece.gravitySpeed=y;
                          myGamePiece.image.src="angry.png";
                    }
                    else{
                          yourGamePiece.gravitySpeed=y;
                          yourGamePiece.image.src="angryb.png";
                    }
              })
            },false)
    }

}

Like you said yourself, at first sight, my opinion is that the listeners might be the culprits. 就像你自己说的那样,乍一看,我的观点是听众可能是罪魁祸首。 If updateGameArea() on the client side is the method repeated to update the game, every time the update happens, you are adding a listener to the socket event. 如果客户端上的updateGameArea()是重复更新游戏的方法,则每次更新发生时,您都会向套接字事件添加一个侦听器。 Which is, after for ex. 也就是说,在前面。 5 iterations through that update method, if one message arrives through the socket, it runs the dedicated code 5 times. 通过该更新方法进行5次迭代,如果一条消息通过套接字到达,它将运行专用代码5次。

You only need to tell once to the socket how it should handle a certain message (same for any listener), and you can do that at setup, no need to run it over and over with the loop. 您只需要告诉套接字它应该如何处理某个消息(对于任何侦听器都是如此),并且您可以在安装时执行此操作,无需在循环中反复运行它。

Here's an attempt at refactoring the code you've posted to go along with what I'm saying. 这是尝试重构您发布的代码以及我所说的内容。 Notice how I use booleans or other variables when a message is received on the client side to alert the updateGameArea() method that some task needs to be performed (after which task the boolean/variable resets and waits for the message again if necessary). 注意在客户端收到消息时如何使用布尔值或其他变量来警告updateGameArea()方法需要执行某些任务(在此任务之后布尔/变量重置并在必要时再次等待消息)。

This is assuming that you already have initialized a variable 'socket'. 这假设您已经初始化了一个变量'socket'。

Hope I didn't break anything. 希望我没有破坏任何东西。

var id = null;//as long as it's null, no message is emitted from the client
var go;
var createob = false;
var clicked = false;

socket.on('connect', function() {
    console.log("connected from the client side");
});

socket.on('id',function(data){
    console.log('server sent info id to me')
    console.log(data.id)
    id = data.id;//set the id
    console.log(id);
});

socket.on('go',function(){
    go = true;
});

socket.on('frame',function(data){
    if (go) {
        frameNo=data.f;
    }
});

socket.on('createob',function(){
    if (go) {
        createob = true;
    }
});

socket.on('info0',function(data){
    if (id==0){
        myGamePiece.gravitySpeed=data.o
        myGamePiece.x=data.x;
        myGamePiece.y=data.y;
        myGamePiece.speedY=data.sy;
    }
    else{
        yourGamePiece.gravitySpeed=data.o;
        yourGamePiece.x=data.x;
        yourGamePiece.y=data.y;
        yourGamePiece.speedY=data.sy;
    }
});

socket.on('info1',function(data){
    if (id==1){
          myGamePiece.gravitySpeed=data.o;
          myGamePiece.x=data.x;
          myGamePiece.y=data.y;
          myGamePiece.speedY=data.sy;
      }
      else{
          yourGamePiece.gravitySpeed=data.o;
          yourGamePiece.x=data.x;
          yourGamePiece.y=data.y;
          yourGamePiece.speedY=data.sy;
      }
});


socket.on('dead0',function(){
    if (id==0){
        myGameArea.stop();
        mySound.play();
        GameO=true;
    }
    else{
        mySound.play();
        yourGamePiece.gravitySpeed==3.5;
    }
});

socket.on('dead1',function(){
    if (id==1){
        myGameArea.stop();
        mySound.play();
        GameO=true;
    }
    else{
        mySound.play();
        yourGamePiece.gravitySpeed==3.5;
    }
});

socket.on('agobj',function(data){
    myObstacles[data.i].x+=1;
});

myGameArea.canvas.addEventListener('click',function(){
    clicked = true;
    socket.emit('push',{'id':id});
    if (mSoundw.sound.pausedy) {
        mySoundw.sound.play();
    }
    else{
        mySoundw.sound.currentTime = 0
    }
},false);

socket.on('pushinf',function(data){
    if (clicked) {//I was not sure if you need this to run only when there's been click. If it's independent of the click then remove this condition and the 'clicked = false' below
        if (id==data.c){
              myGamePiece.gravitySpeed=y;
              myGamePiece.image.src="angry.png";
        }
        else{
              yourGamePiece.gravitySpeed=y;
              yourGamePiece.image.src="angryb.png";
        }
        clicked = false;
    }  
})

function updateGameArea(){
    //whenever the 'id' message from the server arrives, it sets the id;
    //whenever the game updates again it sees a non-null id and emits the
    //corresponding message below, then sets the id to null again
    if (id != null) {
        if (id==0){
            socket.emit('id0');
        }
        else {
            socket.emit('id1');
        }   
        socket.emit('info',{'x':myGamePiece,'c':id});
        id = null;
    }


    if (go){
        if (createob) {
            x=myGameArea.canvas.width;
            minHeight=60;
            maxHeight=140;
            height=Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);
            minGap=60;
            maxGap=90;
            var gap=Math.floor(Math.random()*(maxGap-minGap+1)+minGap);     
            myObstacles.push(new component(10,height,"green",x,0));
            myObstacles.push(new component(10,x-height-gap,"green",x,height + gap));
            socket.emit('numob',{'l':myObstacles[myObstacles.length],'i':myObstacles[myObstacles.length-1]})

            /*
            Depending on if you only want this body to be executed if and only if the 'createob' message has been received,
            you may want to reinitialize the boolean
            */
            createob = false;//comment this out if this body should run from the moment the message is received until further in the game, without depending on the createob message.
        }
        socket.emit('newpos',{'c':id});
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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