为什么一段时间后我的画布性能下降?

时间:2018-06-21 02:23:50

标签: javascript html5-canvas

我有以下代码,当您按向上箭头键时(很长),播放器会跳转:

application = Flask(__name__)
class Vec {
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }
}

class Rect {
  constructor(w, h) {
    this.pos = new Vec;
    this.size = new Vec(w, h);
    this.vel = new Vec;
    this.last = new Vec;
  }
}

class Player extends Rect {
  constructor() {
    super(40, 40);
  }
}

// setup
const backgroundContext = document.getElementById("backgroundCanvas").getContext("2d");
const groundContext = document.getElementById("groundCanvas").getContext("2d");
const objectContext = document.getElementById("objectCanvas").getContext("2d");

const WIDTH = 600;
const HEIGHT = 400;
const GROUND_Y = 50;

const player = new Player;
player.pos.x = 100;
player.pos.y = 390;
player.last.x = player.pos.x;
player.last.y = player.pos.y;
player.vel.x = 0;
let isJumping = true;
const JUMP_STRENGTH = -300;
const GRAVITY = 10;

function update(dt) {
  // update player
  player.last.x = player.pos.x;
  player.last.y = player.pos.y;

  player.vel.y += GRAVITY;
  player.pos.y += player.vel.y * dt;
  player.pos.y = Math.round(player.pos.y);

  document.addEventListener("keydown", (e) => {
    if (e.keyCode === 38 && isJumping === false) {
      isJumping = true;
      player.vel.y = JUMP_STRENGTH;
    }
  }, false);
  if (player.pos.y > HEIGHT - GROUND_Y - player.size.y) {
    isJumping = false;
    player.pos.y = HEIGHT - GROUND_Y - player.size.y;
    player.vel.y = 0;
  }
}

function draw() {
  // draw background
  backgroundContext.fillStyle = "#000";
  backgroundContext.fillRect(0, 0, WIDTH, HEIGHT);

  // draw ground
  objectContext.clearRect(0, HEIGHT - GROUND_Y, WIDTH, GROUND_Y);
  groundContext.fillStyle = "#00ff00";
  groundContext.fillRect(0, HEIGHT - GROUND_Y, WIDTH, GROUND_Y);

  // draw player
  objectContext.clearRect(player.last.x, player.last.y, player.size.x, player.size.y);
  objectContext.fillStyle = "#fff";
  objectContext.fillRect(player.pos.x, player.pos.y, player.size.x, player.size.y);
}

// game loop
const TIMESTEP = 1 / 60;
let accumulator = 0;
let lastRender = 0;

function loop(timestamp) {
  accumulator += (timestamp - lastRender) / 1000;
  lastRender = timestamp;
  while (accumulator >= TIMESTEP) {
    update(TIMESTEP);
    draw();
    accumulator -= TIMESTEP;
  }

  requestAnimationFrame(loop);
}

requestAnimationFrame(loop);
canvas {
  position: absolute;
  left: 0;
  top: 0;
}

我有三个问题:

1)如果等待约一分钟,您会开始注意到性能开始下降。为什么会这样?

2)为什么按住向上箭头键时性能会显着下降?

3)在游戏循环中,我做到了:

<!DOCTYPE html>
<html>

<head>
  <title>Jump_Over_It</title>
  <link href="css/default.css" rel="stylesheet" />
</head>

<body>
  <canvas style="z-index: 0;" id="backgroundCanvas" width="600" height="400"></canvas>
  <canvas style="z-index: 1;" id="groundCanvas" width="600" height="400"></canvas>
  <canvas style="z-index: 2;" id="objectCanvas" width="600" height="400"></canvas>
  <script src="js/main.js"></script>
</body>

</html>

是否可以将while (accumulator >= TIMESTEP) { update(TIMESTEP); draw(); accumulator -= TIMESTEP; }函数与draw()函数放在相同的while循环中?

如果您知道该怎么办,请告诉我。

1 个答案:

答案 0 :(得分:2)

对于问题1和2:

这是因为您是在while循环中添加一个新的EventListener,而本身是在requestAnimationFrame循环中添加。

