mirror of
https://github.com/kevinroast/CanvasMark.git
synced 2025-12-08 19:46:11 +00:00
420 lines
12 KiB
JavaScript
420 lines
12 KiB
JavaScript
/**
|
|
* Basic explosion effect actor class.
|
|
*
|
|
* @namespace Asteroids
|
|
* @class Asteroids.Explosion
|
|
*/
|
|
(function()
|
|
{
|
|
Asteroids.Explosion = function(p, v, s)
|
|
{
|
|
Asteroids.Explosion.superclass.constructor.call(this, p, v, this.FADE_LENGTH);
|
|
this.size = s;
|
|
return this;
|
|
};
|
|
|
|
extend(Asteroids.Explosion, Game.EffectActor,
|
|
{
|
|
FADE_LENGTH: 10,
|
|
|
|
/**
|
|
* Explosion size
|
|
*/
|
|
size: 0,
|
|
|
|
/**
|
|
* Explosion rendering method
|
|
*
|
|
* @param ctx {object} Canvas rendering context
|
|
*/
|
|
onRender: function onRender(ctx)
|
|
{
|
|
// fade out
|
|
var brightness = Math.floor((255 / this.FADE_LENGTH) * this.lifespan);
|
|
var rad = (this.size * 8 / this.FADE_LENGTH) * this.lifespan;
|
|
var rgb = brightness.toString();
|
|
ctx.save();
|
|
ctx.globalAlpha = 0.75;
|
|
ctx.fillStyle = "rgb(" + rgb + ",0,0)";
|
|
ctx.beginPath();
|
|
ctx.arc(this.position.x, this.position.y, rad, 0, TWOPI, true);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
ctx.restore();
|
|
}
|
|
});
|
|
})();
|
|
|
|
|
|
/**
|
|
* Player Explosion effect actor class.
|
|
*
|
|
* @namespace Asteroids
|
|
* @class Asteroids.PlayerExplosion
|
|
*/
|
|
(function()
|
|
{
|
|
Asteroids.PlayerExplosion = function(p, v)
|
|
{
|
|
Asteroids.PlayerExplosion.superclass.constructor.call(this, p, v, this.FADE_LENGTH);
|
|
return this;
|
|
};
|
|
|
|
extend(Asteroids.PlayerExplosion, Game.EffectActor,
|
|
{
|
|
FADE_LENGTH: 15,
|
|
|
|
/**
|
|
* Explosion rendering method
|
|
*
|
|
* @param ctx {object} Canvas rendering context
|
|
*/
|
|
onRender: function onRender(ctx)
|
|
{
|
|
ctx.save();
|
|
var alpha = (1.0 / this.FADE_LENGTH) * this.lifespan;
|
|
ctx.globalCompositeOperation = "lighter";
|
|
ctx.globalAlpha = alpha;
|
|
|
|
var rad;
|
|
if (this.lifespan > 5 && this.lifespan <= 15)
|
|
{
|
|
var offset = this.lifespan - 5;
|
|
rad = (48 / this.FADE_LENGTH) * offset;
|
|
ctx.fillStyle = "rgb(255,170,30)";
|
|
ctx.beginPath();
|
|
ctx.arc(this.position.x-2, this.position.y-2, rad, 0, TWOPI, true);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
}
|
|
|
|
if (this.lifespan > 2 && this.lifespan <= 12)
|
|
{
|
|
var offset = this.lifespan - 2;
|
|
rad = (32 / this.FADE_LENGTH) * offset;
|
|
ctx.fillStyle = "rgb(255,255,50)";
|
|
ctx.beginPath();
|
|
ctx.arc(this.position.x+2, this.position.y+2, rad, 0, TWOPI, true);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
}
|
|
|
|
if (this.lifespan <= 10)
|
|
{
|
|
var offset = this.lifespan;
|
|
rad = (24 / this.FADE_LENGTH) * offset;
|
|
ctx.fillStyle = "rgb(255,70,100)";
|
|
ctx.beginPath();
|
|
ctx.arc(this.position.x+2, this.position.y-2, rad, 0, TWOPI, true);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
}
|
|
|
|
ctx.restore();
|
|
}
|
|
});
|
|
})();
|
|
|
|
|
|
/**
|
|
* Impact effect (from bullet hitting an object) actor class.
|
|
*
|
|
* @namespace Asteroids
|
|
* @class Asteroids.Impact
|
|
*/
|
|
(function()
|
|
{
|
|
Asteroids.Impact = function(p, v)
|
|
{
|
|
Asteroids.Impact.superclass.constructor.call(this, p, v, this.FADE_LENGTH);
|
|
return this;
|
|
};
|
|
|
|
extend(Asteroids.Impact, Game.EffectActor,
|
|
{
|
|
FADE_LENGTH: 12,
|
|
|
|
/**
|
|
* Impact effect rendering method
|
|
*
|
|
* @param ctx {object} Canvas rendering context
|
|
*/
|
|
onRender: function onRender(ctx)
|
|
{
|
|
// fade out alpha
|
|
var alpha = (1.0 / this.FADE_LENGTH) * this.lifespan;
|
|
ctx.save();
|
|
ctx.globalAlpha = alpha * 0.75;
|
|
if (BITMAPS)
|
|
{
|
|
ctx.fillStyle = "rgb(50,255,50)";
|
|
}
|
|
else
|
|
{
|
|
ctx.shadowColor = ctx.strokeStyle = "rgb(50,255,50)";
|
|
}
|
|
ctx.beginPath();
|
|
ctx.arc(this.position.x, this.position.y, 2, 0, TWOPI, true);
|
|
ctx.closePath();
|
|
if (BITMAPS) ctx.fill(); else ctx.stroke();
|
|
ctx.globalAlpha = alpha;
|
|
ctx.beginPath();
|
|
ctx.arc(this.position.x, this.position.y, 1, 0, TWOPI, true);
|
|
ctx.closePath();
|
|
if (BITMAPS) ctx.fill(); else ctx.stroke();
|
|
ctx.restore();
|
|
}
|
|
});
|
|
})();
|
|
|
|
|
|
/**
|
|
* Text indicator effect actor class.
|
|
*
|
|
* @namespace Asteroids
|
|
* @class Asteroids.TextIndicator
|
|
*/
|
|
(function()
|
|
{
|
|
Asteroids.TextIndicator = function(p, v, msg, textSize, colour, fadeLength)
|
|
{
|
|
this.fadeLength = (fadeLength ? fadeLength : this.DEFAULT_FADE_LENGTH);
|
|
Asteroids.TextIndicator.superclass.constructor.call(this, p, v, this.fadeLength);
|
|
this.msg = msg;
|
|
if (textSize)
|
|
{
|
|
this.textSize = textSize;
|
|
}
|
|
if (colour)
|
|
{
|
|
this.colour = colour;
|
|
}
|
|
return this;
|
|
};
|
|
|
|
extend(Asteroids.TextIndicator, Game.EffectActor,
|
|
{
|
|
DEFAULT_FADE_LENGTH: 16,
|
|
fadeLength: 0,
|
|
textSize: 12,
|
|
msg: null,
|
|
colour: "rgb(255,255,255)",
|
|
|
|
/**
|
|
* Text indicator effect rendering method
|
|
*
|
|
* @param ctx {object} Canvas rendering context
|
|
*/
|
|
onRender: function onRender(ctx)
|
|
{
|
|
// fade out alpha
|
|
var alpha = (1.0 / this.fadeLength) * this.lifespan;
|
|
ctx.save();
|
|
ctx.globalAlpha = alpha;
|
|
Game.fillText(ctx, this.msg, this.textSize + "pt Courier New", this.position.x, this.position.y, this.colour);
|
|
ctx.restore();
|
|
}
|
|
});
|
|
})();
|
|
|
|
|
|
/**
|
|
* Score indicator effect actor class.
|
|
*
|
|
* @namespace Asteroids
|
|
* @class Asteroids.ScoreIndicator
|
|
*/
|
|
(function()
|
|
{
|
|
Asteroids.ScoreIndicator = function(p, v, score, textSize, prefix, colour, fadeLength)
|
|
{
|
|
var msg = score.toString();
|
|
if (prefix)
|
|
{
|
|
msg = prefix + ' ' + msg;
|
|
}
|
|
Asteroids.ScoreIndicator.superclass.constructor.call(this, p, v, msg, textSize, colour, fadeLength);
|
|
return this;
|
|
};
|
|
|
|
extend(Asteroids.ScoreIndicator, Asteroids.TextIndicator,
|
|
{
|
|
});
|
|
})();
|
|
|
|
|
|
/**
|
|
* Power up collectable.
|
|
*
|
|
* @namespace Asteroids
|
|
* @class Asteroids.PowerUp
|
|
*/
|
|
(function()
|
|
{
|
|
Asteroids.PowerUp = function(p, v)
|
|
{
|
|
Asteroids.PowerUp.superclass.constructor.call(this, p, v);
|
|
return this;
|
|
};
|
|
|
|
extend(Asteroids.PowerUp, Game.EffectActor,
|
|
{
|
|
RADIUS: 8,
|
|
pulse: 128,
|
|
pulseinc: 8,
|
|
|
|
/**
|
|
* Power up rendering method
|
|
*
|
|
* @param ctx {object} Canvas rendering context
|
|
*/
|
|
onRender: function onRender(ctx)
|
|
{
|
|
ctx.save();
|
|
ctx.globalAlpha = 0.75;
|
|
var col = "rgb(255," + this.pulse.toString() + ",0)";
|
|
if (BITMAPS)
|
|
{
|
|
ctx.fillStyle = col;
|
|
ctx.strokeStyle = "rgb(255,255,128)";
|
|
}
|
|
else
|
|
{
|
|
ctx.lineWidth = 2.0;
|
|
ctx.shadowColor = ctx.strokeStyle = col;
|
|
}
|
|
ctx.beginPath();
|
|
ctx.arc(this.position.x, this.position.y, this.RADIUS, 0, TWOPI, true);
|
|
ctx.closePath();
|
|
if (BITMAPS)
|
|
{
|
|
ctx.fill();
|
|
}
|
|
ctx.stroke();
|
|
ctx.restore();
|
|
this.pulse += this.pulseinc;
|
|
if (this.pulse > 255)
|
|
{
|
|
this.pulse = 256 - this.pulseinc;
|
|
this.pulseinc =- this.pulseinc;
|
|
}
|
|
else if (this.pulse < 0)
|
|
{
|
|
this.pulse = 0 - this.pulseinc;
|
|
this.pulseinc =- this.pulseinc;
|
|
}
|
|
},
|
|
|
|
radius: function radius()
|
|
{
|
|
return this.RADIUS;
|
|
},
|
|
|
|
collected: function collected(game, player, scene)
|
|
{
|
|
// randomly select a powerup to apply
|
|
var message = null;
|
|
switch (randomInt(0, 9))
|
|
{
|
|
case 0:
|
|
case 1:
|
|
// boost energy
|
|
message = "Energy Boost!";
|
|
player.energy += player.ENERGY_INIT/2;
|
|
if (player.energy > player.ENERGY_INIT)
|
|
{
|
|
player.energy = player.ENERGY_INIT;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
// fire when shieled
|
|
message = "Fire When Shielded!";
|
|
player.fireWhenShield = true;
|
|
break;
|
|
|
|
case 3:
|
|
// extra life
|
|
message = "Extra Life!";
|
|
game.lives++;
|
|
break;
|
|
|
|
case 4:
|
|
// slow down asteroids
|
|
message = "Slow Down Asteroids!";
|
|
for (var n = 0, m = scene.enemies.length, enemy; n < m; n++)
|
|
{
|
|
enemy = scene.enemies[n];
|
|
if (enemy instanceof Asteroids.Asteroid)
|
|
{
|
|
enemy.vector.scale(0.75);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 5:
|
|
// smart bomb
|
|
message = "Smart Bomb!";
|
|
|
|
var effectRad = 96;
|
|
|
|
// add a BIG explosion actor at the smart bomb weapon position and vector
|
|
var boom = new Asteroids.Explosion(
|
|
this.position.clone(), this.vector.clone().scale(0.5), effectRad / 8);
|
|
scene.effects.push(boom);
|
|
|
|
// test circle intersection with each enemy actor
|
|
// we check the enemy list length each iteration to catch baby asteroids
|
|
// this is a fully fledged smart bomb after all!
|
|
for (var n = 0, enemy, pos = this.position; n < scene.enemies.length; n++)
|
|
{
|
|
enemy = scene.enemies[n];
|
|
|
|
// test the distance against the two radius combined
|
|
if (pos.distance(enemy.position) <= effectRad + enemy.radius())
|
|
{
|
|
// intersection detected!
|
|
enemy.hit(-1);
|
|
scene.generatePowerUp(enemy);
|
|
scene.destroyEnemy(enemy, this.vector, true);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
// twin cannon primary weapon upgrade
|
|
message = "Twin Cannons!";
|
|
player.primaryWeapons["main"] = new Asteroids.TwinCannonsWeapon(player);
|
|
break;
|
|
|
|
case 7:
|
|
// v spray cannons
|
|
message = "Spray Cannons!";
|
|
player.primaryWeapons["main"] = new Asteroids.VSprayCannonsWeapon(player);
|
|
break;
|
|
|
|
case 8:
|
|
// rear guns
|
|
message = "Rear Gun!";
|
|
player.primaryWeapons["rear"] = new Asteroids.RearGunWeapon(player);
|
|
break;
|
|
|
|
case 9:
|
|
// side guns
|
|
message = "Side Guns!";
|
|
player.primaryWeapons["side"] = new Asteroids.SideGunWeapon(player);
|
|
break;
|
|
}
|
|
|
|
if (message)
|
|
{
|
|
// generate a effect indicator at the destroyed enemy position
|
|
var vec = new Vector(0, -3.0);
|
|
var effect = new Asteroids.TextIndicator(
|
|
new Vector(this.position.x, this.position.y - this.RADIUS), vec, message, null, null, 32);
|
|
scene.effects.push(effect);
|
|
}
|
|
}
|
|
});
|
|
})();
|