Search code examples
javascriptgame-developmentrequestanimationframe

JavaScript Game run slowly over time


i'm coding a game in JS, witch run good, but with time, the FPS slow down. After search here, i think thiks that the problem can be from the load of images, but i don't know how to use the function to run the code after images are loaded. Furthermore my code are in a DOMContentLoaded addevenlistener. the problem can really provide from the load of images ? Thanks!

Here theire a slice of my code

function animate() {    
    ctx.resetTransform();
    ctx.translate(-(player.x - canvas.width / 2), -(player.y - canvas.height / 2)); //for center the character on the map
    ctx.drawImage(Images_array[1], 0, 0, canvasSize.width / 1.1, canvasSize.height / 1.1, 0, 0, canvasSize.width, canvasSize.height); //drawing the background
    // enterInHouse();
    drawSprite(Images_array[0], player.width * player.frameX, player.height * player.frameY, player.width, player.height, player.x, player.y, player.width * scale, player.height * scale) // drawing the sprite
    movePlayer() 
    handlePlayerFrame()
    // collisionRedbox()
    // displaGameboy()
    // if (inHouse === false) {
    //     createBluebox.enterInCollision(blackBoxs, player)    
    // }  
    window.requestAnimationFrame(animate); 
    }
    animate()
    window.addEventListener('resize', displayCanvas)

i loaded the images like this.

const playerSprite = new Image();
    playerSprite.src = "img/main_chara.png ";
    const background = new Image();
    background.src = "img/background.png";
    const office = new Image();
    office.src = "img/interieur_git.png";
    const retraining = new Image();
    retraining.src = 'img/reconversion.png';
    const contact = new Image();
    contact.src = 'img/contact_me.png';
    const grangeOne= new Image();
    grangeOne.src = 'img/grange.png'
    const house= new Image();
    house.src = 'img/maison.png'
    const bigHouse= new Image();
    bigHouse.src='img/maison_principale.png'

i can show you more of code if you want. Thanks a lot for helping me


Solution

  • You're binding on every drawing of your animation an eventlistner.

    window.addEventListener('resize', displayCanvas)
    

    So after 1 second at 60 fps you have 60 eventlisteners, after 2 seconds 120, after a minute 3600 event listeners, after ten minutes 36000

    Bind an eventhandler once, bind it outside of your animate() function.

    Also, looking at your code at https://maxlassort.github.io/MyWorld/index.js

    you have the function moveplayer() that you call on every frame.

    function movePlayer() {
            action_btnt.addEventListener('touchstart', function (e) {
                (actionBtn=true)
                e.stopPropagation();
            },{ passive: true })
           
            up.addEventListener('touchstart', function (e) {
                (movingUp=true)
                player.moving = true
                e.stopPropagation();
            },{ passive: true })
            up.addEventListener('touchend', function () {
                movingUp=false
                player.moving = false
            },{ passive: true })
            right.addEventListener('touchstart', function (e) {
                (movingRight=true)
                player.moving = true
                e.stopPropagation();
            },{ passive: true })
            right.addEventListener('touchend', function () {
                movingRight=false
                player.moving = false
            },{ passive: true })
            down.addEventListener('touchstart', function (e) {
                (movingDown=true)
                player.moving = true
                e.stopPropagation();
            },{ passive: true })
            down.addEventListener('touchend', function () {
                movingDown=false
                player.moving = false
            },{ passive: true })
            left.addEventListener('touchstart', function (e) {
                (movingLeft=true)
                player.moving = true
                e.stopPropagation();
            },{ passive: true })
            left.addEventListener('touchend', function () {
                movingLeft=false
                player.moving = false
            },{ passive: true })
    
    
            if(openPannels===false) {
              if(movingRight===false && movingLeft===false){
                if (movingDown===true && player.y < 2000) {
                    player.y += player.speed
                    player.frameY = 0;
                    player.moving = true
                }
                if (movingUp===true && player.y > 360) {
                    player.y -= player.speed
                    player.frameY = 3;
                    player.moving = true
                }
              }
                if (movingRight===true && player.x < 3000) {
                    player.x += player.speed
                    player.frameY = 2;
                    player.moving = true
                }
                if (movingLeft===true && player.x > 360) {
                    player.x -= player.speed
                    player.frameY = 1;
                    player.moving = true
                }
            }
        }
    

    This function has 9 event listeners that are bound every framedraw. so 9 * 60 per second, resulting in 32400 bound events per drawn frame.

    Also put those event handlers outside of the moveplayer function. That way they are bound only once, with access to your javascript context variables.

            action_btnt.addEventListener('touchstart', function (e) {
                (actionBtn=true)
                e.stopPropagation();
            },{ passive: true })
    
            up.addEventListener('touchstart', function (e) {
                (movingUp=true)
                player.moving = true
                e.stopPropagation();
            },{ passive: true })
            up.addEventListener('touchend', function () {
                movingUp=false
                player.moving = false
            },{ passive: true })
            right.addEventListener('touchstart', function (e) {
                (movingRight=true)
                player.moving = true
                e.stopPropagation();
            },{ passive: true })
            right.addEventListener('touchend', function () {
                movingRight=false
                player.moving = false
            },{ passive: true })
            down.addEventListener('touchstart', function (e) {
                (movingDown=true)
                player.moving = true
                e.stopPropagation();
            },{ passive: true })
            down.addEventListener('touchend', function () {
                movingDown=false
                player.moving = false
            },{ passive: true })
            left.addEventListener('touchstart', function (e) {
                (movingLeft=true)
                player.moving = true
                e.stopPropagation();
            },{ passive: true })
            left.addEventListener('touchend', function () {
                movingLeft=false
                player.moving = false
             },{ passive: true })
    
    function movePlayer() {
    
            if(openPannels===false) {
              if(movingRight===false && movingLeft===false){
                if (movingDown===true && player.y < 2000) {
                    player.y += player.speed
                    player.frameY = 0;
                    player.moving = true
                }
                if (movingUp===true && player.y > 360) {
                    player.y -= player.speed
                    player.frameY = 3;
                    player.moving = true
                }
              }
                if (movingRight===true && player.x < 3000) {
                    player.x += player.speed
                    player.frameY = 2;
                    player.moving = true
                }
                if (movingLeft===true && player.x > 360) {
                    player.x -= player.speed
                    player.frameY = 1;
                    player.moving = true
                }
            }
        }