RKR
RKR

Reputation: 687

How to change the image to another in canvas for some time and then change back again

I am new to game development and I am developing a simple game where I can get a point when I hit the monster by car. So now I want to change the color of the car (if red then blue and vice versa ) when I hit the monster for a while (5 seconds) and then switch back to the original color. I tried with

var myObj = {
    imgs: ["http://res.cloudinary.com/dfhppjli0/image/upload/c_scale,w_2048/v1492045665/road_dwsmux.png", "http://res.cloudinary.com/dfhppjli0/image/upload/c_scale,w_32/v1491958999/car_p1k2hw.png","http://res.cloudinary.com/dfhppjli0/image/upload/v1491958478/monster_rsm0po.png","http://res.cloudinary.com/dfhppjli0/image/upload/v1492579967/car_03_ilt08o.png"], 
    currentImg: 0, 
    draw: function(){
        ctx.drawImage(this.imgs[this.currentImg], this.x, this.y)
    }, 
    changeImg: function(index){
        this.currentImg = index
    }
}

and then draw with

images.__createImage("background","img[0]");

But it did not work.

My working :pen

Any help is appreciated

Upvotes: 0

Views: 672

Answers (1)

Mr_KoKa
Mr_KoKa

Reputation: 618

You were already loading images you need for changing appearance forth and back so that was ok, you don't need to keep url array inside your hero (car) object and loading it again when it is needed.

I have added changeImage property to your heroDefault (car) so I can mark the object that it needs to check if the image need to be changed back, and I also added changeImageTime to heroDefault where I store time after the change has to be done, so when car hits a monster I check changeImage to true and I set changeImageTime to Date.now() + 5000 which means I store current time plus 5 seconds (5000ms):

if (monster.isTouching(this)) {
    monster.reset();
    monstersCaught += 1;

    this.changeImage = true;
    this.changeImageTime = Date.now() + 5000; //5 sec from now.
    this.image = (this.image === images.hero)? images.hero_other : images.hero;
}

Then inside your heroDefault update function I check if there is need to change image back and if the time has passed, if so I change image back and mark the object so it won't compare time no more by setting changeImage to false.

if(this.changeImage){
    if(Date.now() > this.changeImageTime){
        this.changeImage = false;
        this.image = (this.image === images.hero)? images.hero_other : images.hero;
    }
}

// Create the canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 2048;
canvas.height = 1024;
document.body.appendChild(canvas);
var monstersCaught = 0;
var lastFrameTime;
var frameTime = 0; // in seconds used to control hero speed

// The main game loop
function main(time) {
  if (lastFrameTime !== undefined) {
    frameTime = (time - lastFrameTime) / 1000; // in seconds
  }
  lastFrameTime = time
  updateObjects();
  render();
  requestAnimationFrame(main);
};

// this is called when all the images have loaded
function start() {
  monstersCaught = 0;
  resetObjs();
  requestAnimationFrame(main);
}

function displayStatus(message) {
  ctx.setTransform(1, 0, 0, 1, 0, 0); // set default transform
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = "black";
  ctx.font = "24px Helvetica";
  ctx.textAlign = "center";
  ctx.textBaseline = "center";
  ctx.fillText(message, canvas.width / 2, canvas.height / 2);
}
// reset objects
function resetObjs() {
  monsters.array.forEach(monster => monster.reset());
  heros.array.forEach(hero => hero.reset());
}

// Update game objects
function updateObjects(modifier) {

  monsters.array.forEach(monster => monster.update());
  heros.array[0].update('random');
  heros.array[1].update('random');
  heros.array[2].update('random');
  heros.array[3].update('random');
  heros.array[4].update('random');
  heros.array[5].update('random');
  heros.array[6].update('random');
  heros.array[7].update('random');


}

function drawObjects(modifier) {
  monsters.array.forEach(monster => monster.draw());
  heros.array.forEach(hero => hero.draw());

}

