mirror of
https://github.com/kevinroast/CanvasMark.git
synced 2025-12-08 19:46:11 +00:00
333 lines
9.8 KiB
JavaScript
333 lines
9.8 KiB
JavaScript
/**
|
|
* Asteroid actor class.
|
|
*
|
|
* @namespace Asteroids
|
|
* @class Asteroids.Asteroid
|
|
*/
|
|
(function()
|
|
{
|
|
Asteroids.Asteroid = function(p, v, s, t)
|
|
{
|
|
Asteroids.Asteroid.superclass.constructor.call(this, p, v);
|
|
this.size = s;
|
|
this.health = s;
|
|
|
|
// randomly select an asteroid image bitmap
|
|
if (t === undefined)
|
|
{
|
|
t = randomInt(1, 4);
|
|
}
|
|
eval("this.animImage=g_asteroidImg" + t);
|
|
this.type = t;
|
|
|
|
// randomly setup animation speed and direction
|
|
this.animForward = (Math.random() < 0.5);
|
|
this.animSpeed = 0.25 + Math.random();
|
|
this.animLength = this.ANIMATION_LENGTH;
|
|
this.rotation = randomInt(0, 180);
|
|
this.rotationSpeed = randomInt(-1, 1) / 25;
|
|
|
|
return this;
|
|
};
|
|
|
|
extend(Asteroids.Asteroid, Game.SpriteActor,
|
|
{
|
|
ANIMATION_LENGTH: 180,
|
|
|
|
/**
|
|
* Asteroid size - values from 1-4 are valid.
|
|
*/
|
|
size: 0,
|
|
|
|
/**
|
|
* Asteroid type i.e. which bitmap it is drawn from
|
|
*/
|
|
type: 1,
|
|
|
|
/**
|
|
* Asteroid health before it's destroyed
|
|
*/
|
|
health: 0,
|
|
|
|
/**
|
|
* Retro graphics mode rotation orientation and speed
|
|
*/
|
|
rotation: 0,
|
|
rotationSpeed: 0,
|
|
|
|
/**
|
|
* Asteroid rendering method
|
|
*/
|
|
onRender: function onRender(ctx)
|
|
{
|
|
var rad = this.size * 8;
|
|
ctx.save();
|
|
if (BITMAPS)
|
|
{
|
|
// render asteroid graphic bitmap
|
|
// bitmap is rendered slightly large than the radius as the raytraced asteroid graphics do not
|
|
// quite touch the edges of the 64x64 sprite - this improves perceived collision detection
|
|
this.renderSprite(ctx, this.position.x - rad - 2, this.position.y - rad - 2, (rad * 2)+4, true);
|
|
}
|
|
else
|
|
{
|
|
// draw asteroid outline circle
|
|
ctx.shadowColor = ctx.strokeStyle = "white";
|
|
ctx.translate(this.position.x, this.position.y);
|
|
ctx.scale(this.size * 0.8, this.size * 0.8);
|
|
ctx.rotate(this.rotation += this.rotationSpeed);
|
|
ctx.lineWidth = (0.8 / this.size) * 2;
|
|
ctx.beginPath();
|
|
// asteroid wires
|
|
switch (this.type)
|
|
{
|
|
case 1:
|
|
ctx.moveTo(0,10);
|
|
ctx.lineTo(8,6);
|
|
ctx.lineTo(10,-4);
|
|
ctx.lineTo(4,-2);
|
|
ctx.lineTo(6,-6);
|
|
ctx.lineTo(0,-10);
|
|
ctx.lineTo(-10,-3);
|
|
ctx.lineTo(-10,5);
|
|
break;
|
|
case 2:
|
|
ctx.moveTo(0,10);
|
|
ctx.lineTo(8,6);
|
|
ctx.lineTo(10,-4);
|
|
ctx.lineTo(4,-2);
|
|
ctx.lineTo(6,-6);
|
|
ctx.lineTo(0,-10);
|
|
ctx.lineTo(-8,-8);
|
|
ctx.lineTo(-6,-3);
|
|
ctx.lineTo(-8,-4);
|
|
ctx.lineTo(-10,5);
|
|
break;
|
|
case 3:
|
|
ctx.moveTo(-4,10);
|
|
ctx.lineTo(1,8);
|
|
ctx.lineTo(7,10);
|
|
ctx.lineTo(10,-4);
|
|
ctx.lineTo(4,-2);
|
|
ctx.lineTo(6,-6);
|
|
ctx.lineTo(0,-10);
|
|
ctx.lineTo(-10,-3);
|
|
ctx.lineTo(-10,5);
|
|
break;
|
|
case 4:
|
|
ctx.moveTo(-8,10);
|
|
ctx.lineTo(7,8);
|
|
ctx.lineTo(10,-2);
|
|
ctx.lineTo(6,-10);
|
|
ctx.lineTo(-2,-8);
|
|
ctx.lineTo(-6,-10);
|
|
ctx.lineTo(-10,-6);
|
|
ctx.lineTo(-7,0);
|
|
break;
|
|
}
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
}
|
|
ctx.restore();
|
|
},
|
|
|
|
radius: function radius()
|
|
{
|
|
return this.size * 8;
|
|
},
|
|
|
|
/**
|
|
* Asteroid hit by player bullet
|
|
*
|
|
* @param force of the impacting bullet, -1 for instant kill
|
|
* @return true if destroyed, false otherwise
|
|
*/
|
|
hit: function hit(force)
|
|
{
|
|
if (force !== -1)
|
|
{
|
|
this.health -= force;
|
|
}
|
|
else
|
|
{
|
|
// instant kill
|
|
this.health = 0;
|
|
}
|
|
return !(this.alive = (this.health > 0));
|
|
}
|
|
});
|
|
})();
|
|
|
|
|
|
/**
|
|
* Enemy Ship actor class.
|
|
*
|
|
* @namespace Asteroids
|
|
* @class Asteroids.EnemyShip
|
|
*/
|
|
(function()
|
|
{
|
|
Asteroids.EnemyShip = function(scene, size)
|
|
{
|
|
this.size = size;
|
|
|
|
// small ship, alter settings slightly
|
|
if (this.size === 1)
|
|
{
|
|
this.BULLET_RECHARGE = 45;
|
|
this.RADIUS = 8;
|
|
}
|
|
|
|
// randomly setup enemy initial position and vector
|
|
// ensure the enemy starts in the opposite quadrant to the player
|
|
var p, v;
|
|
if (scene.player.position.x < GameHandler.width / 2)
|
|
{
|
|
// player on left of the screen
|
|
if (scene.player.position.y < GameHandler.height / 2)
|
|
{
|
|
// player in top left of the screen
|
|
p = new Vector(GameHandler.width-48, GameHandler.height-48);
|
|
}
|
|
else
|
|
{
|
|
// player in bottom left of the screen
|
|
p = new Vector(GameHandler.width-48, 48);
|
|
}
|
|
v = new Vector(-(Math.random() + 1 + size), Math.random() + 0.5 + size);
|
|
}
|
|
else
|
|
{
|
|
// player on right of the screen
|
|
if (scene.player.position.y < GameHandler.height / 2)
|
|
{
|
|
// player in top right of the screen
|
|
p = new Vector(0, GameHandler.height-48);
|
|
}
|
|
else
|
|
{
|
|
// player in bottom right of the screen
|
|
p = new Vector(0, 48);
|
|
}
|
|
v = new Vector(Math.random() + 1 + size, Math.random() + 0.5 + size);
|
|
}
|
|
|
|
// setup SpriteActor values
|
|
this.animImage = g_enemyshipImg;
|
|
this.animLength = this.SHIP_ANIM_LENGTH;
|
|
|
|
Asteroids.EnemyShip.superclass.constructor.call(this, p, v);
|
|
|
|
return this;
|
|
};
|
|
|
|
extend(Asteroids.EnemyShip, Game.SpriteActor,
|
|
{
|
|
SHIP_ANIM_LENGTH: 90,
|
|
RADIUS: 16,
|
|
BULLET_RECHARGE: 60,
|
|
|
|
/**
|
|
* Enemy ship size - 0 = large (slow), 1 = small (fast)
|
|
*/
|
|
size: 0,
|
|
|
|
/**
|
|
* Bullet fire recharging counter
|
|
*/
|
|
bulletRecharge: 0,
|
|
|
|
onUpdate: function onUpdate(scene)
|
|
{
|
|
// change enemy direction randomly
|
|
if (this.size === 0)
|
|
{
|
|
if (Math.random() < 0.01)
|
|
{
|
|
this.vector.y = -(this.vector.y + (0.25 - (Math.random()/2)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Math.random() < 0.02)
|
|
{
|
|
this.vector.y = -(this.vector.y + (0.5 - Math.random()));
|
|
}
|
|
}
|
|
|
|
// regular fire a bullet at the player
|
|
if (GameHandler.frameCount - this.bulletRecharge > this.BULLET_RECHARGE && scene.player.alive)
|
|
{
|
|
// ok, update last fired frame and we can now generate a bullet
|
|
this.bulletRecharge = GameHandler.frameCount;
|
|
|
|
// generate a vector pointed at the player
|
|
// by calculating a vector between the player and enemy positions
|
|
var v = scene.player.position.clone().sub(this.position);
|
|
// scale resulting vector down to bullet vector size
|
|
var scale = (this.size === 0 ? 5.0 : 6.0) / v.length();
|
|
v.x *= scale;
|
|
v.y *= scale;
|
|
// slightly randomize the direction (big ship is less accurate also)
|
|
v.x += (this.size === 0 ? (Math.random() * 2 - 1) : (Math.random() - 0.5));
|
|
v.y += (this.size === 0 ? (Math.random() * 2 - 1) : (Math.random() - 0.5));
|
|
// - could add the enemy motion vector for correct momentum
|
|
// - but problem is this leads to slow bullets firing back from dir of travel
|
|
// - so pretend that enemies are clever enough to account for this...
|
|
//v.add(this.vector);
|
|
|
|
var bullet = new Asteroids.EnemyBullet(this.position.clone(), v);
|
|
scene.enemyBullets.push(bullet);
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Enemy rendering method
|
|
*/
|
|
onRender: function onRender(ctx)
|
|
{
|
|
if (BITMAPS)
|
|
{
|
|
// render enemy graphic bitmap
|
|
var rad = this.RADIUS + 2;
|
|
this.renderSprite(ctx, this.position.x - rad, this.position.y - rad, rad * 2, true);
|
|
}
|
|
else
|
|
{
|
|
ctx.save();
|
|
ctx.translate(this.position.x, this.position.y);
|
|
if (this.size === 0)
|
|
{
|
|
ctx.scale(2, 2);
|
|
}
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, -4);
|
|
ctx.lineTo(8, 3);
|
|
ctx.lineTo(0, 8);
|
|
ctx.lineTo(-8, 3);
|
|
ctx.lineTo(0, -4);
|
|
ctx.closePath();
|
|
ctx.shadowColor = ctx.strokeStyle = "rgb(100,150,100)";
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, -8);
|
|
ctx.lineTo(4, -4);
|
|
ctx.lineTo(0, 0);
|
|
ctx.lineTo(-4, -4);
|
|
ctx.lineTo(0, -8);
|
|
ctx.closePath();
|
|
ctx.shadowColor = ctx.strokeStyle = "rgb(150,200,150)";
|
|
ctx.stroke();
|
|
|
|
ctx.restore();
|
|
}
|
|
},
|
|
|
|
radius: function radius()
|
|
{
|
|
return this.RADIUS;
|
|
}
|
|
});
|
|
})();
|