Tuesday, July 17, 2018

Enemy states and formating



Sorry about the silence. Working on stuff, life stuff, etc.

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.

States
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.

Sequences

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[0] = [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.

Format

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)
-shoot (2)
-low jump (10)
-high jump (11)
-low jump back(12)
-high jump back(13)

a low jump back and then shooting would be

sequence[0] = [ 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[0] = [[12,5,3],2,1]

With every state having a set of optional modifiers. In this case 12 would be the state, 5 could be jump height, and 3 could be horizontal speed.

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[0] = ["jump back", "shoot", "move around"]

Which I guess would looks like this with modifiers

sequence[0] = [["jump back",3,1],["shoot",bullet_1_ob,5],"move around"]

Yikes. Makes sense but probably looks intimidating.

Other formats
Instead of having everything in one array, you could also split controls into multiple optional arrays.

sequence[0] = ["wait","jump","shoot","wait","pace"]
sequence_xspeed[0] = [0,2,0,0,0]
sequence_sprite[0] = [0,0,0,pose_sprite,0]
sequence_time[0] = [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[0] 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...



22 comments:

  1. Your concept of "sequences" seems to be a sort of pseudo-hierarchical state machine implementation, in that a sequence is itself a mini state machine. I'm not gonna nitpick cus I have no idea what your requirements are here, but I will say the stuff you're pointing out as ugly:

    "
    sequence[0] = [["jump back",3,1],["shoot",bullet_1_ob,5],"move around"]
    "

    looks more to be a problem with whitespace. Something like:

    "
    sequence[0] = [
    ["jump back",3,1],
    ["shoot",bullet_1_ob,5],
    "move around"
    ]
    "

    is obviously more readable (indentation would be better but it looks like blogspot eats whitespace). Now, if GML doesn't support use of whitespace like that, I guess you're kind of fucked there, in which case I'd try to represent sequences the same way you do states instead. (I'm not sure how that is; I'd assume your individual states are functions or objects but I know nothing about GML, so...)

    Regardless, you're probably already aware but the technical CS-y term for these things is "finite state machine", with many many variations of the concept. MUGEN characters are purely FSM-driven, and I think they just duplicate states for the most part instead of doing sequences. And honestly, I think you might be better off not coupling things that tightly; do you really wanna have to redo all of your cutscene logic because you decided your character's walk cycle should move her faster?

    ReplyDelete
    Replies
    1. I know it was ugly, that's why I said "yikes" afterwards lol. But Yeah, GM can have whitespace. It's possible that I'd write it like that, though if the goal is to make something people can use as a template, I think either form of it is a bit confusing looking. The user would be able to do it either way though, so far as white space goes.

      Sequences are simply a series of states tied together, so most objects would have their own set of sequences and states, rather than a global list. What would be duplicated would be basic things that are common, however one enemy's "jump back" can be different from another's if need be.

      As for how GM looks, here's a random BS example. In this example the enemy would walk back and fourth, turning at edges. When they get close to the player, they would attack, and then after the attack they would jump back. Once they hit the ground they would go back to moving. (all the collision code and such happens elsewere, of course)

      if state =1
      {
      if on_solid =0
      {
      xscale = -1
      on_solid = 1
      }
      xspeed = 1*xscale

      if abs(x - player.x) < 32
      {
      create = 1
      state = 2
      }
      }

      if state = 2
      {
      if create = 1
      {
      create = 0
      sprite_index = attack
      image_index = 0
      }
      if image_index = image_number
      state = 3
      }
      }

      if state =3
      {
      if create = 1
      {
      create = 0
      yspeed = -1
      xspeed = -1*xscale
      }
      if on_solid = 1
      state = 1
      }

      What I'd be using sequences for is if I wanted the enemy to attack 5 times and then jump back. That way I don't have to program it specifically, I just need to set the sequence to [2,2,2,2,2,3,1].

      The cutscene thing wouldn't really happen, since a state of "walk left" or "walk to a position" would have defaults. Changing the default value would change all defaults, while using a speed modifier would only change the situation where the state and modifier was used. So if you want to speed up all cutscene movement you could, but if you wanted a specific part to move faster, you could still do that as well.

      Delete
  2. Don't know much about GML, but if I had built a FSM like that, for enemy behavior, I would have each state contain its own arguments in chunks, stored similar to a JSON object, with k-v pairs. Internally, this would be represented by the target language's Dictionary object (can also be called Map, "List" or Associative Array).

    Each chunk could contain the function it seeks to replicate in the NPC behavior, along with any arguments you'd need to go along with it. Assuming each chunk MUST contain at least one key, (maybe call it "_type" or something), you can branch out from there. You can have an array of these chunks as part of a behavior value, with any "global" values existing higher up in the data hierarchy.

    If the number of behaviors is expected to be limited (based on the idea that more complex behaviors can be expressed by chaining simpler ones), this shouldn't get too unwieldy to branch out from.

    ReplyDelete
    Replies
    1. to clarify, the data chunk wouldn't have the actual functionality, just a name for the function STATE that you'd call from your actual branch code.

      Delete
    2. Some states would be general behavior, like exploring, chasing the player, etc, and would be a combination of settings.

      Other states are like "moves", in that they do a very specific individual movement and then return to the behavior state.

      Sequences in my case are multiple "moves" executed one after the other. Behavior states would generally only be at the end of the sequence so that it can return to normal movement and behavior.

      Also, things like sprite animation, collisions, etc, would mostly be handled outside of the states. That way I can move an object, and it will animated based on how it's moving automatically. (for example it will use a jump sprite if it's in the air, during behavior states)

      Delete
  3. My programming knowledge is mostly restricted to front end, but I remember reading a fairy recent interview with John Romero where he recommended Corona engine for making 2D games. If you have a moment you might want to check it out.

    ReplyDelete
    Replies
    1. Nah, not much reason to use other stuff. GM doesn't really limit me in any way at this point. If I were to learn something else, I'd learn Unity or Unreal.

      Delete
  4. I use Godot, so pretty much all my states are created in code.

    Entering and exiting states is split between detecting player input and at key points in the animation clips.

    An example of how this would work is, the player will hit the attack button sending the game character into the attack state. I use a simple bool to lock out further input while the attack is happening.

    The Godot animation editor allows you to animate pretty much anything, including the properties like transform, rendering, physics ect. So I usually will enable my raycast or colliders to match up with the players sprite.

    At the end of the animation clip I put in a key that links to a function that will send the PC back to a rest state (usually idle). If the PC is hit during the animation cycle they are sent to the hurt animation state that has a similar exit function.

    ReplyDelete
    Replies
    1. The actual control and programming part happens between changing states, states are simply a way of dividing what the object is doing.

      Delete
  5. What I'm going to say is probably really rude but I still think its for the best.
    I think your time on programming is wasted. Your art is great and programming a 2d game can be already done by underage.

    ReplyDelete
    Replies
    1. There are also people younger than me who are better at pixel art, better at music, and better at animation. Why do anything then?

      Because I don't want to just program, or code, or make pixel art; I want to make games.

      Delete
    2. Kudos for being able to do it all yourself. I almost flunked C++ in college, and pixel art is painstaking slow for me (plus I'm not very good at it). I'm thankful there are programs like RPG Maker, and also for the artists who take commissions. It's certainly expensive, mind you, but saves me a LOT of time.

      Delete
    3. I think most people could do it, in my case I just happened to start pretty early. I started drawing at a young age, and pixel art, GM, and music were all started at about the same time, early highschool.

      If you draw on paper, but find pixel art to be slow, I'd get a Wacom, even a cheap one. A tablet is pretty essential for pixel art, speed-wise.

      Delete
  6. I don't use any game engine but one thing confuses me.
    Why don't you try to organize them in maps with lists of the states in it?

    ReplyDelete
    Replies
    1. [1,4,6,8,9]

      Is a sequence of states, which is the only situation I would need to list a combination of states (which are actions). Not sure what you mean by map.

      Behaviors like "bounce of walls" or "slow to a stop on the ground" could also be an array, where each state has an array of behavior, in addition to the basic movement. That's the closest thing I can think of that I'd describe as a map.

      Delete
  7. I'm currently using RPG Maker VX, and working with code is always a big hurdle for me. I'm using menu scripts that require dabbling into the code to add more lines, quests, etc.. It's a real pain, but I have to do it. xP

    For the most part I use events, and they make it very easy to do most things. When I first started out I would make one event for an enemy, and then just copy/paste it. Problem is, if you have an issue in any of the event commands, then you must manually replace ALL of those events that you copy/pasted. Ouch!

    Later I learned about common events, which you can link to from any normal event. These common events work much better since you'd then only have to edit a single common event, no matter how many of your events call/refer to it. The only reason to replace all the events then would be if you wanted to change the graphic or something, which shouldn't be necessary if you simply replace the graphic that it's using.

    I feel like I'm constantly learning how to do new stuff, and how to better simplify things that, before, were unnecessarily complex. I'd love to move on to a more advanced RPG Maker someday, but the longer I stay with RPG Maker VX the more comfortable I am with it. I'm seriously thinking about doing so after I finish FSA (The Fairy, The Succubus, and The Aybss). It just seems highly illogical to switch before then. At least if it's a new project then I can do something simpler to learn the ropes, and if I just can't get the hang of it then I can always abandon ship. xP

    ReplyDelete
    Replies
    1. Well, from an outside perspective I don't personally see much point in moving from one RPG Maker to another. I'm not sure it would be worth the time lost. Personally, I think it'd probably be better to stick with it and focus on streamlining your process, improving gameplay, artwork, etc.

      To me, RPG Maker and GM are essentially good starting points while being valuable methods of production. But, once you have the programming and development mindset, it's less worth it to invest time into multiple starting points, or in the case of RPG maker, learning new versions. (For example I would never switch from GM to Godot, or from GM to RPG maker)

      Delete
    2. Godot is so not beginner friendly so I don't blame you

      Delete
  8. Do you still have the demo for Crimson Brave? I missed getting to play it when Megaupload got shut down.

    ReplyDelete
    Replies
    1. On a harddrive somewhere, I'll probably dig it up sometime. Once I finish current projects and go back to some of the unfinished games, I may upload examples of the ones I choose not to finish, and have a page for them.

      Delete
    2. Nice! Makes me excited!

      Delete
  9. You will make a 2D hentai game with characters that look big and good?, I mean something like Atelier Tia, night of revenge or any of those, I know how easy and simple is to make small characters, pixelated and not look good, but sometimes the easy and simple is not what Better and there's a lot of that, believe me

    ReplyDelete