Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411430 Posts in 69363 Topics- by 58416 Members - Latest Member: JamesAGreen

April 20, 2024, 01:39:07 AM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)Platforming with states!
Pages: [1]
Print
Author Topic: Platforming with states!  (Read 3511 times)
___
Vice President of Marketing, Romeo Pie Software
Level 10
*


View Profile
« on: July 21, 2009, 09:53:29 PM »

Hello gents  Gentleman

I'm approaching a rather complicated platforming game project in my near future, (dealing with game maker here) and I'm trying to think of the best way to go about this.  I've just learned about the terms single state machine, and overlapping states, and I am intrigued!

It seems since I've been making games, I've just been using a bunch of booleans and timers all independent of each other that affect how my character behaves.  Stuff like "on_ground", "has_jumped", "grappled", "punching", etc.  I guess this is referred to as overlapping states...?

But now I'm starting to explore having a single variable "STATE" control a lot of stuff.  So it would be things like "STATE_NORMAL", "STATE_DASH", "STATE_GRAPPLED", "STATE_SWING", "STATE_CROUCHING", "STATE_STANDING", etc.  Having all the code for each state separate could be really handy, but I'm unsure if it will make things more complicated, and which states I should even be separating from each other.  (Should I just have "STATE_NORMAL" cover basic standing, running, and jumping -- or have "STATE_STAND", "STATE_RUN", "STATE_JUMP"...?)

I've been moving forward with perhaps a mix of a little from both sides, as both methods have advantages and disadvantages... but hopefully if anyone out there has any tips or experiences they'd like to share, it'd give me a clearer picture of what I'm doing.

Okaaaaay GO.   Corny Laugh Hand Any Key
Logged
Xion
Pixelhead
Level 10
******



View Profile WWW
« Reply #1 on: July 21, 2009, 10:56:55 PM »

This interests me as well. Who, Me?
Logged

Martin 2BAM
Level 10
*****


@iam2bam


View Profile WWW
« Reply #2 on: July 22, 2009, 05:00:55 AM »

If things get overcomplicated, don't use it.

Use states to define actions that are mutually exclusive (like Moving left and Moving right).
You can use two directional states to define movement (horizontal direction/vertical direction)
That way you'll have 3 possible states in two variables. (left/right/still, up/down/still)

If you want to define a single direction state, you'll have to define several options (3*3)

still
left
left-up
left-down
right
right-up
...

And that's not productive. Add to those jumping and shooting boolean states. The states will be multiplied by 2, twice (making you define 36 unique states!)


Nevertheless, for AI is a good way to make the entity follow some actions.
You think the action in one part, set the entity state, and then on other part you perform it.
I think it's pretty useful there.

For example, thinking states could be:
Actions: Idle, Move towards target, Dodge, Shoot target, etc.
Targets: PowerUp, Enemy, Dodge position


The state could go like this (pseudocode):
if(action = Idle) {
   if(find enemy) {
      target = found enemy
      target type = enemy
      if(enemy in reach)
         action = shooting
      else
         action = move towards target
   }
   else if(find power up) {
      target = found power up
      target type = power up
      action = move towards target
   }
}
else if(action = shooting)
{
   if(target is dead)
      action = idle
}


Well, you get the picture.



Regards
-Martín
Logged

Working on HeliBrawl
Overkill
Level 3
***


Andrew G. Crowell


View Profile WWW
« Reply #3 on: July 22, 2009, 05:55:24 AM »

Hmm, my platformers so far have used separate boolean "flags" instead of states. But I have wanted to simplify things a bit.

I would opt for a hybrid, kind of.

Directional state definitely needs to be an enum separate from motion state.

I think that vertical movement needs to have its own state variables. And horizontal movement would have separate states. This way your player can be VerticalState.JUMP and HorizontalState.MOVE, with Direction.RIGHT.

Also, if you think about, you probably still wanna have your guy fall rather than float there if he's swinging a sword. So that needs multiple states.

Avoids having horrendous unmaintainable messes by trying to mash every state in to one variable.

Also you'll still need additional flags probably. For instance, if you're in VerticalState.JUMP, you might keep a counter of how much more the player can jump before they reach their max height. If you're in VerticalState.FALL, you might keep a counter of how long they've been falling so you know if you need to introduce a "heavy landing" animation. If you're in HorizontalState.MOVE, you probably want to know if they're obstructed, so you can possibly introduce grappling near walls.

I dunno, this is stuff I *just* thought of, it might be flawed. I think states definitely clean things up, but make sure you stuff it into reasonably separated states, and still have those extra variables to track stuff. Yeah.

I will need to come back to this thread later! I'm sure it'll help a bunch.

Logged

Kadoba
Level 3
***



View Profile
« Reply #4 on: July 22, 2009, 06:46:14 AM »

The only thing I use state machines for is for ai (really helpful) and "conditions". Or what I call mental and physical states. Mental is the ai state like "chase player" or "wander aimlessly". Only npcs have this state. On the other hand all entities have a physical state which deal with stuff like hitstun, attacking, anything that would take control away from the entitiy. In fact, all input is generally ignored if the state is anything but normal.