我什至都不会计算所附加的事件处理程序的数量,也不会运行此代码段,但不要触摸您的键盘,因为那里可能会有Zillions处理程序串行执行。

要正确解决此问题,请将addEventListener调用移出这些循环,只需调用一次即可。

问题3:

尚不清楚为什么您甚至根本不需要这个while循环。直接计算新位置比在这样的循环中更新要好。
但至少没有。您不应在此while循环内调用draw,因为每次调用都会否定先前的调用。因此,只需在您的rAF处理程序结束时调用一次即可。

此外,请注意,与其清除对象所在的部分,不如每次都清除整个画布更好,甚至可能考虑将所有图形移动到单个画布上,因为您认为合成是d当在屏幕上绘制3个DOM元素时,实际上仍然会发生三个画布的获胜。

class Vec {
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }
}

class Rect {
  constructor(w, h) {
    this.pos = new Vec;
    this.size = new Vec(w, h);
    this.vel = new Vec;
    this.last = new Vec;
  }
}

class Player extends Rect {
  constructor() {
    super(40, 40);
  }
}

// setup
const backgroundContext = document.getElementById("backgroundCanvas").getContext("2d");
const groundContext = document.getElementById("groundCanvas").getContext("2d");
const objectContext = document.getElementById("objectCanvas").getContext("2d");

const WIDTH = 600;
const HEIGHT = 400;
const GROUND_Y = 50;

const player = new Player;
player.pos.x = 100;
player.pos.y = 390;
player.last.x = player.pos.x;
player.last.y = player.pos.y;
player.vel.x = 0;
let isJumping = true;
const JUMP_STRENGTH = -300;
const GRAVITY = 10;

function update(dt) {
  // update player
  player.last.x = player.pos.x;
  player.last.y = player.pos.y;

  player.vel.y += GRAVITY;
  player.pos.y += player.vel.y * dt;
  player.pos.y = Math.round(player.pos.y);

  if (player.pos.y > HEIGHT - GROUND_Y - player.size.y) {
    isJumping = false;
    player.pos.y = HEIGHT - GROUND_Y - player.size.y;
    player.vel.y = 0;
  }
}
document.addEventListener("keydown", (e) => {
  if (e.keyCode === 38 && isJumping === false) {
    e.preventDefault();
    isJumping = true;
    player.vel.y = JUMP_STRENGTH;
  }
}, false);

function draw() {
  // draw background
  backgroundContext.fillStyle = "#000";
  backgroundContext.fillRect(0, 0, WIDTH, HEIGHT);

  // draw ground
  groundContext.clearRect(0, 0, WIDTH, HEIGHT);
  groundContext.fillStyle = "#00ff00";
  groundContext.fillRect(0, HEIGHT - GROUND_Y, WIDTH, GROUND_Y);

  // draw player
  objectContext.clearRect(0, 0, WIDTH, HEIGHT);  objectContext.fillStyle = "#fff";
  objectContext.fillRect(player.pos.x, player.pos.y, player.size.x, player.size.y);
}

// game loop
const TIMESTEP = 1 / 60;
let accumulator = 0;
let lastRender = 0;

function loop(timestamp) {
  accumulator += (timestamp - lastRender) / 1000;
  lastRender = timestamp;
  while (accumulator >= TIMESTEP) {
    accumulator -= TIMESTEP;
    update(TIMESTEP);
  }
  draw();

  requestAnimationFrame(loop);
}

requestAnimationFrame(loop);
canvas {
  position: absolute;
  left: 0;
  top: 0;
}
<!DOCTYPE html>
<html>

<head>
  <title>Jump_Over_It</title>
  <link href="css/default.css" rel="stylesheet" />
</head>

<body>
  <canvas style="z-index: 0;" id="backgroundCanvas" width="600" height="400"></canvas>
  <canvas style="z-index: 1;" id="groundCanvas" width="600" height="400"></canvas>
  <canvas style="z-index: 2;" id="objectCanvas" width="600" height="400"></canvas>
  <script src="js/main.js"></script>
</body>

</html>