I've talked before about making a template of some kind for people to use. While I'm not currently working on one directly, I am trying to streamline certain parts of my workflow, and that inherently means making something that's easy to use, but flexible.
Part of the process of making a game is enemy behavior, or rather, the actions an enemy can perform. There are a few methods for making an entity "do" something in GM.
You can have every action as a different object,
Or all the code can be contained within one object, with each action/state being represented by a number.
Initially, I found it easier to use the first method, as when an object is created it has it's own set of events (create, step, animation end, etc). It also made it easier for me to debug games since an issue with an action could be easily isolated, and messing up an object wouldn't affect the rest.
However, it isn't really practical as games become more complex, and as I've become better at programming my original reasons for using it have become less relevant. GM also added #region which is very helpful for keeping code separated.
That said, for the second method everything an object can do is separated into a state. For example, a simple jump upwards might be state 5. So switching to a jump is essentially just;
state = 5
So, if you wanted a character to do this,
You can separate it into two states
- move until edge (1)
- wait and turn (2)
So, the object hits an edge, changes the state to 2, it plays out the state, and then it's built into state 2 that it returns to state 1 at the end.
This is basically the manual version of the method; every state does something very specific. However, despite the fact that "wait" and "turn" might be a part of other actions, they are combined, and only go back to state 1. This means that if I wanted to add a new move that involves waiting and turning before doing an attack, I need to make a separate set of states.
So instead, you can do things in a sequence. Let's say you have the following states;
- pace (1)
- wait (2)
- jump back (3)
- jump forward (4)
- melee attack (5)
- neat pose (6)
If you wanted an enemy to jump back, do a pose, jump forward, attack, wait, and then go back to pacing. Instead of programming each state to lead into the next manually, we can program a system that plays them in order based on a simple sequence of numbers. This would be the above sequence.
sequence = [3,6,4,5,2,1]
Thus, that "move" is sequence 0.
By doing this, you can set a sequence to play out, rather than a single state. This also comes in handy for cutscenes, where you need to be able to animate characters quickly and easily.
That said, the question becomes, how much control do I want/need, and how should it be formatted? If you have a state for "jump", what should determine how far, or the direction? For example, you could have each variation be a separate state;
-move around (1)
-low jump (10)
-high jump (11)
-low jump back(12)
-high jump back(13)
a low jump back and then shooting would be
sequence = [ 12 , 2 , 1 ]
Or, you could be more complicated with the arrays, such as having modifiers included in the sequence. So instead it might be written like this;
sequence = [[12,5,3],2,1]
In either case, the more more states you eventually have, the more difficult it would be to remember them all. It might make more sense to name states with strings;
sequence = ["jump back", "shoot", "move around"]
Which I guess would looks like this with modifiers
sequence = [["jump back",3,1],["shoot",bullet_1_ob,5],"move around"]
Yikes. Makes sense but probably looks intimidating.
Instead of having everything in one array, you could also split controls into multiple optional arrays.
sequence = ["wait","jump","shoot","wait","pace"]
sequence_xspeed = [0,2,0,0,0]
sequence_sprite = [0,0,0,pose_sprite,0]
sequence_time = [10,0,0,50,0]
The first chooses the states to play in sequence,
The second chooses the xspeed modifier for each state,
The third overwrites the sprite that the state displays, with 0 using the default.
The fourth would change the wait time.
Using only sequence with nothing else would use the states with defaults. Could also include states like "jump_back" so that there's a quick and dirty method if more control isn't required.
Of course, it's hard to say how useful so many options would be outside of making a template since; at the end of the day just programming what you want is generally going to be faster for things like enemy specific attacks. Where it would probably be the most useful for me personally is simply creating movement patterns, and for cut-scenes where you definitely need some kind of system.
Words words words...
Anyhow. Let me know if you know of any good standard practice for dealing with states. Maybe something that other engines like RPG maker do particularly well, or stuff you'd like to see when I do eventually make a template.
Back to work...