If you have played some of the Danmaku stype games, you would have noticed there are cases where the enemy would shoot a group of bullets which look like an n-way pattern where the bullets get further apart as they fly. They look simiar to n-way with accelerating bullets, however the individual bullets fly at constant speeds. What is happening is that "rounds" of bullets are fired at different speeds.
In this post we create such a danmaku pattern, which are called "spread" shots.
The principle is quite straight forward. You set up the cannon angles as you would do for a standard nway. However, you need to fire the nway shot n times (at at the same time) but each nway shot is fired at differing speeds.
First, to achieve this we will create the following new parameters for the danmaku object
danmakuType: SPREAD
spreadGroupCount: this is the number of nway shots to be fired at once (ie, the "n" referred to in the description above)
bulletSpeedVariance: this is the bullet speed differential of each nway shot (which are fired at once)
In the existing code, we have a setCannonAngles function to set up an array of cannon angles for nway (and any other patterns that fire more than one bullet in one shot). In a similar fashion we will create a function which sets up an array of bullet speeds, like below. For all danmaku patters so far, all bullets were fired at consistent speeds hence no need for such an array; hence in the below code, apart from spreadshots, we are creating an array of one speed. In a for-loop simply, we loop through spreadGroupCount number of times, adding bulletSpeedVariance to this.bulletSpeed to get successively higher speeds.
(As a side note, we had already created an option to to randomise bullet intervals for nway - in that code, we are changing the delay property of the timer event itself).
The bullet speeds are held in an array called bulletSpeeds.
setBulletSpeeds(danmakuType) {
const bulletSpeeds = []
switch (danmakuType) {
case "SPREAD":
for (let i = 0; i < this.spreadGroupCount; i++) {
bulletSpeeds.push(this.bulletSpeed + this.bulletSpeedVariance * i);
}
break;
default:
bulletSpeeds.push(this.bulletSpeed);
}
return bulletSpeeds
}
Changed the setCannonAngles function slightly
I have also changed the setCannonAngles function slightly in that whereas before I used to set the randomise element within the setCannonAngles function, and store the randomised version of the angle in the array, now, the randomise element is added within the fireweapon (not fireShot) function - making the code slightly more compact, and flexible.
Revised fireweapon function (now renamed fireShot)
Once we create such an array, the rest is easy. We simply loop through the created array within the fireShot function, within the for-loop that loops through the cannon angles array.
fireShot(scene) {
// first check if there is a set to aim at. if so, reset the cannon angle to the target
if (this.target) {
this.aimAt(this.target);
}
// is the random delay flag set? if so, add random element to timeBetweenShots
if (this.randomBulletDelay) {
this.repeatFireTimer.delay =
this.timeBetweenShots +
Phaser.Math.Between(-this.timeBetweenShots, this.timeBetweenShots);
} // to randomise the fire interval of shots or not
const cannonAngles = this.setCannonAngles(this.danmakuType); // set an array of cannon angles for NWAY and other multiple cannon danmaku
const bulletSpeeds = this.setBulletSpeeds(this.danmakuType);
// cycle through the array of cannon angles, and fire bullets accordingly
for (let i = 0; i < cannonAngles.length; i++) {
if (this.bulletSound) {this.bulletSound.play()}
// cycle through the array of speed array, eg used for SPREAD shot
for (let j = 0; j < bulletSpeeds.length; j++) {
const direction = cannonAngles[i] + this.randomiseDirection();
const bullet = this.munitions.getFirstDead(false);
if (bullet) {
bullet.fire({
x: this.x, // the bullet is fired from the middle of the Danmaku class (ie the spawner)
y: this.y, // the bullet is fired from the middle of the Danmaku class (ie the spawner)
shootAngle: direction, // direction in which the bullet is fired
bulletSpeed: bulletSpeeds[j], // the speed of the bullet
bulletAcceleration: this.bulletAcceleration,
bulletAngle: direction, // make the bullet face the direction in which it is fired
bulletAngularVelocity: this.bulletAngularVelocity,
bulletTexture: this.bulletTexture,
bulletFrame: this.bulletFrame,
bulletType: this.bulletType
}); // end of bullet fire method
} // end of if statement which checks whether bullet is null
} // end of for-loop to loop through the bulletSpeeds array
} // end of the for-loop to loop through cannonAngles array
} // end of fireShot method
Other minor changes
I have once again changed the names of some of my important properties, including timeBetweenBullets and fireweapon() which have been changed to timeBetweenShots and fireShot() respectively.
And that's it! As usual, the CodePen is available below for your perusal.
Comments