javascript - tutorial - Arreglar lag en el juego multijugador socket.io



socket.io https (1)

Estoy tratando de reproducir un juego simple en multijugador (máximo 2 jugadores). Estoy usando javascript, node.js, socket.io y express para hacer eso. Todo fue bien, pero desde que activé el ciclo principal en el servidor y en los clientes, el juego comenzó de manera muy fluida, pero después de 2 o 3 segundos, el retraso y la congelación aumentan exponencialmente. Sé que esto es para el infinito del oyente del evento que llamo en los ciclos infinitos ..... ¿Cómo puedo evitar eso?

Aquí está el ciclo del servidor:

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

    });
}

Aquí está el ciclo del cliente:

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

}

Como usted mismo dijo, a primera vista, mi opinión es que los oyentes podrían ser los culpables. Si updateGameArea () en el lado del cliente es el método repetido para actualizar el juego, cada vez que ocurre la actualización, está agregando un oyente al evento socket. Que es, después de por ej. 5 iteraciones a través de ese método de actualización, si un mensaje llega a través del socket, ejecuta el código dedicado 5 veces.

Solo necesita decirle una vez al socket cómo debe manejar un mensaje determinado (lo mismo para cualquier oyente), y puede hacerlo en la configuración, sin necesidad de ejecutarlo una y otra vez con el ciclo.

Aquí hay un intento de refactorizar el código que ha publicado para que coincida con lo que estoy diciendo. Observe cómo utilizo booleanos u otras variables cuando se recibe un mensaje en el lado del cliente para alertar al método updateGameArea () de que se debe realizar alguna tarea (después de lo cual la variable / boolean se reinicia y espera el mensaje nuevamente si es necesario).

Esto es asumiendo que ya has inicializado una variable 'socket'.

Espero no haber roto nada.

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




server