// Draw everything
function render() {
  ctx.setTransform(1, 0, 0, 1, 0, 0); // set default transform
  ctx.drawImage(images.background, 0, 0);
  drawObjects();

  // Score
  ctx.setTransform(1, 0, 0, 1, 0, 0); // set default transform
  ctx.fillStyle = "rgb(250, 250, 250)";
  ctx.font = "24px Helvetica";
  ctx.textAlign = "left";
  ctx.textBaseline = "top";
  ctx.fillText("points : " + monstersCaught, 32, 32);
}

// hold all the images in one object.
const images = { // double underscore __ is to prevent adding images that replace these functions
  __status: {
    count: 0,
    ready: false,
    error: false,
  },
  __onready: null,
  __createImage(name, src) {
    var image = new Image();
    image.src = src;
    images.__status.count += 1;
    image.onerror = function() {
      images.__status.error = true;
      displayStatus("Error loading image : '" + name + "'");
    }
    image.onload = function() {
      images.__status.count -= 1;
      if (images.__status.count === 0) {
        images.__status.ready = true;
        images.__onready();
      }
      if (!images.__status.error) {
        displayStatus("Images remaing : " + images.__status.count);
      }
    }
    images[name] = image;
    return image;
  }
}

// Handle all key input
const keys = { // key input object
  ArrowLeft: false, // only add key names you want to listen to
  ArrowRight: false,
  ArrowDown: false,
  ArrowUp: false,
  keyEvent(event) {
    if (keys[event.code] !== undefined) { // are we interested in this key
      keys[event.code] = event.type === "keydown";
      event.preventDefault();
    }
  }
}

// default setting for objects
const objectDefault = {
  x: 0,
  y: 0,
  dir: 0, // the image rotation
  isTouching(obj) { // returns true if object is touching box x,y,w,h
    return !(this.x > obj.x + obj.w || this.y > obj.y + obj.h || this.x + this.w < obj.x || this.y + this.h < obj.y);
  },
  draw() {
    ctx.setTransform(1, 0, 0, 1, this.x + this.w / 2, this.y + this.h / 2);
    ctx.rotate(this.dir);
    ctx.drawImage(this.image, -this.image.width / 2, -this.image.height / 2);
  },
  reset() {},
  update() {},
}

// default setting for monster object
const monsterDefault = {
  w: 32, // width 
  h: 32, // height
  reset() {
    this.x = this.w + (Math.random() * (canvas.width - this.w * 2));
    this.y = this.h + (Math.random() * (canvas.height - this.h * 2));
  },
}

// default settings for hero
const heroDefault = {
  w: 32, // width 
  h: 32, // height
  speed: 256,
  spawnPos: 1.5,
  distanceTraveledInOneDirection: 0,
  autoDirection: 'right',
  changeImage: false, // If true, will check if changeImageTime passed and image needs to be changed
  changeImageTime: 0, // Time after image will be changed
  reset() {
    this.x = canvas.width / this.spawnPos;
    this.y = canvas.height / this.spawnPos;
    this.autoDirection = 'right';
    this.distanceTraveledInOneDirection = 0;
  },
  auto() {
    this.y -= this.speed * frameTime;
  },
  update(dir) {
    this.distanceTraveledInOneDirection += this.speed * frameTime;
    if (dir === 'random') {
      dir = this.autoDirection; //set new direction
      if (this.distanceTraveledInOneDirection > 300) { //make this random or use a timestamp instead of distance if you want
        this.autoDirection = ['up', 'down', 'right', 'left','right','down','left','up'][Math.floor(Math.random() * 4)]; //we have traveled in one direction long enough, time to roll dice and change direction.
        dir = this.autoDirection; //set new direction
        this.distanceTraveledInOneDirection = 0;
      }
    }
    if (!dir) {
      if (keys.ArrowUp) dir = 'up'
      if (keys.ArrowDown) dir = 'down'
      if (keys.ArrowLeft) dir = 'left'
      if (keys.ArrowRight) dir = 'right'
    }
    if (dir === 'up') { // Player holding up
      this.y -= this.speed * frameTime;

      this.dir = Math.PI * 0; // set direction
    }
    if (dir === 'down') { // Player holding down
      this.y += this.speed * frameTime;
      this.dir = Math.PI * 1; // set direction
    }
    if (dir === 'left') { // Player holding left
      this.x -= this.speed * frameTime;
      this.dir = Math.PI * 1.5; // set direction
    }
    if (dir === 'right') { // Player holding right
      this.x += this.speed * frameTime;
      this.dir = Math.PI * 0.5; // set direction
    }
    if (Math.sign(this.speed) === -1) { // filp directio of second car
      this.dir += Math.PI; // set direction
    }

    monsters.array.forEach(monster => {
      if (monster.isTouching(this)) {
        monster.reset();
        monstersCaught += 1;
        this.changeImage = true;
        this.changeImageTime = Date.now() + 5000; //5 sec from now.
        this.image = (this.image === images.hero)? images.hero_other : images.hero;
      }
    });
    if (this.x >= canvas.width || this.y >= canvas.height || this.y < 0 || this.x < 0) {
      this.reset();
    }
    
    if(this.changeImage){
      if(Date.now() > this.changeImageTime){
        this.changeImage = false;
        this.image = (this.image === images.hero)? images.hero_other : images.hero;
      }
    }
  }
}

