The main character sprite
The hero or main character will be another sprite in our game. However, this sprite is more complex than the platforms, since it needs more business logics: moving around, jumping, etc.
Wouldn't be nice to have a class for these sprites with jump
, move
, etc. methods? We can achieve this by extending (also known as "inheriting from") Phaser.Sprite
.
In JavaScript, we can extend classes following this pattern. Imagine that we have a base class Vehicle
and we want to extend it in Car
:
function Car() {
// call parent constructor
Vehicle.call(this);
}
// clone Vehicle's prototype into Car
Car.prototype = Object.create(Vehicle.prototype);
// restore the constructor at Car
Car.prototype.constructor = Car;
We will use this pattern for extending Phaser.Sprite
.
Yes, sometimes inheritance is not the best choice and usually in JavaScript composition is more favoured. However, Phaser's architecture expects us to extend Phaser.Sprite
, so this is what we are doing.
Tasks
Load the hero image
In
preload
:PlayState.preload = function () { // ... this.game.load.image('hero', 'images/hero_stopped.png'); };
Inherit from Phaser.Sprite
Add the following at the top of
main.js
. This follows the JavaScript inheritance pattern we have already seen. Note how we can have our own custom parameters –in this case, we are not requiring to provide the image key in theHero
constructor.function Hero(game, x, y) { // call Phaser.Sprite constructor Phaser.Sprite.call(this, game, x, y, 'hero'); } // inherit from Phaser.Sprite Hero.prototype = Object.create(Phaser.Sprite.prototype); Hero.prototype.constructor = Hero;
Spawn the hero when loading the level.
As with platforms, the hero position is stored in the JSON level file. We will create a new method,
_spawnCharacters
, to spawn the hero and, later on, the enemies.PlayState._loadLevel = function (data) { //... // spawn hero and enemies this._spawnCharacters({hero: data.hero}); };
PlayState._spawnCharacters = function (data) { // spawn hero this.hero = new Hero(this.game, data.hero.x, data.hero.y); this.game.add.existing(this.hero); };
Check how it looks like. You should see the hero… not in a very good position:
Why is this? Is the level data wrong? What happens is that, usually, we'd like sprites to be handled by their center. This helps in operations like rotations, flipping, etc. and it's also more intuitive. Let's fix this.
In Phaser, the point where we handle sprites and images is called
anchor
. It's a vector, and it accepts values in the0
(left) to1
(right) range. So the central point would be(0.5, 0.5)
. Modify theHero
constructor to set up the anchor:function Hero(game, x, y) { // ... this.anchor.set(0.5, 0.5); }
Refresh the browser again and you should see the hero positioned just over the ground:
Checklist
- There is a hero sprite over the ground, on the bottom left part of the level.
Download
Are you stuck? Take a look at the source code for this step.