top of page
Search
cedarcantab

Danmaku using Phaser 3 (lesson 37 Part 2): NWAY revisited

Updated: Nov 29, 2021

I continue my documentation of the substantial changes I have made to my NWAY code.




I posted a picture of a danmay which shoots bullets from a point that is away from the centre of the danmaku object, and appears to move, and the bullets all fly downwards. In order to achieve this, I have had to create even more parameters.


Additional parameters to shift the position of the cannon

First to be specify how far away from the centre of the danmaku to fire from, I created the following 2 parameters to specify the relative position of the firing origin.
  • danmakuConfig.vOffset = this.danmakuVOffset --- vertical offset - the shot origin is placed Voffset pixels away from the danmakuOrigin. the vertical and horizontal is from the perspective of the angle of the cannon being "up". so with the cannon angle at zero (i.e. pointing right), vertical is to the right. horizontal is to the bottom. I can not figure out the best name for this.

  • danmakuConfig.hOffset = this.danmakuHOffset

Simply adding vOffset to a normal spiral has quite a dramatic impact. The danmaku at the top of this post combines a offset spiral with exploding bullets, with the parameter set below.


  danmakuPattern.push({
    name: "ROTATING EXPLODING BULLETS",
    danmakuConfig: {
      vOffset: 100,
      countA: 1, // cannons in each NWAY
      angularVelocity: 360, // angularVelocity
    },
    cannonConfig: {
      shotType: "NORMAL",
      numberOfShots: 20, stopShotsTime: 4000,
      timeBetweenShots: 50,
    },
    bulletConfig: {
      speed: 50,
      texture: "eyeballMID", frame: 3
    },
    bulletTransform: {
      class: "EXPLODE",
      stage1Time: 800,
      count: 6,
      speed: 50,
    }
  });

User of higher order array functions


In the new setUpCannons function, I have made more use of JS array related higher order functions which has made the code much more compact. For example, the previous coed to set up the cannon shot speeds array for the "SPREADQ" shot class was as follows.


case "SPREAD":
  for (let i = 0; i < this.spreadGroupCount; i++) {
    cannonsInGroup = [];
    for (let j = 0; j < this.danmakuCount; j++) {
      cannonsInGroup.push(this.bulletSpeed + this.bulletSpeedVariance * i);
    }
    cannonShotSpeeds.push(cannonsInGroup);
  }
  break;

