Search code examples
javascripthtmlcssflicker

Flickering images with Javascript


I am trying to make a game in Javascript with Repl.it, but every few seconds the player's images flickers. I cannot figure out why this is happening? I am loading some images onto a canvas and it only started flickering once I added in the animate() function and started changing the image. Can someone please explain this? (go to this website to see the flicker and play the game too: https://advanced-chrome-dino-game.sharkcoding.repl.co/) My code:

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();


Solution

  • I checked the code and I realized you were loading images each time into the player.img variable.

    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")
    }
    

    If you use my code here, you need to change the code to use those images instead. Because now, each time you draw, you are loading an image. Like this, all images are stored and I tried it, no more flickering.