Javascript 的闪烁图像

Flickering images with Javascript

我正在尝试使用 Repl.it 在 Javascript 中制作游戏,但玩家的图像每隔几秒就会闪烁。我不明白为什么会这样?我正在将一些图像加载到 canvas 上,并且在我添加 animate() 函数并开始更改图像后它才开始闪烁。有人可以解释一下吗? (去这个网站看忽悠也玩游戏:https://advanced-chrome-dino-game.isaacroot.repl.co/)我的代码:

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var ground_size = 75;
var up = false;
var game_over = false;
const start_speed = 8;
var score = 0;


function randBetween(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}


class Player {
  constructor(x_pos) {
    this.color = "black";
    this.image = "dino_1.png"
    this.img = new Image();
    this.width = 120;
    this.height = 120;
    this.x = x_pos;
    this.y = c.height - ground_size - this.height;
    this.speed = 0;
    this.jump_power = 22.5;
    this._gravity = 1;
    this.an_time = 7;
    this.an_count = 0;
  }

  ground_height() {
    return c.height - ground_size - this.height;
  }

  on_ground() {
    if (this.y == this.ground_height()) {
      return true;
    } else {
      return false;
    }
  }

  jump() {
    if (this.on_ground()) {
      this.speed = this.jump_power;
      this.image = "dino_jump.png";
    }
  }

  gravity() {
    this.speed -= this._gravity;
  }

  animate() {
    if (this.an_count <= 0) {
      if (this.image == "dino_1.png") {
        this.image = "dino_2.png";
      } else {
        if (this.image == "dino_2.png") {
          this.image = "dino_1.png"
        }
      }
      this.an_count = this.an_time;
    } else {
      this.an_count -= 1;
    }
  }

  react() {
    this.y -= this.speed
    if (this.y > this.ground_height()) {
      this.y = this.ground_height();
      this.speed = 0;
    }
    if (this.on_ground() && this.image == "dino_jump.png") {
      this.image = "dino_1.png"
    }
  }

  rect() {
    return [this.x, this.y, this.width, this.height]
  }
}


class Obstacle {
  constructor(x_pos, speed) {
    this.color = "red";
    this.img = new Image();
    this.img.src = "cactus_big.png";
    this.width = 52 * 1.5;
    this.height = 75 * 1.5;
    this.x = x_pos;
    this.y = c.height - ground_size - this.height;
    this.speed = speed;
  }

  ground_height() {
    return c.height - ground_size - this.height;
  }

  on_ground() {
    if (this.y == this.ground_height()) {
      return true;
    } else {
      return false;
    }
  }

  react() {
    if (this.x <= 0 - this.width) {
      this.x = randBetween(c.width, c.width + 500);
    }
    this.x -= this.speed;
  }

  rect() {
    return [this.x, this.y, this.width, this.height]
  }
}


player = new Player(75);
obstacle1 = new Obstacle(c.width, start_speed);

function inRect(rect1, rect2) {
  var rect1_left = rect1[0];
  var rect1_right = rect1[0] + rect1[2];
  var rect1_top = rect1[1];
  var rect1_bottom = rect1[1] + rect1[3];

  var rect2_left = rect2[0];
  var rect2_right = rect2[0] + rect2[2];
  var rect2_top = rect2[1];
  var rect2_bottom = rect2[1] + rect2[3];

  var horizontal = false;
  var vertical = false;
  if (rect1_right > rect2_left && rect2_right > rect1_left) {
    horizontal = true;
  }
  if (rect1_bottom > rect2_top && rect2_bottom > rect1_top) {
    vertical = true;
  }

  return (vertical && horizontal);
}

function draw() {
  ctx.beginPath();
  ctx.fillStyle = "white";
  ctx.fillRect(0, 0, c.width, c.height);
  ctx.fillStyle = "#4b4b4b";
  ctx.fillRect(0, c.height - ground_size, c.width, c.height);
  ctx.fillStyle = player.color;
  // ctx.fillRect(player.x, player.y, player.width, player.height);
  player.img.src = player.image;
  ctx.drawImage(player.img, player.x, player.y, player.width, player.height)
  ctx.fillStyle = obstacle1.color;
  // ctx.fillRect(obstacle1.x, obstacle1.y, obstacle1.width, obstacle1.height);
  ctx.drawImage(obstacle1.img, obstacle1.x, obstacle1.y, obstacle1.width, obstacle1.height)
  ctx.fillStyle = "black";
  ctx.font = "30px Arial";
  ctx.fillText("Score: " + Math.round(score / 25).toString(), 20, 50);
  if (game_over) {
    ctx.font = "80px Arial";
  }
  ctx.stroke();
}

document.addEventListener('keydown', (event) => {
  if (event.key == 'ArrowUp' || event.key == 'Spacebar') {
    up = true;
  } else if (event.key == 'ArrowDown') {
    //pass
  }
});

document.addEventListener('keyup', (eventt) => {
  if (eventt.key == 'ArrowUp') {
    up = false;
  } else if (event.key == 'ArrowDown') {
    //pass
  }
});

function update_speed() {
  obstacle1.speed += 0.001;
}

function run() {
  if (up == true) {
    player.jump()
  }

  player.gravity();
  player.react();
  player.animate();

  obstacle1.react();

  if (inRect(player.rect(), obstacle1.rect())) {
    game_over = true
  }

  score += obstacle1.speed

  draw();

  update_speed();

  if (game_over == false) {
    requestAnimationFrame(run);
  }
}

run();

好吧,您所要做的就是预加载图像,这样您的 index.html 应该看起来像:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>Block Runner</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
    <link rel="preload" href="cactus_big.png" as="image">
    <link rel="preload" href="dino_1.png" as="image">
    <link rel="preload" href="dino_2.png" as="image">
    <link rel="preload" href="dino_jump.png" as="image">
    <link rel="preload" href="ground.png" as="image">
  </head>
  <body>
    <canvas id="myCanvas" width="900" height="600" style="border:0px solid #d3d3d3;">
        Your browser does not support the HTML5 canvas tag.</canvas>
    <script src="script.js"></script>
  </body>
</html>

这样应该不会闪烁。

我检查了代码,发现您每次都将图像加载到 player.img 变量中。

function createImage(path){
  let image = new Image();
  image.src = path;
  return image;
}

var images = {
  dino:[
    createImage("dino_1.png"),
    createImage("dino_2.png"),
    createImage("dino_jump.png")
  ],
  cactus:createImage("cactus_big.png")
}

如果您在此处使用我的代码,则需要更改代码以改为使用这些图像。因为现在,每次绘制时,您都在加载图像。就这样,所有的图片都存起来了,我试了下,不闪烁了。