// objects to hold monsters and heros
const monsters = { // dont call a monster "array"
  array: [], // copy of monsters as array    
};

const heros = { // dont call a monster "array"
  array: [], // copy of heros as array
};

// add monster 
function createMonster(name, settings = {}) {
  monsters[name] = Object.assign({}, objectDefault, monsterDefault, settings, {
    name
  });
  //monsters[name] = {...objectDefault, ...monsterDefault, ...settings, name};
  monsters[name].reset();
  monsters.array.push(monsters[name]);
  return monsters[name];
}

// add hero to heros object
function createHero(name, settings) {

  heros[name] = Object.assign({}, objectDefault, heroDefault, settings, {
    name
  });
  //heros[name] = {...objectDefault, ...heroDefault, ...settings, name};
  heros[name].reset();
  heros.array.push(heros[name]);
  return heros[name];
}

// set function to call when all images have loaded
images.__onready = start;

// load all the images
images.__createImage("background", "http://res.cloudinary.com/dfhppjli0/image/upload/c_scale,w_2048/v1492045665/road_dwsmux.png");
images.__createImage("hero", "http://res.cloudinary.com/dfhppjli0/image/upload/c_scale,w_32/v1491958999/car_p1k2hw.png");
images.__createImage("monster", "http://res.cloudinary.com/dfhppjli0/image/upload/v1491958478/monster_rsm0po.png");
images.__createImage("hero_other", "http://res.cloudinary.com/dfhppjli0/image/upload/v1492579967/car_03_ilt08o.png");

// create all objects
createHero("hero", {
  image: images.hero,
  spawnPos: 1.5
});

createHero("hero3", {
  image: images.hero,
  spawnPos: 2
});
createHero("hero9", {
  image: images.hero_other,
  spawnPos: 2.6
});
createHero("hero12", {
  image: images.hero,
  spawnPos: 1.75
});
createHero("hero15", {
  image: images.hero,
  spawnPos: 1.8
});
createHero("hero18", {
  image: images.hero,
  spawnPos: 2.4
});
createHero("hero21", {
  image: images.hero_other,
  spawnPos: 2.8
});
createHero("hero24", {
  image: images.hero,
  spawnPos: 1.9
});

createMonster("monster", {
  image: images.monster,
});
createMonster("monster3", {
  image: images.monster
});
createMonster("monster9", {
  image: images.monster
});
createMonster("monster12", {
  image: images.monster
});
createMonster("monster15", {
  image: images.monster
});
createMonster("monster18", {
  image: images.monster
});

// add key listeners
document.addEventListener("keydown", keys.keyEvent);
document.addEventListener("keyup", keys.keyEvent);
canvas.addEventListener('click', function(event) {
    createMonster("monster24", {
  image: images.monster
});

}, false);
 <!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>Simple Canvas Game</title>
	</head>
	<body>
		<script src="game.js"></script>
	</body>
</html>

Upvotes: 2

Related Questions