Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Programming Talk / C++ / C# - Question about AI Design (HFSM's)

Author
Message
JTK
14
Years of Service
User Offline
Joined: 10th Feb 2010
Location:
Posted: 7th Jun 2010 05:29 Edited at: 7th Jun 2010 05:36
I'm not sure if it belongs here or somewhere else so MODS, feel free to move it you think it's inapropriate here)...:

In my game, my player character has a set of 9-possible "animation states" consisting of Normal, Shield, Boot, Glove, Shoes, Spring, Kite, Ball and Rope. Furthermore, he also has a set of 4 "internal states" consisting of Normal, Jumping, Flying and Falling.

Now, having done some preliminary designing, I've decided the following "interactions" were possible (CODE snippet used for brevity):



Now I've been researching all weekend for ways to:

1) Document this set of interactions - specifying the various relationships between "internal state" and "animation state" beyond the textual descriptions I provide above...

This research has led me to believe that Z-Notation would be the most succint in defining the relationships; however, from what I can gather Z-Notation is not very standard and is thus a more-specialized form of notation. Perhaps a series of tables (1 for each "internal state") would be more graphically appealing and intuitive to understand by an outside reader of my design/technical documentation? I've considered "state diagrams" as well, however, they are (in my opinion) a "fluster cuck" of jibberish and icons to understand - perhaps, that's just my lack of understanding on the subject...

2) Implementing these proverbial "rules" in code in an as "straight forward" means as possible without turning my code into speghetti by nesting switch() inside of switch() for each set of relationships.

Again, my research leads me to use the proverbial "state" class here (and further suggests a "state machine" class; however, I'm not quite understanding how to relate "internal state" with "animation state" using this approach... Perhaps some guidance from some of you may assist me in this particular matter?

At present, my current thoughts on implementation are to take 3-values:

1) current "internal state",
2) current "animation state",
3) proposed "animation state"

and combining them into an int value (32-bits) using a formula such as:

test_value = (((internal_state << 16) | (curr_anim_state << 8)) | prop_anim_state);

switch(test_value)...

In this way, I can define my case values such that all "internal state" values are *grouped* together. Of course, this means that in a worst case scenario, I could have up to 16+ million possible case values to test (ie: speghetti code) if I were to ultimately define another 252 "internal states" with another 247 "animation states" (overkill I know, but I want extensibility/flexibility without complications)...

Right now, however, I am left with 4*9*9=324 possible case values to test; of which, 90% or so can be left to the *default* action of "do nothing"... But is this the way to go?

So, my real question is; How would you attack this scenario in your own projects? Please be as specific as possible (technically speaking) so that I may understand *what* you are doing, and more importanly, Why!

I'm not asking for code (per se) except as illustration. What I need, is to understand the choices that you would make in this situation and why those decisions make sense...

