简体   繁体   中英

Why does the page start to lag when drawing many elements on the canvas?

I'm creating a game, and I need to draw) some elements at the top of the <canvas> , but the more elements appear, the more lag the page itself. I found this example where a lot of circles appear, but everything works fine - JSFiddle . Can someone tell me how to optimize my case?

"use strict";

/*Determing canvas*/
window.onload = () => {
    const canvas = document.getElementById("canvas"),
        ctx = canvas.getContext('2d'),
        endTitle = document.getElementById('gameover');
    let spawnRate = 300,
        lastspawn = -1;

    class Wall {
        /*Getting values*/
        constructor(x, y, width, height, speed) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.speed = speed;
        }
        /*Draw rectangle*/
        draw() {
            ctx.beginPath();
            ctx.fillStyle = "#000000";
            ctx.fillRect(this.x, this.y, this.width, this.height)
        }
    }

    /*Making walls*/
    let walls = [];

    /*Spawn walls endlessly*/
    function spawnWalls() {
        const wall_x = Math.floor(Math.random() * (canvas.width - 20)) + 10
        const wall_y = 0
        for (let i = 0; i < 200; i++) {
            walls.push(new Wall(wall_x, wall_y, 10, 10, 10))
        }
    }
    
    /*Update game*/
    function refresh() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        let time = Date.now()
        if (time > (lastspawn + spawnRate)) {
            lastspawn = time;
            spawnWalls();
            spawnRate -= 10;
        }
        walls.forEach(wall => wall.draw())
        for (let j of walls) {
            j.y += j.speed;
            j.draw();
        };
    };
    let interval = setInterval(refresh, 50);                                                                                                   

Walls is too big.

It looks like you're never removing old walls, so they are continuing to be drawn well after they have been removed from the canvas. In your Refresh function, check if the wall has passed the canvas size and if so, remove that from the walls array.

EDIT:

I've added your 'remove' code from the comment.

Another easy win is to stop using new Date() because of who knows what, probably time zones and localization, dates are very expensive to instantiate. However modern browsers offer a performance API, and that can tell you the time since page load, which seems to have a substantial improvement on your existing performance.

 "use strict"; /*Determing canvas*/ window.onload = () => { const canvas = document.getElementById("canvas"), ctx = canvas.getContext('2d'), endTitle = document.getElementById('gameover'); let spawnRate = 300, lastspawn = -1; endTitle.style.display = "none"; canvas.width = window.innerWidth; canvas.height = window.innerHeight; /*Classes*/ class Player { /*Get player info*/ constructor(x, y, width, height, speed) { this.x = x; this.y = y; this.width = width; this.height = height; this.speed = speed; } /*Draw player*/ draw() { ctx.beginPath(); ctx.fillStyle = "#000000"; ctx.fillRect(this.x, this.y, this.width, this.height); } /*Move player*/ move() { } }; class Wall { /*Getting values*/ constructor(x, y, width, height, speed) { this.x = x; this.y = y; this.width = width; this.height = height; this.speed = speed; } /*Draw rectangle*/ draw() { ctx.beginPath(); ctx.fillStyle = "#000000"; ctx.fillRect(this.x, this.y, this.width, this.height) } } /*Defining players*/ let player_01 = new Player(20, 70, 20, 20, 10); let player_02 = new Player(50, 500, 20, 20, 10); let players = []; players.push(player_01); /*Making walls*/ let walls = []; /*Spawn Walls for infinity*/ function spawnWalls() { const wall_x = Math.floor(Math.random() * (canvas.width - 20)) + 10 const wall_y = 0 for (let i = 0; i < 200; i++) { walls.push(new Wall(wall_x, wall_y, 10, 10, 10)) } } /*Update game*/ function refresh() { ctx.clearRect(0, 0, canvas.width, canvas.height); let time = performance.now() if (time > (lastspawn + spawnRate)) { lastspawn = time; spawnWalls(); spawnRate -= 10; } walls.forEach(wall => wall.draw()) outOfWindow() for (let i of players) { i.draw(); }; for (let j of walls) { if (jy > canvas.height) { walls.shift(j) } jy += j.speed; j.draw(); if (player_01.height + player_01.y > jy && j.height + jy > player_01.y && player_01.width + player_01.x > jx && j.width + jx > player_01.x) { clearInterval(interval); endTitle.style.display = "flex"; }; }; }; let interval = setInterval(refresh, 50); /*Move players on keypress*/ for (let i of players) { window.addEventListener("keydown", (event) => { let key = event.key.toLowerCase(); if (key == "w") iy -= i.speed; else if (key == "s") iy += i.speed; else if (key == "a") ix -= i.speed; else if (key == "d") ix += i.speed; }) } /*Check if player out of the window*/ function outOfWindow() { for (let i of players) { if (ix < 0) ix = 0; else if (ix + i.width > canvas.width) ix = canvas.width - i.width; else if (iy < 0) iy = 0; else if (iy + i.height > canvas.height) iy = canvas.height - i.height; } } }
 #gameover { position: absolute; width: 100%; height: 100%; justify-content: center; align-items: center; flex-direction: column; background-color: rgba(0, 0, 0, .5); }
 <div id="gameover"> <h2>The Game Is Over</h2> <button onclick="restart()">Try again!</button> </div> <canvas id="canvas"></canvas>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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