Convert “Shoot 'em Up in an Afternoon” to Phaser 3

hello everybody!

I’m picking up this thread after 4 years because i just made the full “shootem up in 1 afternoon” from Bryan Bibat (which I loved), and started to migrate that Phaser 2.4 2015 code to a modern ES6+Phaser3 code.

I’m done now with the ES6 Javascript code migration, but want to migrate the API to Phaser 3.

I understand that it is completely different, and states are now scenes and so on. Despite this, I’d love some guidelines on how those old objects match now the new P3 API. Is there anyone here who has followed this path?

Thanks in advance!

API Chains in Unofficial Help Center may help with this. Some methods are similar, but Phaser 3 often uses config arguments.

Overview

You can use game.scene.add() like Phaser 2’s game.state.add(), but it’s simpler IMO to add all scenes to the game config instead:

new Phaser.Game(
  scene: [ Boot, Preloader, MainMenu, Game ]
);

In a scene you should use the scene’s own plugin, this.scene, not the Scene Manager, e.g.,

this.scene.start('Game');

Draw Enemy Animation

You can create animations globally or (as in Phaser 2) on a sprite. For animations used on multiple sprites (enemies, explosions), it would be a little more efficient to use global animations.

In Phaser 3 animation frames can come from any texture, so you have to specify a texture key.

Set Object Anchor

Phaser has originX and originY instead of anchor. Most game object types have a default origin of (0.5, 0.5) already, so you don’t need to set this.

The Game Loop

There is no scene render() callback. There is a similar event callback, but you usually don’t need it.

Apply Physics

Phaser 3 this.physics is the Arcade Physics scene plugin and this.physics.world is its simulation.

There is physics.world.enable(), but it’s usually more convenient to use the physics.add methods:

this.bullet = this.physics.add.sprite(400, 400, 'bullet');

This creates an Arcade Physics Sprite with extra methods and a physics body.

Show Body Debug

This is done with debug: true in the scene or game Arcade Physics config instead.

Collision

There’s no kill() in Phaser 3. Similar is setActive(false).setVisible(false), but for physics sprites you should use

bullet.disableBody(true, true);

Mouse/Touch Movement

There’s no moveToPointer(). Use moveToObject() instead.

Firing Bullets

There’s no keyboard.isDown(). Create a key object in create() and then check its isDown in update().

Fire Rate etc.

I find it easier to create timer events for these things.

How To Play message

There’s no game object exists, but visible would be similar here.

A timer event would be easier for this.

Convert Bullets to Sprite Group

Use

this.bulletPool = this.physics.add.group();

There’s no outOfBoundsKill or similar. You could do this in scene update():

if (
  !Phaser.Geom.Rectangle.ContainsRect(
    this.physics.world.bounds,
    bullet.body
  )
) {
  bullet.disableBody(true, true);
}

Use getFirstDead() for getFirstExists(false).

There’s no general game object reset(). setActive(true).setVisible(true).setPosition(x, y) would be similar. For physics sprites, use, e.g.,

bullet.enableBody(true, this.player.x, this.player.y - 20, true, true);

Enemy Sprite Group

You could create global animations here instead.

this.anims.create({
  key: 'greenEnemyFly',
  frames: this.anims.generateFrameNumbers('greenEnemy', { frames: [0, 1, 2] }),
  frameRate: 20,
  repeat: -1
});
enemy.play('greenEnemyFly');

Randomize Enemy Spawn

this.enemyPool.countActive(false) is the dead (inactive) count.

Phaser.Math.RND is the random number generator.

Player Death

Check this.player.active or this.player.visible.

Convert Explosions to Sprite Group

You could create global animations here instead.

Refactoring create

There’s no Tile Sprite autoScroll, so keep the update code the same.

Using Relative Values

this.scale.width and this.scale.height are the game dimensions.

Enemy Health

Phaser 3 uses event emitters instead of signals. Game objects are also event emitters.

enemy.once('animationcomplete', () => {
  enemy.play('fly');
});

But it would be easier to use chained animations instead of an event handler here:

enemy.anims.chain('fly');

There’s no game object health in Phaser 3. You could use the state property for this:

enemy.state = BasicGame.ENEMY_HEALTH;

Then you need to do the damage calculations yourself.

Win/Lose Conditions, Go back to Menu

There’s no need to destroy everything, because stopping the scene will do that.

this.scene.start('MainMenu');

Diagonal Movement

I think this is supposed to be

shooter.rotation = shooter.body.velocity.angle();

Boss Battle

I think you need only 1 boss sprite here.

Sound Effects

MP3 audio is well supported now.

For single audio effects, skip sound.add() and use, e.g.,

this.sound.play('explosion');

instead.

Restore original game flow

No need to destroy things. Stopping the scene will do that.

this.scene.start('MainMenu');
1 Like