There are three rules I have for physical states: 1) The entity only has control in the normal physical state 2) hitstun overrides all other states (unless your game doesn't have hitstun) 3) all states eventually return to normal. I usually set a timer that resets the state to normal. This way you dont have to handle transitions going back to the normal state. You just set the timer when you go into a state.

States that have different phases are still one state. For example you wouldn't have a "state_attacking_pt1", "state_attacking_pt2", etc. Instead you would check the state timer to see how much time is left before reverting back to normal. so it would be like

Code:
if (timer[0] > 10)
 //ready attack
else if (timer[0] = 5)
 //attack happens
else if (timer[0] < 5)
 // attack lag

Put the logic for each state inside a different code action. At the top of have the line "if (state!= this_state) exit;"

The problem with having states for every tiny thing, like running, jumping, ect, is that your code is everywhere and it gets really confusing in a hurry. States are suppose to alleviate complexity, not induce it.

Don't bother declaring your states as constants. You're going to find a lot of your entities have uniqe states, especially with mental states (if you go that route) and since you have to declare all constants in the game in one place it gets messy. I just declare the states in the creation event mental states starting at 200 and physical at 100. so something like:

Code:
PST_NORMAL = 100
PST_HITSTUN = 101
PST_ATTACKING = 102

MST_IDLE = 200
MST_CHASE = 201
MST_SHOOT = 203

(For those of you who just cringed Game Maker doesn't have enumerators)

I just use boolean operators for jumping and such. Anyway, this all works for me but I would love to see how other people handle it.
« Last Edit: July 22, 2009, 06:49:40 AM by Kadoba » Logged
Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #5 on: July 22, 2009, 10:36:51 AM »

I use states in platformers, usually reduced to "on ground" "in air" and then any specialist ones specific to the game (like standing in front of the exit playing an animation - a time when the player is invincible and can't move at all so it's handy for it to be seperated into its own state). "on ground" covers running, walking and standing in both directions just based on the velocity value and a direction bool.

Stuff like crouching I would handle with a bool as well. I find it's easier to adjust acceleration and animations when crouching rather than giving it a whole seperate state, since it shares the majority of things with standing/running like wall collision, falling off platforms, triggering crumbly platforms etc.
Logged

Zaknafein
Level 4
****



View Profile WWW
« Reply #6 on: July 22, 2009, 10:45:29 AM »

I know next to nothing about Game Maker, but in Fez I use a state-ish design pattern for the player actions.

I have an ActionType enumeration that defines which state the player is in, it can only have one of these :

Code:
None,                   // Default value (not initialized)
Idle,                   // Not doing crap
Walking,                // Walking slow
Running,                // Walking fast
Jumping,                // Jumping
Suffering,              // Bouncing off a Hurter actor
Falling,                // Falling down (not grounded nor climbing, velocity.y < 0)
Bouncing,               // Bouncing off a Bouncer actor
Flying,                 // Debug mode only, using "jetpack"
Dropping                // Dropping from a top-only-collision trile

There are 41 of these right now and I keep adding to them whenever I need to.

Then I have a series of Action classes that can apply to one or more ActionTypes, and additional conditions about the player like whether he is grounded or not, whether he stands in front of a particular object, etc.

Each Action class has TestConditions(), Begin() and Act() methods.
I have an instance of each Action class in a container, and every update I go through each of them, test the conditions, begin if it started to be active, and act if it's active.

Oh and I have an extension method on ActionType which defines which sprite animation I should be using for each type.

It's been working well for me up to now!
Logged

___
Vice President of Marketing, Romeo Pie Software
Level 10
*


View Profile
« Reply #7 on: July 22, 2009, 05:03:30 PM »

Thanks for the responses so far!  I'm a little... scatter brained at the moment so here is my best shot at replying.

Oh ho, interesting ZAKNAFEIN!... if that is your real name.  Does gravity and friction and all that happen separate from these states, or does each one handle them on it's own?

nitram_cero: I have done something like this for enemy AI before, and it keeps everything clear cut.  thanks for the example.

Overkill: having separate horizontal and vertical states might be a better way to approach it than I was thinking.

Kadoba: That sounds like a good method.  Right now I have two motions that are pretty separate from each other, regular platforming with gravity and such, and swinging on a grappling hook (the rules sort of change when rotating around a point.  no gravity, input affects the object differently, etc), so these work quite well as separate states entirely.

I also define states in the create events as integers, I didn't even think about using constants... those are always a pain to edit anyway.  Using a timer is also something I do a lot.  I don't know about making each state a separate code action entirely... maybe if I get to a point where stuff is looking out of control though it's a possibility.

Ishi: So you just go with overlapping states then?  A lot of booleans?

I started working on my platforming code somewhat.  I combined my player's grappling code with my base actor's platforming code and put the grapple code in state_swing, while the regular platforming is in state_normal.  I tried adding a state_dash for dashing to the left or right (like a Mega Man X style dash) but adding that as a separate state seemed immediately dumb to me after I implemented it because gravity and stuff only applies when the state is state_normal.  So... dashing might be a boolean instead of a state, or ... I'd have to place all the normal code in with the dash state, or switch the state == state_normal into state == state_normal || state == state_dashing.  gah!

I think my problem lately is thinking too much...  Durr...?
Logged
Zaknafein
Level 4
****



View Profile WWW
« Reply #8 on: July 22, 2009, 05:44:56 PM »

I prefer to be called... Renaudbedardrenaudbedard. As per my MIGS pass.

Gravity happens in the "Falling" Action class, i.e. its Act() method is called on every ActionType that doesn't defy gravity (like climing ladders for instance).

Friction is another thing,... After looping through all the Actions, all the player physics and collision are applied based on the modifications they've made on the Velocity vector. So I try to keep it separate.
Logged

andy wolff
Level 10
*****


-------


View Profile
« Reply #9 on: July 22, 2009, 06:05:33 PM »

I used an offshoot of what you've described as single-state machines when I was experimenting with a turn-based strategy sort of game with 2d platforming aspects.
Instead of having one state, I found it was better to have two or three different states in a hierarchy of sorts, using them as an action tree with both branching and converging limbs, as it were.

I, however, would contend that the best way to code anything is the way you're most comfortable with, be it more or less versatile than another way or not.
Logged

Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #10 on: July 23, 2009, 12:28:54 PM »

Ishi: So you just go with overlapping states then?  A lot of booleans?

I started working on my platforming code somewhat.  I combined my player's grappling code with my base actor's platforming code and put the grapple code in state_swing, while the regular platforming is in state_normal.  I tried adding a state_dash for dashing to the left or right (like a Mega Man X style dash) but adding that as a separate state seemed immediately dumb to me after I implemented it because gravity and stuff only applies when the state is state_normal.  So... dashing might be a boolean instead of a state, or ... I'd have to place all the normal code in with the dash state, or switch the state == state_normal into state == state_normal || state == state_dashing.  gah!

I think my problem lately is thinking too much...  Durr...?

Sort of a combination of the two methods. Kind of like you said there with the dash, if it's not that different from the normal state I'll do it as overlapping. It does soon get quite messy though.

I'm liking the sound of Renaud's mega-OOP system. All nicely stuctured, and it's easy to create new states that reuse elements of others like Falling. I should make more effort to think up clean solutions like that rather than just coding-as-I-go all the time.
Logged

___
Vice President of Marketing, Romeo Pie Software
Level 10
*


View Profile
« Reply #11 on: July 23, 2009, 07:25:49 PM »

I'm pretty dumb, Renaud... you have just the falling state that adds gravity?  So are your states .. overlapping?  Like does the falling state also happen with say... "bouncer"?  (I'm interpreting bouncer as an object I'd collide with and be thrown off in some vector, so possibly into the air -- so then gravity would have to act to pull me down)
Logged
Ivan
Owl Country
Level 10
*


alright, let's see what we can see


View Profile
« Reply #12 on: July 23, 2009, 07:29:14 PM »

Gravity should be applied always, no? no matter what state?
Logged

http://polycode.org/ - Free, cross-platform, open-source engine.
Zaknafein
Level 4
****



View Profile WWW
« Reply #13 on: July 23, 2009, 07:51:43 PM »

xerus : States overlap, yeah. Each Action class is run if its conditions are met, more than one can be run, but the current ActionType mostly just defines which sprite animation should be displayed. And it's the main condition upon which Action classes decide to act or not.

Ivan : I suppose that climbing a ladder should just "friction out" gravity, or cancel it out somehow. I just decide not to apply it.

And I wouldn't say that my stuff is a justifiable and proper way of doing things. It's a way, and it's hacky in some areas... but it keeps things nice and separate most of the time.
Which comes back to what Andy said last : do whatever you're most comfortable with.
Logged

___
Vice President of Marketing, Romeo Pie Software
Level 10
*


View Profile
« Reply #14 on: July 23, 2009, 08:13:58 PM »

xerus : States overlap, yeah. Each Action class is run if its conditions are met, more than one can be run, but the current ActionType mostly just defines which sprite animation should be displayed. And it's the main condition upon which Action classes decide to act or not.

Oh okay, gotcha.  Right... earlier you said each one has testconditions, begin, and act.  Hm!  An interesting approach for sure... THANKS  Gentleman
Logged
Ishi
Pixelhead
Level 10
******


coffee&coding


View Profile WWW
« Reply #15 on: August 07, 2011, 02:19:22 AM »

This thread is a couple of years old, but I dug it up because I fancied having another look at it. Thought I'd bump it because it's pretty interesting. I'm about to embark on a bit of character movement today, and I'm gonna class the hell out of it.
Logged

Pages: [1]
Print
Jump to:  

Theme orange-lt created by panic