1

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

2 Answers2

2

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
            }
        }
    }
Tschallacka
  • 27,901
  • 14
  • 88
  • 133
  • 2
    I'll need more than a slice I'm afraid then. Could you provide a reproducable example of the problem in a minimal fashion? Try to strip as much code as posible whilst still having the problem. Then I could aid in tracing down the problem. – Tschallacka Mar 29 '22 at 14:47
  • i have already did this, i still have the problem when i have only the ctx.resetTransform, the ctx.translate, the ctx.drawImage for background, the drawSprite function , the move movePlayer() and the handlePlayerFrame() and finally the requestAnimationFrame. – maxime Lassort Mar 29 '22 at 14:56
  • 2
    Please provide a running example that I can study in a stack snippet or jsfiddle. Without running code that demonstrates the problem it's hard to help you. – Tschallacka Mar 29 '22 at 14:57
  • you can go on my git hub https://github.com/MaxLassort/MyWorld see the code in main and go here to see the projet https://maxlassort.github.io/MyWorld/ – maxime Lassort Mar 29 '22 at 15:01
  • 2
    @maximeLassort I've added another suggestion, again event handlers. Cool site :-) – Tschallacka Mar 29 '22 at 15:22
  • 1
    thanks for the suggestion, it is logical indeed, i'll remplace it and go back here after! Thanks for the compliment :D – maxime Lassort Mar 29 '22 at 15:28
  • hi, i changed the code, it work better but still get some slow down over time, but more time than before, i'll check if theire are more eventlistener somewhere! In any case thanks you for the help! – maxime Lassort Mar 29 '22 at 15:48
0

You can use onload function to understand when image was loaded and then start your game.

const playerSprite = new Image();
playerSprite.src = "img/main_chara.png ";
playerSprite.onload = function(){}

For more information: https://www.techrepublic.com/article/preloading-and-the-javascript-image-object/

dellink
  • 544
  • 3
  • 16
  • yes i tried it but, it doesnt work, what i need to put in the onload? i tried to put the draw image, but it work only with the background! thanks for the link i go se that! – maxime Lassort Mar 29 '22 at 13:46
  • You need to put in the onload your start game logic, but you need preload all images, not only one See this question https://stackoverflow.com/questions/3646036/preloading-images-with-javascript – dellink Mar 29 '22 at 13:57
  • thanks, one more question :D, i put my animation in what image loaded function? the first one? like the background? – maxime Lassort Mar 29 '22 at 14:06