Define Bullet

From LuaSTG Wiki
Jump to navigation Jump to search

A define bullet node defines a custom bullet type.

A custom bullet type is a LuaSTG object class (see Game Object). In stages/boss fights bullets of this type can be created with Create Bullet nodes. There are many similarities between a custom bullet and a simple bullet. However, a define custom bullet node accepts parameters under its on init and create task nodes can be put under there.


Parameters[edit | edit source]

Define Bullet Node[edit | edit source]

Here is a list of parameters for define bullet node.

Parameters Function
Name (string without quotations) Name of the bullet, this can be used to identify the bullet type defined in a create bullet node
Difficulty (string without quotations) If different difficulties of the game use the same bullets with different behavior, this can be set to distinguish between those bullets. Essentially this creates a brand new type of bullet for each difficulty

Use of the Difficulty parameter is not recommended in most cases, as it encourages code duplications. It is recommended to use parameters to control the bullet instead.

This node will be translated to a LuaSTG object definition when the script is run. The variable that holds the class will be an attribute of the list _editor_class. More precisely, it will be "_editor_class[Name:Difficulty]", where Name and Difficulty are strings specified in the above parameters.


On Init Node[edit | edit source]

Define bullet node will always come with an on init node. The parameters of the on init node controls some attributes of bullets on initialization. Here is a list of parameters for this particular type of on init node.

Parameters Function
Parameter List (parameter list) A list of parameters to be filled in a create bullet node that uses this type of bullet. There can be zero or more parameters, separated by commas if more than 2 parameters are in this list. These parameters can be used to make bullets of the same type do different things. An example of parameter list would be initSpeed, accelerationTime, finalSpeed
Style (LuaSTG object class) The type of the bullet on creation E.g. ball_big
Color (number) The color of the bullet on creation. Some types of bullets like ball_huge do not have full color range
Stay on Create (boolean) If true, the bullet will not move during the mist phase. More precisely, the tasks under the bullet will not get executed until the bullet mist phase is over. See Stay on Create section below for more details
Destroyable (boolean) If true, the bullet will not get canceled by player bomb/miss bullet clear. This sets the .group attribute of the bullet to GROUP_INDES instead of GROUP_ENEMY_BULLET. However, the bullet can still be deleted at the end of spell card, or by clear bullet node if Clear indestructible is set to true

Parameter list works in the same way as the parameter list of a Lua function definition. It defines zero or more variables that can be used inside the on init method.


Sub-Bullets[edit | edit source]

Bullets can be spawned inside a custom bullet task, similar to how recursion works in programming. This is done in the same way as when bullets are spawned normally, which is to put a create bullet node inside the task.


Examples of Use[edit | edit source]

Example 1[edit | edit source]

In this first example, we will define a custom bullet with 4 parameters that goes in a straight path with fixed speed, same as a simple bullet with default settings. This comes with a twist - the bullet will be deleted after 120 frames, by the task created by on init function.

Define Bullet Example 1- bullet deleted after a fixed time.png

Then we can put a create bullet node in a spell or a stage as follows, and run the game.

Define Bullet Example 1-1.png

We will see that a bullet appears at the center of the screen, moving downwards in constant speed. Two seconds (120 frames) later, the bullet disappears. In an actual script, it may be better to parametrize the deletion time as well, adding it to the 5th parameter of the bullet, so we have control over the time it takes before a bullet disappears when tuning the parameters of a pattern.


Example 2[edit | edit source]

For the second example, we will define a bullet that moves in one direction. However, this time it will have accelerating speed - its speed increases for a period of time, then stops increasing at some time.

Define Bullet Example 2- acceleration bullet fixed.png

self.rot = moveAngle at the start of on init is necessary, since the rotation of the bullet image is not immediately set when the bullet is created, but rather when the task starts executing in the next frame. This is different from the case when creating simple bullets.

Then we can create a bullet that accelerates from speed = 0 to speed = 3 in 120 frames. Notice the style and color parameters are in the parameter list, so we can specify the type and color of a bullet upon creation.

Define Bullet Example 2-2.png

When we run the game, we will see a bullet spawns in center, and slowly accelerates leftward.

If finalSpeed >= initSpeed, this can be seen as a special case of simple bullet as well, if Angle and Accel angle are set to the same, and Max Velocity is set to the end velocity. The difference is that in this case, you can use accTime to control the acceleration time of the bullet, instead of changing the magnitude of acceleration each frame.


Example 3[edit | edit source]

In the previous example, we see a pattern of controlling the movement of bullets through setting its attribute each frame (with SetV node). In this example, we will do the same thing, but by directly manipulating the position of a bullet (with attributes .x and .y).

We will define a bullet that takes spiral shaped path, named Archimedean spiral, which can be imagined like a straight line movement with constant speed - but in polar coordinates.

Define Bullet Example 3- spiral bullets.png

The function of the big block of code after on init is just to initialize the position and image rotation of the bullet when it is spawned. The last line self.navi = true specifies that the bullet will update its image rotation automatically, see Game Object. After initialization, the position of the bullet will be set each frame according to the parametric equation of Archimedean spiral.

Define Bullet Example 3-2 audio added.png

And we have made a pattern that cannot be done with simple bullets alone (without writing additional code). This example shows how the parameters of a custom bullets can be adjusted slowly as the time passes, which makes it a bit more engaging. It also shows how sound effects, boss charge and boss movement can be added into the spell along with the pattern itself.


Stay on Create[edit | edit source]

If stay on create is set to true, tasks of a custom bullets will not get executed until the bullet mist phase is over. See Stay on Create section of Create Simple Bullet for more details.


Deletion[edit | edit source]

On bullet deletion, a deletion effect will be left where the bullet was. In some versions of LuaSTG, the deletion animation will keep moving in the same velocity as the velocity of the deleted bullet in the last frame. Because this velocity is given by the .dx and .dy attributes automatically calculated by the engine.

This can lead to very obscure glitch when a bullet is deleted after it teleports (moves a long distance in one frame) from one place to another, especially when the teleportation happens upon bullet creation. There will be apparently a few small sprites flying around the screen in high speed, which are actually just bullet deletion effects that are moving really fast.


On Kill[edit | edit source]

When a bullet is killed, it will leave a faith point item by default, similar to bullet cancels in the game th10: Mountain of Faith.


Recommendations[edit | edit source]

  1. Try to define a few kinds of bullets that are general and cover your use cases well and master how to use them, rather than define a large number of custom bullets. It would be hard to keep track of all kinds of bullets in the latter case. You can think of this as using your existing bullets as much as you possibly can, except in special cases when complex behaviors are necessary.
  2. If a type of custom bullet is used very frequently, try copy its code (with names modified) and include somewhere in data. After that, you can define functions that directly spawns multiple bullets and just re-use those functions. For rarely used, or even half-frequently used bullets however, this would not be worth-while.