CanvasMark/scripts/asteroids_enemies.js
2013-07-23 23:57:10 +01:00

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