Почему страница начинает отставать при рисовании большого количества элементов на холсте? - PullRequest
1 голос
/ 06 августа 2020

Я создаю игру, и мне нужно создать (нарисовать) некоторые элементы в верхней части холста, но чем больше появляется элементов, тем больше лагает сама страница. Я нашел этот пример, где появляется много кругов, но все работает нормально - JSFiddle . Может кто подскажет, как оптимизировать мой случай?

"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 = Date.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) {
            j.y += j.speed;
            j.draw();
            if (player_01.height + player_01.y > j.y && j.height + j.y > player_01.y && player_01.width + player_01.x > j.x && j.width + j.x > 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") i.y -= i.speed;
            else if (key == "s") i.y += i.speed;
            else if (key == "a") i.x -= i.speed;
            else if (key == "d") i.x += i.speed;
        })
    }
    
    /*Check if player out of the window*/
    function outOfWindow() {
        for (let i of players) {
            if (i.x < 0) i.x = 0;
            else if (i.x + i.width > canvas.width) i.x = canvas.width - i.width;
            else if (i.y < 0) i.y = 0;
            else if (i.y + i.height > canvas.height) i.y = canvas.height - i.height;
        }
    }
};

/*Restart game*/
function restart() {
    document.location.reload();
};
#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>

Возможно, мне нужно очистить все, что находится за пределами холста, или взять все старые прямоугольники за пределы окна и снова заменить их случайным образом, или не использовать setInterval ()? И может кто-нибудь сказать мне, действительно ли clearRect () очищает все старые элементы?

1 Ответ

3 голосов
/ 06 августа 2020

Walls слишком велик.

Похоже, вы никогда не удаляете старые стены, поэтому они продолжают рисоваться после того, как были удалены с холста. В вашей функции Refre sh проверьте, соответствует ли стена размеру холста, и если да, удалите это из массива walls.

EDIT:

Я добавил ваш ' remove 'code из комментария.

Еще одна легкая победа - отказаться от использования new Date() из-за того, кто знает, что, вероятно, часовые пояса и локализация, даты очень дорого создавать. Однако современные браузеры предлагают API производительности, который может сказать вам время, прошедшее с момента загрузки страницы, что, по-видимому, значительно улучшает вашу существующую производительность.

"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 (j.y > canvas.height) {
        walls.shift(j)
      }
      j.y += j.speed;
      j.draw();
      if (player_01.height + player_01.y > j.y && j.height + j.y > player_01.y && player_01.width + player_01.x > j.x && j.width + j.x > 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") i.y -= i.speed;
      else if (key == "s") i.y += i.speed;
      else if (key == "a") i.x -= i.speed;
      else if (key == "d") i.x += i.speed;
    })
  }

  /*Check if player out of the window*/
  function outOfWindow() {
    for (let i of players) {
      if (i.x < 0) i.x = 0;
      else if (i.x + i.width > canvas.width) i.x = canvas.width - i.width;
      else if (i.y < 0) i.y = 0;
      else if (i.y + i.height > canvas.height) i.y = 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...