Unfortunately, this is now the hold-up of my current project. And it disappoints me to think this is the "player" character and not the AI entities... What throws me is the dual-level of hiearchy in the state-machine (hence the HFSM in the thread's title)...

How would you approach this in your own projects?

Your Responses and Advice would be greatly appreciated,

JTK
Slayer
20
Years of Service
User Offline
Joined: 15th Nov 2003
Location: CA
Posted: 8th Jun 2010 10:23 Edited at: 8th Jun 2010 10:23
the way I always wanted to control a player was to load all animations and load one of the players with no animation data and just use the limb values of the animations you want and set them to the limb rotation values of the non animated player with a curvangle, so they can morph in a cool way to the animation that you want the player to perform. I have many other ways but I had done all this lang ago when dbpro first came out and the limbs were hella buggy! Limbs would take off all out of wack ..ect. Theres other ways to use if you are going to animate the player yourself or also if the objects you are using have set animations that are pro with smooth morphing already given for use. Also you must type well because you can type a hella lot of info. I seen one of your codes and man allot of stuff for a simple dam demo lol thats cool.

I some time ago did a good animation morphing of a object and it used like only 100 lines of code but it used 8 objects of the player
in different animations that all went with each other for the smooth morphing. Try to find ways to use only one function to control all animations, one function to control a switch animation and another to control the animation you want. Try simple ways to control big things. Simple Values added in a function will play animations that you want with one function. I like to code things in a way to were I get big things and try my dam best to make it more simple. When you do that sometimes you invent new and better ways to control your objects, images, AI ..ect. Im getting back into programing and learning C++ and Dark basic pro helped me out allot. Simple makes things better.

Hope some of this helps - Crazy Coder. Lol J/K

I dont know how to spell
Matty H
15
Years of Service
User Offline
Joined: 7th Oct 2008
Location: England
Posted: 8th Jun 2010 19:21 Edited at: 8th Jun 2010 19:26
Hi JTK, I have not had alot of time lately and your question is a biggy. I don't really understand what kite, ball, rope etc represent, I know you say they are animation states but I fail to visualise what you mean.

Anyway, from a quick read over, would some kind of table aid you in any way, in code as arrays or just as a diagram to help see the problem, something like this.



This would give you some sort of access to information on what states are available given the state its currently in.
Sorry if I totally misunderstand the problem

JTK
14
Years of Service
User Offline
Joined: 10th Feb 2010
Location:
Posted: 10th Jun 2010 15:41
Thanks for the responses you two.

@slayer: I know I'm over complicating things in this scenario however I'm doing it more as an exercise. By trying to get a grasp of the concepts (and implementations) now with a relatively simple set of states and sub-states, I'll have a firm grasp of understanding in future endeavors when the state system is more complicated.

@matty: you're not completely off the mark but your table is missing some of the facts I'm wanting to illustrate where sometimes it makes no sense to allow certain changes in animation state. For example, it makes no sense to allow the player to turn into shoes when jumping or falling.

Think of animation states as being the visual representation of the characters special powers. shield for blocking, boot for kicking, glove for punching etc.

I hope this helps explain things a little better...

JTK
Slayer
20
Years of Service
User Offline
Joined: 15th Nov 2003
Location: CA
Posted: 11th Jun 2010 14:16
Are you saying put things there even though they dont need to be there but just in case do, so later in time you just might need whats there.
basically a AI engine with full control.

Also yah thats the way I like to learn. I like to learn things that I might use in the future. So I can know I did my best to get done what needed to be done.

I dont know how to spell
JTK
14
Years of Service
User Offline
Joined: 10th Feb 2010
Location:
Posted: 11th Jun 2010 17:10
Quote: "I like to learn things that I might use in the future."


That's more like what I'm after. Trying to figure out the process of creating an AI. Since each game is different, the specifics will differ, but the process will (hopefully) be the same.

JTK
BearCDP
14
Years of Service
User Offline
Joined: 7th Sep 2009
Location: NYC
Posted: 8th Jul 2010 09:58 Edited at: 8th Jul 2010 10:10
Are you trying to combine these two aspects into one state machine? That seems like it would cause a serious headache


From what it sounds like, your animation state is dependent on the internal state, but the internal state is not dependent on the animation state. Is this correct?

I hope so, because that's how my answer tackles it

First, get your internal state machine working flawlessly (luckily, not too difficult considering it has less states to think about). Now, since your internal state is independent of any other state, you can leave it be. It has no need to worry about the animation state. For all it cares the animation state could be a BSOD and the internal state will keep on chugging.

Now, for the animation state, give it a reference to (or some other means of identifying) the current internal state. Now, just base your state transition conditions for the animation states take into account the internal state.

Here's a sample table:



If you're using a standard FSM pattern like the one in Mat Buckland's book, Programming Game AI By Example (EDIT: link, then that state's Update/Execute method is where you can check for the internal state.

I wasn't clear on how you were handling this in your description, but if the internal state will change as a result of the player wanting to change to a specific animation state, then the animation state can request that the internal state change to a compatible state



Example

Given:
InternalFSM.CurrentState = NormalInternState
AnimationFSM.CurrentState = NormalAnimState
Player presses "Kite" button

1. Input/Update loop calls AnimationFSM.Change(KiteState)

2. NormalAnimState calls InternalFSM.Change(JumpState)

3a. If InternalFSM reports unsuccessful state change (via return value, callbacks, messaging, whatever), then do nothing (still in NormalInternState and NormalAnimState). AnimationFSM reports unsuccessful state change to the Input/Update loop.

3b. If InternalFSM reports successful state change, NormalAnimState calls on its own AnimationFSM.Change(KiteState).

4. It's safe to assume AnimationFSM will report a successful state change. However, you could have other conditional blocks following the one that looks for a valid InternalFSM state (NOT ENOUGH MANA!!).



This does have the potential to turn into spaghetti code if you have a ton of states to worry about with complex interactions. And if that becomes the case, you might want to think about breaking the problem down further. Also, this problem doesn't exist if your AnimationStates aren't directly controlled by the player, or if your gameplay requires two separate actions to differentiate between a kite and a jump (ie: Space to jump, then K to use kite while in umping or Falling).

In the least complicated scenario, AnimationFSM only uses the InternalFSM reference to check for a valid state transition. Any action that required changing the Internal state in order to reach a specific Animation state would be handled by a third object or system.


Also, you might want to see if there's a way to consolidate your Jumping and Falling states. I had a player state machine that I recently trashed because I had coupled the animation and jumping states too tightly. I ended up with:

OnGround
JustJumped
JustFell
InTheAir
>>IsJumping
>>IsFalling
JustLanded
>>FromFall
>>FromJump

When I only had 3 different animations to worry about (idle, walking, and jump). Because the state machine was trying to handle both jumping and falling as separate states on top of mixing in the animations it turned into this unmaintainable mini-monster. It wasn't long before I realized that all I really needed for basic functionality was 3 states: walking, idling, in the air. I then used a separate FSM that checked the player state and listened for input and set the animation accordingly. I was even able to show "falling off platform" (just showed the last frame of the jump animation) by differentating between a JumpInputEvent followed by an InTheAirState versus just an InTheAirState. Your design is already nicely partitioned, but any simplification you can do while still achieving the same effect will make your brain hurt that much less.



A lot of this post was really abstract, and I apologize for that. There's a lot of really awesome features in C# that will abstract and simplify a lot of this for you once your lay some groundwork.

Check out this WIP flash game from the Global Game Jam!

Login to post a reply

Server time is: 2024-05-02 05:18:53
Your offset time is: 2024-05-02 05:18:53