LuaSTG Pattern Making Tool-Spawning a Bullet

From LuaSTG Wiki
Jump to navigation Jump to search

If you look at a boss fight from Touhou games, it is very likely that you will see lots of bullets - no matter the difficulty of the game - on the screen moving in simple paths but together forming a complex looking pattern. When you look closer, often you would found that visually distinctive patterns share some surprising similarities in their spawning mechanics.


As somebody who has tried writing scripts for those patterns myself, I've been looking for ways to understand those similarities better, and exploit them to improve the efficiency of scripting. The reason is that I see lots of repetitive works done in scripting those patterns, and the resulting scripts are one-time-use as you would not use any parts of the code in another script in the foreseeable future, neither do the similarities between two such scripts necessarily seem obvious even when they implement pretty much the same thing. I believe this is due to the default way of implementing patterns directly with simple loops (that you see in general purpose programming languages) is often redundant in its representation.


To solve these issues, I will introduce an appealing alternative method to represent patterns in comparison to simple loops. This method aims to be more iteration-efficient by reducing redundancy (replications) in representation of a pattern script and offers an intuitive view in which representations of two mechanically similar patterns will look alike. In the second part of tutorial, I will introduce a more practical tool that uses this method, which is the in-game pattern editor.


This part of the tutorial will focus on what the method is and its basic ideas. As a starting point, I will briefly talk about some basic challenges that you may encounter when making a pattern with simple loops (I assume you already have some ideas on how to overcome them). Then I will introduce an algorithm I wrote that forms the backbone of this method, along with lots of stuffs about related knowledge.


We will start from something simple, let's talk about ways to spawn a single bullet.


The Simplest Case[edit | edit source]

Sometimes the behavior of even a single bullet can be quite complicated, therefore some assumptions can be helpful. We assume that there is a function SpawnBullet(image, x, y, a, v) that:

  1. The bullet will spawn at the same frame SpawnBullet is called, i.e. SpawnBullet spawns a bullet in the game immediately.
  2. The bullet will have a sprite of a still image, the image is specified by the image parameter.
  3. On spawn, the bullet will appear at position (x, y)
  4. After spawn, the bullet will move in the direction of a, with a speed of v distance units/frame.
  5. After spawn, the bullet's moving direction and speed never changes, until it eventually gets deleted by the game


Using this function we can spawn a bullet anywhere in the screen with arbitrary velocity and sprite image. Note besides directly calling the function and fill its parameter list to spawn a bullet, there are a few other styles to pass the parameters:

  1. You may define a function that accepts an array of parameters
  2. Or you may even give names to each parameter in the array (here the array becomes a table/map/dictionary/whatever you call it)
pseudo code of spawning a bullet in three different ways


The performance may differ among different methods, but all there methods work and will produce the same results. We will be using the first method and the third method for the rest of this tutorial. The reason for this is that both methods have their own advantages. The first method is short, simple and easy to understand. The third method allows its parameters to be set dynamically, and the table itself can be reused for spawning several bullets; additionally we can give each variable a name, which would be helpful for using string names to refer to the variables inside the program.


This means that we can use the string "v" to retrieve speed from table, similar to using the position index 5 to retrieve speed from array.


An example continuing from the pseudo code would be:

table["v"] == array[5] // will evaluate to true


where table["v"] is another way of writing table.v. (this is allowed in Lua) Now we've learned how to spawn one bullet, in theory we just need maths to spawn any kind of patterns, but there are quite a lot of problems that need to be solved. They will be discussed one by one in the following tutorials.