Marc Fletcher
Marc Fletcher

Reputation: 1082

Canvas how to rotate image and redraw without rotating the entire context

I am trying to recreate asteroids with canvas and JS, and am having trouble rotating the ship based on it's angle. I have tested my methods for calculating the angle and converting to radians, and they checkout, and the angle is defined when called in draw(), but the rotation is not occurring. When I can get some rotation going, it rotates the entire context, not the ship.

I have included the entire ship class, but the relevant function is the draw function at the bottom.

function Ship(posOptions) {
  let options = {game: posOptions['game'], color: 'green', pos: posOptions['pos'], radius: 20, vel: [0,0], wrappable: true, type: 0}
  MovingObject.call(this, options);
  this.facingDir = 0;
  this.H = window.innerHeight; //*0.75,
  this.W = window.innerWidth; //*0.75;
  this.xc = this.W/2; //zeby bylo w centrum :v
  this.yc = this.H/2; //jw.
  this.x =  this.xc;
  this.y =  this.yc;
  this.dv = 0.2;
  this.dt = 1;
  this.vx = 0;
  this.vy = 0;
  this.maxVel = 10;
}

Utils.inherits(Ship, MovingObject);

//Relocate ship if hit by asteroid.
Ship.prototype.relocate = function () {
  this.pos = this.game.randomPosition();
  this.vel = [0,0];
};


Ship.prototype.fireBullet = function () {
  let bulletVel = [(this.vel[0] * 4), (this.vel[1] * 5) - 10];
  let bullet = new Bullet({pos: this.pos, vel: bulletVel, game: this.game});
  this.game.bullets.push(bullet);
};

//Calculate velocity based on keyboard input and angle of rotation

Ship.prototype.power = function (impulse) {
  if (impulse[0] === -2 && this.facingDir !== Math.PI) {
    this.facingDir <= Math.PI ? this.facingDir += 30 / 180 * Math.PI : this.facingDir -= 30 / 180 * Math.PI;
  }
  if (impulse[0] === 2 && this.facingDir !== 0) {
    this.facingDir <= 0 ? this.facingDir += 30 / 180 * Math.PI : this.facingDir -= 30 / 180 * Math.PI;
  }
  if (impulse[1] === 2 && this.facingDir !== (Math.PI / 2 * 3)) {
    this.facingDir <= (3 * Math.PI / 2) ? this.facingDir += 30 / 180 * Math.PI : this.facingDir -= 30 / 180 * Math.PI;
  }
  if (impulse[1] === -2 && this.facingDir !== (Math.PI / 2)) {
    this.facingDir <= (Math.PI / 2) ? this.facingDir += 30 / 180 * Math.PI : this.facingDir -= 30 / 180 * Math.PI;
  }
  this.vel[0] += impulse[0];
  this.vel[1] += impulse[1];
};


Ship.prototype.move = function () {
  if (this.isWrappable) {
    this.pos = this.game.wrap(this.pos);
  }

  this.pos[0] += this.vel[0];
  this.pos[1] += this.vel[1];
  //Attenuate the velocity over time so it doesn't accelerate forever. 
  this.vel[0] *= .98;
  this.vel[1] *= .98;
};

Ship.prototype.convertToRadians = function(degree) {
  return degree*(Math.PI/180);
}

Ship.prototype.draw = function (ctx) {
  const img = new Image();
  img.onload = function () {
    ctx.drawImage(img, this.pos[0]-this.radius, this.pos[1]-this.radius)
  };
  img.src = 'galaga_ship.png';
  ctx.drawImage(img, this.pos[0]-this.radius, this.pos[1]-this.radius);

  **//This is where I am stuck.**
  ctx.save();
  ctx.translate(this.x,this.y);
  ctx.rotate(this.facingDir);
  ctx.translate(-7,-10);
  ctx.restore();

};

module.exports = Ship;

Upvotes: 1

Views: 1059

Answers (1)

AgataB
AgataB

Reputation: 647

You are not drawing anything before restoring the context. The way ctx.save() and ctx.restore() should be used is that you save it, with the original rotation and location of the origin, you transform it, do the drawing, then restore it back to where it was originally. Thus only the drawing uses the transformed coordinate system, and then everything else acts as normal again.

  **//This is where I am stuck.**
  ctx.save();
  ctx.translate(this.x,this.y);
  ctx.rotate(this.facingDir);
  ctx.translate(-7,-10);
// PUT DRAWING YOUR SHIP HERE
  ctx.restore();

Upvotes: 1

Related Questions