In the previous post I created the most basic of danmaku patterns, namely shooting consecutive bullets in a straight line. The bullet class was defined to fly automatically using Phaser 3 arcade physics (i.e., by setting body.velocity).
Using Phaser's timer event
The frequency of firing was controlled by 'counting' a timer using if statement which necessitated calling the bullet firing function from the update function; ie the fireweapon() function would be called every frame (every 60th of a second), and each time it is called, the fireweapon() function would check the time elapsed since the last time a bullet was fired and if the prescribed time delay has not yet passed, it would return and not execute anything. If the required time had elapsed, then the function to fire a bullet would be called and the timer would be reset. However, there is something called the Phaser 3 timer which can be set to execute a particular action at fixed intervals.
Adding the following piece of code to the constructor() of DanmakuWrapper does exactly just that.
// create time event to call the fireweapon methods at frequency determined by this.timeBetweenBullets
this.machineGun = scene.time.addEvent({
delay: this.timeBetweenBullets,
callback: this.fireweapon,
callbackScope: this,
loop: true
}); // end of timer event
Now, there is no need for all the counting of timers, and resetting of timers like in the previous example. And there is no need to call the fireweapon() method from the update() function every frame, like in the previous example since the method would be called automatically by the Phaser timer event created. Don't forget to delete the danmaku.fireweapon(elapsedTime) in the update() function, if you are editing the code from the last example!
Using Phaser 3's physics body to create a Spiral Danmaku
Using Phaser's timer event has simplified the code. However, at this point in time, the result is exactly the same as before.
I mentioned in the previous post that I have set up the danmaku class as a Phaser 3 physics gameobject for a reason. There are many factors associated with a physics body that can be used to control its behaviour. So far we have used the body.velocity attribute make the bullet fly 'automatically' at the desired speed.
As as well velocity, Phaser 3 physics body also has members called 'angle' and 'body.angularVelocity'. The former, as the name suggests affects the rotation of the body (in Phaser, angle = 0 is right facing, angle=90 is downward). The latter is the velocity of the angle. According to the Phaser docs, it is the rate of change of this Body's rotation, in degrees per second. If we set this to something other than zero, then the Body would move rotated at a specified rate by Phaser's physics engine. We can then use the angle of the body to determine the direction in which the bullet is fired - remember, from the previous example, the Bullet class and the associated fire() method took in a parameter for shootAngle!
This characteristic can be used to make the 'enemy' fire consecutive bullets in varying direction, giving the effect of a sprial. This is called the Spiral Danmaku or 渦巻弾 in Japanese.
The revised DanmakuWrapper class is shown below.
class DanmakuWrapper extends DanmakuCore {
constructor(scene, config) {
super(
scene,
config.x,
config.y,
config.bulletSpeed,
config.timeBetweenBullets
); // end of super
this.angle = config.shootAngle || 0; // default is 0
this.body.angularVelocity = config.angleVelocity || 0; // default is 0
// create time event to call the fireweapon methods at frequency determined by this.timeBetweenBullets
this.machineGun = scene.time.addEvent({
delay: this.timeBetweenBullets,
callback: this.fireweapon,
callbackScope: this,
loop: true
}); // end of timer event
} // end of constructor
fireweapon(elapsedTime) {
const bullet = bullets.getFirstDead(false);
if (bullet) {
bullet.fire({
x: this.danmakuPosX,
y: this.danmakuPosY,
shootAngle: this.angle,
bulletSpeed: this.bulletSpeed
});
} // end of fire method
} // end of fireweapon method
} // end of DanmakuWrapper class
Finally, I have changed the size of the canvas to 700x700 (in the previous post it was 600x700) and placed the enemy ship in the middle of the screen, to better show the spiralling effect. Otherwise, there are no changes other than those described above.
The entire code is available below.
Comments