The above GIF represents the latest build of what I’ve decided to call Guts. Since my last post a few days ago, I’ve created and positioned the Mets and Bladers, and as the red half-transparent red boxes in the later area show, am still testing the triggering areas for spawning Bladers in the vertical part of the level. I’m just about ready to add in the Picket Men and Big Eye.
Just like in my earlier posts, I’m also going to share the code I’m using to re-create classic Mega Man enemies. This time, it’s for the Mets and Bladers.
Here is the code for the “Met” (Tool):
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Tool(game, x, y, cacheKey) { | |
// Call the Phaser.Sprite constructor | |
Phaser.Sprite.call(this, game, x, y, cacheKey); | |
// Enable physics | |
this.game.physics.enable(this); | |
// Set the (physics) body to be immovable | |
this.body.immovable = true; | |
// Center the anchor | |
this.anchor.setTo(0.5, 0.5); | |
// Create a group for the bullets | |
this.bulletGroup = this.game.add.group(); | |
// Enable all create items to have (physics) bodies | |
this.bulletGroup.enableBody = true; | |
// Set the type of physics bodies to be ARCADE | |
this.bulletGroup.physicsBodyType = Phaser.Physics.ARCADE; | |
// Create 13 bullets using the 'enemyBullet' cache key | |
this.bulletGroup.createMultiple(13, 'enemyBullet'); | |
// Check if bullets collide with world bounds | |
this.bulletGroup.setAll('checkWorldBounds', true); | |
// If they do collide with world bounds, they are killed | |
this.bulletGroup.setAll('outOfBoundsKill', true); | |
// Bullets only 'live' for 1600ms | |
this.bulletGroup.setAll('lifespan', 1600); | |
// Set the firing rate (how long between shooting) | |
this.fireRate = 1800; | |
// The time of the next shot | |
this.nextFire = 0; | |
// The velocity of each created or revived bullet | |
this.bulletSpeed = 150; | |
// The initial firing angle | |
this.firingAngle = 135; | |
// The 'triggerBox' | |
// If another sprite is within this rectangle, shoot at them | |
this.triggerBox = new Phaser.Rectangle( | |
x - (this.width * 3), | |
y - (this.height * 3), | |
this.width * 3.5, | |
this.height * 3.5); | |
// The 'explosionGroup' for spawning explosions | |
this.explosionGroup = new ExplosionGroup(this.game); | |
// Set that this sprite is 'alive' | |
this.alive = true; | |
} | |
Tool.prototype = Object.create(Phaser.Sprite.prototype); | |
Tool.prototype.constructor = Tool; | |
Tool.prototype.shoot = function() { | |
// Is this sprite alive? | |
if (this.alive) { | |
// It is alive, so check if enough time has past since the last | |
// shot and that there are at least 3 bullets 'dead' | |
if (this.game.time.now > this.nextFire && this.bulletGroup.countDead() > 3) | |
{ | |
// Update the timer | |
this.nextFire = this.game.time.now + this.fireRate; | |
// Run for three loops | |
for (var i = 0; i < 3; i += 1) { | |
// Get the first 'dead' sprite | |
var bullet = this.bulletGroup.getFirstDead(); | |
// Reset its position to the same as this sprite's position | |
// making some adjustments for where the bullets should | |
// come from for this sprite. | |
bullet.reset(this.body.x + (this.width / 2), this.body.y + (this.height / 2) - 18); | |
// Set the firing angle | |
bullet.angle = this.firingAngle; | |
// Set the firing trajectory as based on | |
// the angle and set velocity (linear diagonal motion) | |
this.game.physics.arcade.velocityFromAngle(bullet.angle, | |
this.bulletSpeed, | |
bullet.body.velocity); | |
// Update the firing angle by 45 degrees | |
this.firingAngle += 45; | |
} | |
// Reset the firing angle to 135 degrees | |
this.firingAngle = 135; | |
} | |
} | |
}; | |
Tool.prototype.kill = function() { | |
// Create an explosion at this position | |
this.explosionGroup.explode(this.x, this.y); | |
// kill() this sprite by calling Phaser.Sprite's | |
// own kill function and passing 'this' | |
Phaser.Sprite.prototype.kill.call(this); | |
}; |
And here is the code for the Bladers:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function Blader(game, x, y, cacheKey) { | |
// Call the Phaser.Sprite constructor | |
Phaser.Sprite.call(this, game, x, y, cacheKey); | |
// Enable physics | |
this.game.physics.enable(this); | |
// Set the (physics) body to be immovable | |
this.immovable = true; | |
// Set the initial target coordinates | |
this.target = new Phaser.Point(0, 0); | |
// Set the 'fly' animation | |
this.animations.add('fly', [0, 1], 5, true); | |
// Set the velocity to chase another sprite | |
this.speed = 90; | |
// The 'explosionGroup' for spawning explosions | |
this.explosionGroup = new ExplosionGroup(this.game); | |
// Set that this sprite is 'alive' | |
this.alive = true; | |
// Set the distance at which a Blader should | |
// destory() itself. | |
this.killDistance = this.width * 24; | |
} | |
Blader.prototype = Object.create(Phaser.Sprite.prototype); | |
Blader.prototype.constructor = Blader; | |
/* | |
* This is called from the main game loop like the following: | |
* this.bladerGroup.callAll('updateTarget', null, this.player.x, this.player.y); | |
* | |
* It updates the 'target' position for all Bladers in the group | |
* | |
*/ | |
Blader.prototype.updateTarget = function(x, y) { | |
this.target.x = x; | |
this.target.y = y; | |
}; | |
Blader.prototype.update = function() { | |
// If the 'target.x' is still 0, don't do anything | |
if (this.target.x !== 0) { | |
// At some point, the 'target' has been updated, so | |
// we need to move toward the target at the 'speed' | |
this.game.physics.arcade.moveToXY(this, | |
this.target.x, this.target.y, this.speed); | |
// Since we are moving, play the 'fly' animation | |
this.play('fly'); | |
// If the target is greater than 24 * width OR 24 * height away, | |
// go ahead and destory yourself. (If they are that | |
// far away, a Blader cannot ever catch up.) | |
if ((this.target.x - this.x) > this.killDistance || | |
(this.target.y - this.y) > this.killDistance) { | |
Phaser.Sprite.prototype.destroy.call(this); | |
} | |
} | |
}; | |
Blader.prototype.kill = function() { | |
// Create an explosion at this position | |
this.explosionGroup.explode(this.x, this.y); | |
// kill() this sprite by calling Phaser.Sprite's | |
// own kill function and passing 'this' | |
Phaser.Sprite.prototype.kill.call(this); | |
}; |
As a bonus, here is the code for the explosion groups these both use too:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function ExplosionGroup(game) { | |
// Call the Phaser.Group constructor | |
Phaser.Group.call(this, game); | |
// Have the game add this group | |
this.game.add.existing(this); | |
} | |
ExplosionGroup.prototype = Object.create(Phaser.Group.prototype); | |
ExplosionGroup.prototype.constructor = ExplosionGroup; | |
ExplosionGroup.prototype.explode = function(x, y) { | |
// Get the first 'dead' member of the group | |
var explosion = this.getFirstDead(); | |
// If 'explosion' is null, there weren't any 'dead' memebers | |
if (explosion === null) { | |
// Create a sprite using the 'explosion' cache key | |
explosion = this.game.add.sprite(0, 0, 'explosion'); | |
// Center its anchor | |
explosion.anchor.setTo(0.5, 0.5); | |
// Create an animation based on the 'explosion' cache key | |
// and label it 'boom' for later playing. | |
// (We also need to save a reference to the create animation.) | |
var animation = explosion.animations.add('boom', [0, 1, 2, 3], 50, false); | |
// Tell the animation to kill() itself when done | |
animation.killOnComplete = true; | |
// All the sprite + animation to the group | |
this.add(explosion); | |
} | |
// If there was a 'dead' member in the group, revive it. | |
// Otherwise, 'revive' the new member. | |
explosion.revive(); | |
// Reset its position to those passed into this function | |
explosion.reset(x, y); | |
// Pick a random angle for the sprite (and thus animation) | |
explosion.angle = this.game.rnd.integerInRange(0, 360); | |
// Play the 'boom' animation. | |
// (When it is done, it will kill the animation.) | |
explosion.animations.play('boom'); | |
}; |