LuaSTG Pattern Making Tool-Extensions

From LuaSTG Wiki
Jump to navigation Jump to search

There are some extension features for the matrix model introduced to make it easier to use. I will introduce some of them in this tutorial, and for the rest of them that are related to a graphical interface, I will leave those features for the second part.

Column Script Constructor[edit | edit source]

Matrix Entry Scripts[edit | edit source]

Tricks with Delay Manipulation[edit | edit source]

Recall in a matrix of parameters, there are two delay values for each column, col.s_t and col.s_dt. The first decides the waiting time before the loop starts, and the second decides the waiting time between repetitions. You may notice the unlike other rows, there is an implied constraint here on the delays, which is that both delays can not be negative. This is because it doesn't make sense to wait a negative amount of time.


Consequentially, we are left with two fields that can only take positive values, and when we enter negative values on those fields the result is undefined. What if we can interpret negative values inside those fields in some meaningful way such that occasionally entering negative values may be useful?


There is a way we can interpret those values. We start by putting some necessary requirements on how the spawned object behave. We assume there is a easily computable function spawn(spawn_parameters, t) that spawns an object with a "future state" as if it was spawned t frames earlier. Usually the only states affected by the time t will be position and velocity. For example, for the spawn function SpawnBullet(x, y, a, v), we may modify the function signature as SpawnBullet(x, y, a, v, t) and rewrite it so it spawns bullet at position x' = x + t * v * cos(a), y' = y + t * v * sin(a).


When s_t is assigned a negative value (in actual implementation the sign is flipped for s_t, so it would be a positive value), instead of waiting any frame at all, we can use the spawn function to generate it as if it was generated -s_t frames earlier. The logic is that normally with a positive value we would wait s_t frames before spawning a bullet, therefore the spawn happens s_t frames later than when the waiting starts. With a negative value we want to spawn the bullet -s_t frames earlier as opposed to later, but of course spawning bullets in the past is not possible. We calculate its state if it has spawned -s_t frames earlier and spawn it with that state. After that we pretend it is spawned in the past, though it really is just spawned at frame 0 with a different state.


When used correctly, pre-generation of objects can give a nice looking spawn effect. However, not all objects can support decimal number of frames, some objects' position may only be well-defined for integer value of time. For them, we may simply ignore self.s_t in the definition of the output column and type in non-negative values in their matrices, the result will be the same as without this feature.


Interestingly we can interpret a negative s_dt value with some meaning as well, though I believe this does not have as much practical value. When a negative s_dt is given, the associated loop can be executed with index i looping backwards from s_n - 1 to 0, with a delay time |self.s_dt|. This comes with two disadvantages, one is that the transition in value of s_dt is not as simple to understand as it would be with only non-negative value, since the total execution of time (interval between the first repeat and the final repeat) of the loop would be |self.s_dt * (self.s_n - 1)| which contains an absolute value operator. The other disadvantage is that, though we can change the sign of s_dt before the start of the loop, we still can not change the sign of s_dt during the loop, as doing so makes no sense.


Single 2d Vector Interface for Both Standard and Polar Coordinates[edit | edit source]

In testing of the tool, I found that the need to set and/or access a 2d-position or velocity vector in both standard mode (i.e. (x, y)) and polar mode is frequent and also a pain to deal with. For example, when a bullet requires both the direction and magnitude of a velocity vector as its initial parameters, we need to convert the velocity to polar mode if it is originally represented in the form (vx, vy). We can use a column script for this case, but we need to define other ones as well for other cases E.g. convert polar to standard, or even doing so in the middle of a matrix.


If we define a vector for this, the problem would be solved, but we can no longer directly access the x, y components of the vector, as we need to write cur.vpos.x, cur.vpos.y etc. (and within the syntax of Lua there are other potential problems to this approach).


An ideal solution is allowing all common representations to be accessed directly in a simultaneous way. That is, allowing set and get of .x, .y, .a, .r, .xy, .ar for every incrementable variable pair that represents a vector. A vector will be originally belong to one of the two modes, say, the standard mode. When an access to one of the variable .x or .y or the vector .xy comes, the vector will directly provide the values; same for modifying those values. When an access to .a, .r or .ar comes, the vector will compute the values for polar mode and then provide the values. When a modification on polar mode variables .a, .r or .ar comes, the vector will set the values and then invalidate the variables .x, .y.


The actual names referred to those six interfaces (.x, .y, .a, .r, .xy and .ar) can vary allowing more than one vectors exist for a single column. We may specify those names in the variable name field in a matrix much like for a normal variable.


This is something that can be done but has not been implemented nor tested because of my limited technical skill in writing parsers (or the code compilation process in general).