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

时间:2016-07-07 07:34:12

标签: javascript node.js express socket.io server

我试图在多人游戏中重现一个简单的游戏(最多2个玩家)。我正在使用javascript,node.js,socket.io和express来做到这一点。 这一切都很好,但是当我在服务器和客户端激活主循环时,游戏开始如此流畅,但在2或3秒之后,滞后和冻结呈指数增长。我知道这是为了我在无限循环中调用的事件监听器的无限......我怎么能避免这种情况?

这是服务器的循环:

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

    });
}

这是客户周期:

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

}

1 个答案:

答案 0 :(得分:0)

就像你说的那样,乍一看,我的观点是听众可能是罪魁祸首。如果客户端上的updateGameArea()是重复更新游戏的方法,则每次更新发生时,您都会向套接字事件添加一个侦听器。也就是说,在前面。通过该更新方法进行5次迭代,如果一条消息通过套接字到达,它将运行专用代码5次。

你只需要告诉套接字它应该如何处理某个消息(对于任何监听器都是一样的),你可以在安装时这样做,不需要在循环中反复运行它。

这是尝试重构您发布的代码以及我所说的内容。注意在客户端收到消息时如何使用布尔值或其他变量来警告updateGameArea()方法需要执行某些任务(在此任务之后布尔/变量重置并在必要时再次等待消息)。

这假设你已经初始化了一个变量'socket'。

希望我没有破坏任何东西。

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