In all the examples up to now the Danmaku fired bullets at fixed intervals in an endless loop.
As a bit of variety how about if we had the Danmaku fire intermittently? For example, fire a round of 3 bullets rapidly fired at short fixed intervals, then a break, then another round of 3 bullets, etc.
I could do this using another manual counter like in the very original Danmaku. However, how about using Phaser's many timer events in some kind of combination?
In the previous 2 examples, we used the Phaser 2 timer event to call back the fireweapon() method at fixed intervals in an endless loop, i.e. a "looped timer", reproduced below for information below.
// create time event to call the fireweapon method 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
Use of repeat timer
There is a variant of this called a "repeat timer" which calls back a particular function a prescribed number of times, which simply involves changing the "loop: true" to "repeat: n" which calls the callback function n+1 times (I don't know why it's n+1, as opposed to n). However, this timer, by definition, "dies" once it completes executing the prescribed function n+1 times. There is a method to reuse timer events. Hence, what if we created another timer event which executes the above repeat event, at fixed intervals? With a (quite) a bit of playing around I managed to get the result I want - the code (included in the constructor function of the extended Danmaku class) is reproduced below.
// create timer event to call the fireweapon method at frequency determined by this.timeBetweenBullets; ie fire one "round" of bullets
const timerConfig = {
delay: this.timeBetweenBullets,
callback: this.fireweapon,
callbackScope: this,
repeat: this.bulletsInRound - 1 // repeat n+1 times
};
const machineGun = new Phaser.Time.TimerEvent(timerConfig); // end of timer event
// create a timer event to fire rounds at frequency determined by this.timeBetweenRounds
this.repeatWeaponFire = scene.time.addEvent({
delay: this.timeBetweenRounds,
callback: fireround,
callbackScope: this,
loop: true
}); // end of timer event
fireround(); // call fireround once immediately since the timer will wait before firing first round upon instantiation of this Danmaku class
function fireround() {
machineGun.reset(timerConfig); // seems reset of config of the timer event required after each time it is completed
scene.time.addEvent(machineGun); // call the timer event that controls the firing of each round
}
Reset timer? Closures? Scope?
The bit I struggled the most (and I don't know if this is an elegant way of doing this - please comment) is in bold. First, it took me a fair bit of time to realise that you need to reset the config of the machineGun timer otherwise it refuses to fire up after the first round. The other bit I am unsure about is declaring a function within the constructor function. If I declare the function (which is simply 2 lines of code) outside the constructor function, it refused to work. It is probably something to do with scopes and closures but I am not knowledgeable enough to understand whether there is a better way. Anyway, it seems to get the job done.
Tidying up
Other than the above, I made a few other changes which are of cosmetic nature
changed the bullet image to "bullet9"
set Danmaku angular velocity to zero (so bullets are fired in the same direction - straight down - all the time)
set bullet angular velocity to zero (bullet itself does not rotate)
added a bulletType as a parameter to the Danmaku class, so that you can specify bullet type when instantiating the Danmaku class, as opposed to setting it up in the bullets class
moved the enemy ship higher up the screen, so that we can see a few more "rounds"
Finally, I have changed the name of the extended Danmaku class as Intermittent. The previous examples built on each other, but I think I will keep this Danmaku class separate from those that fire continuously.
As always, the entire code in as a Codepen Pen is available below for your perusal.
Commentaires