top of page
Search
  • cedarcantab

Danmaku using Phaser 3 (step 5): Accelerating Bullets

Updated: Oct 8, 2021

As mentioned in a previous posts, individual bullets are created as image game objects with physics bodies. As such the members of the game object or the Body can be set to manipulate the bullet's behaviour. So far, the most important member that has been utilised is the game object's velocity, which makes the bullet 'fly' automatically.


If you had examined my code from previous examples, you might have noticed the following piece of code within the fire() function of the Bullet class. In prior examples, this was not used but this is in fact the piece of code that allows us to set the acceleration vector of the physics body underlying the bullet game object. We just need to pass the magnitude of the acceleration vector as a parameter, in conjunction with the direction of travel, from the Danmaku Class via the Bullet class fire() method.

this.scene.physics.velocityFromAngle(
      this.shootAngle,
      this.acceleration,
      this.body.acceleration
    );

Although the fundamental content of the Bullet class has not changed, I have made some cosmetic changes like changing some of the parameter names to make it (hopefully) easier to read. For completeness the entire Bullet class code is reproduced below.

class Bullet extends Phaser.Physics.Arcade.Image {
  fire(config) {
    this.enableBody(true, config.x, config.y, true, true);
    this.body.collideWorldBounds = true;
    this.body.onWorldBounds = true;

    this.shootAngle = config.shootAngle || 0; // this is the direction in which the bullet should shoot out at.
    this.bulletSpeed = config.bulletSpeed || 300; // this is the speed of bullet travel. default set to 300.
    this.acceleration = config.bulletAcceleration || 0; // this is the acceleration of bullet. defaults is 0.
    this.angle = config.bulletAngle || 0; // this is the angle of the bullet image
    this.body.angularVelocity = config.bulletAngleVelocity || 0; // this is the angular velocity of the bullet image
    this.setTexture(config.bulletType); // set the texture of the bullet
    // set the velocity (vector) of the bullet in accordance with the speed (bulletSpeed) and direction (shootAngle)
    this.scene.physics.velocityFromAngle(
      this.shootAngle,
      this.bulletSpeed,
      this.body.velocity
    );
    // set the acceleration vector of the bullet in accordance with the acceleration passed as parameter and direction (shootAngle)
    this.scene.physics.velocityFromAngle(
      this.shootAngle,
      this.acceleration,
      this.body.acceleration
    );
  }
  onWorldBounds() {
    this.disableBody(true, true);
  }
} // end of Bullet Class

Now all we need to do is make sure that there is a way to pass the acceleration parameter via the extended Danmaku class. This is not a big change, but the entire extended DanmakuWrapper class code is reproduced below, with the important changes highlighted in bold.

class DanmakuWrapper extends DanmakuCore {
  constructor(scene, config) {
    super(scene, config.x, config.y, config.bulletSpeed, config.timeBetweenBullets, config.bulletType);

    this.angle = config.shootAngle || 0; // set the angle at which to shoot. default is 0, which is to the right
    this.body.angularVelocity = config.angleVelocity || 0; // default is 0
    this.bulletAcceleration = config.bulletAcceleration || 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() {
    const bullet = bullets.getFirstDead(false);
    if (bullet) {
      bullet.fire({
        x: this.danmakuPosX, // the bullet is fired from the middle of the Danmaku class (ie the spawner)
        y: this.danmakuPosY, //
        shootAngle: this.angle, // direction in which the bullet is fired
        bulletSpeed: this.bulletSpeed, // the speed of the bullet
        bulletAngle: this.angle, // make the bullet face the direction in which it is fired
        bulletAngleVelocity: 360,
        bulletAcceleration: this.bulletAcceleration,
        bulletType: this.bulletType
      });
    } // end of fire method
  } // end of fireweapon method
} // end of DanmakuWrapper class

You add the acceleration parameter to the DanmakuWrapper class when it is instantiated, which can in turn feed that to the bullet class, via the fireweapon() method.


If you set bulletAcceleration to a positive number, the bullet - obviously - accelerates, hence the spiral becomes less 'spirally'. Interesting things happen when you set bulletAcceleration to negative. The bullet will decelerate (i.e. slow down) and eventually flies backwards (if it doesn't fly off the screen and disappear - remember the bullets are destroyed automatically when collide with the edge of screen - before it starts travelling backwards).


There are a lot of maths involved in making bullets fly in different directions with velocity, acceleration etc., but it is made so easy with Phaser 3 framework, compared to the days when I was programming in Basic in the early 80's!


The entire code as a Codepen Pen is available below for your perusal.



Danmaku which shoot bullets with acceleration


記事: Blog2_Post
bottom of page