The new version of the code is as follows (note, the name of some of the variables have been changed.

case "SPREAD":
  speedArray.push(...new Array(cannonCount).fill(bulletSpeed).map((item,i) => new Array(anglesArray.length).fill(item+shotAcceleration*i)))
  break; 

In the previous version of the code, the following were the parameters for the spreadshot.

  • spreadGroupCount = this.spreadGrouCount

  • bulletSpeedVariance = this.bulletSpeedVariance (ie the variance in speed of each successive group of shots)

Now the parameters have been turned into properties of the cannonConfig

  • cannonConfig.count => cannonCount

  • cannonConfig.acceleration -> shotAcceleration

However, the basic logic is the same.


Ability to enforce a specific bullet bearing

I have also created a new parameter, bulletConfig.bearing = this.bulletBearing. If this is not set, the bullet is fired in the direction that cannon is facing (default). However, if a number is given, then the bullet will always fire in that direction, irrespective of the cannon direction. a little bit interesting when combined with nway + offset.


With the above changes (excluding a lot of other "under-the-hood" changes to parameter names etc), I can now have danmaku that fire bullets from points away from the centre of the danmaku, and in a fixed direction. The danmaku pictured at the top of the previous post was created with the following parameter set.


danmakuPattern.push({
    name: "SWIRLING BULLETS",
    danmakuConfig: {
      vOffset: 100,
      countA: 3, // cannons in each NWAY
      angle: 90, // danmakuangle
      angularVelocity: 180, // angularVelocity
    },
    cannonConfig: {
      shotType: "NORMAL",
      acceleration: 20, 
      timeBetweenShots: 50,
    },
    bulletConfig: {
      speed: 150,
      bearing: 90,
      texture: "roundMID", frame: 4
    }
  });

"PARALLEL" no longer danmaku classses


The flexibility of the new set up (with the getArcAngles function and the setUpCannons function structure) means that PARALLEL danmaku could be combined with Nway, so that you can have parallel cannons being fired from each spoke of an nway (or even multiple nways).


It also means that you can fire OVERTAKE" or "SPREAD" shots with PARALLEL danmaku.


Combining the PARALLEL with NWAY in combination with the new optionality to offset the cannon positions away from the danmaku centre means you can now create danmaku like below.


  danmakuPattern.push({
    name: "LEFT ROTATING OFFSET PARALLEL BULLETS",
    danmakuConfig: {
      type:  "PARALLEL",
      hOffset: 100, // horizontal offset
      width: 70, // horizontal "breadth" of the lined-up cannons 
      countB: 3,
      angle: 90, angularVelocity: -30,
      multiple: 2 
    },
    cannonConfig: {
      fireRate: 300,
      numberOfShots: -1,
    },
    bulletConfig: {
      class: "NORMAL" ,
      speed: 100,
      texture: "daggerMID", frame: 6
    },
  });


Summary of addition of new parameters, and changes in parameter names


As if the above re-write is not enough I have change the names of many of the key variables.

  • bulletConfig: bulletType which has been the object to define bullet specific parameters has now been renamed to bulletConfig.xxx to be consistent with danmakuConfig and cannonConfig

  • washer: previously an indepent parameter has now been moved to a property of danmakuConfig. The properties of washer parameter remains the same.

    • washer.swingRange

    • washer.cycleLength

    • washer.swingType

  • this.danmakuWasher: this.washer has been renamed to danmakuWasher

  • timeBetweenShots, formerly a property of bulletType has now been moved to be a property of cannonConfig

The parameter set reflecting all the changes, to create the waving 8-way circle first created in lesson 13 is shown below as illustration of the new variable names.


  danmakuPattern.push({
    name: "WAVING 8-WAY CIRCLE",
    danmakuConfig: { 
      countA: 8, // number of spokes
      angle: 90, // direction in which the primary cannon faces.  
      washer: {
        swingRange: 30,
        cycleLength: 500,
        swingType: "Linear"
      }
    },
    cannonConfig: {
      angleRange: 360, // used to n-way type. angle range across which cannons are positioned.
      fireRate: 100, // time between bullets in ms
      numberOfShots: -1, // how many times to shoot the weapon in succession
    },
    bulletConfig: {
      class: "NORMAL",
      speed: 150, // speed of bullets fired from cannon
      texture: "roundMID", // specify the bullet image to be used,
    },
  });

Simulating Toho's famous bullet hell patterns

With the new changes, I have tried to simulate one of the famous Toho bullet hell patterns, this time the spell card titled 秘弾 「そして誰もいなくなるか?」from the game 東方紅魔郷 - or at least, one element of it that has bullets firing from all four sides. My attempt was created with the following parameter set.

  danmakuPattern.push({
    name: "x10 PARALLE BULLETS SHOOTING UP FROM ALL SIDES",
    danmakuConfig: {
      countA: 4, // 2 cannons (ie 2-way)
      type: "PARALLEL", countB: 10, // 15 parallel cannons at end of each of the 2-way spokes
      vOffset: -WIDTH/2+10,
      width: 500,
    },
    cannonConfig: {
      class: "OVERTAKE", acceleration: 20,
      numberOfShots: 2,
      stopShotsTime: 8000,
      fireRate: 100, // time between bullets in ms
    },
    bulletConfig: {
      speed: 50,
      texture: "roundMID", frame: 5
    },
  });


As I mentioned, this is only a very small part of the "real thing". And in fact, it is one big flaw with my simulation. In the real version the bullets from the top and bottom are not fired from the same X-positions so fly "past" each other, as opposed to "fly over" each other. This is for another day. This actually makes a very big difference in terms of visual effect - it makes me realise how much effort and consideration goes into the commercial Toho games.


And that's it. This post was more for me to document what I have done, but here is the CodePen, if you are interested to see what I have done.




コメント


記事: Blog2_Post
bottom of page