Sign in to follow this  
Robster

Unity State machine for beginner - how to shoot state AND jump state

Recommended Posts

Hi all,

My first post. I am not very skilled yet in programming though have a good idea of the ideas behind how a lot of it works. I've done codecademy courses on Javascript, GIT and am working through their Python course now. I am using Godot as my preferred engine, due to this I've put Python as the topic prefix as it's the closest I could find.

The above is to give an idea of where I'm at.

I've in time found that If Then Else is a bad idea for controlling a character due to the complexity that comes from such a structure and the code turns spaghetti. So I've been researching and have come to state machines. I love the idea of them, but I can't get my head around this issue below. (remember I'm a newb)

 

[attachment=33096:FSM-export01.png]

If you look at the image attached I have various states and I think I know how to move between them in theory. My issue though is the shooting state. You see I can shoot and idle, shoot and jump, shoot and fly, shoot and run. As it's a state machine and I can only have one state at a time, does that mean I need 4 new states for those combinations? It's a shame if so due to the duplication of so much code. So I thought I'd check here first and see what the community thinks.

Thanks so much and I'm glad to have found this place.

Rob

Edited by Robster

Share this post


Link to post
Share on other sites
Generally you only want to use a state machine when it contains mutually exclusive states. If you ever have two or more things that you can combine at the same time (like shooting and any movement state), either split them in two different state machines, or use something else instead of a state machine.

Sometimes you don't need a state machine at all and can do everything in a single Update function that gets called once a frame.

such as:
 
If health is <= 0 and dying animation not playing, play it and return.
If dying animation is done, do game over and return.

Check arrow keys, update velocity.
Check whether the player is touching the ground, if so reset the jumping flag.
If jumping flag is false and jump key is pressed, set jump flag and add lots of upward velocity.
If jumping flag is set and jump key is released quickly, subtract a bit of upward velocity to let the player perform a smaller jump.  Potentially add another flag to prevent the user from repeating this multiple times in the same jump.
If player is capable of flight, holding the jump key while jumping adds a little bit of upward velocity.

If fire key is down, and firing is possible now, then fire.

Apply velocity to position.

If in air, use jumping/flying animation.
Else If on ground and speed > large threshold, use running animation.
Else If on ground and speed > small threshold, use walking animation.
Else if on ground use idle animation.
Edited by Nypyren

Share this post


Link to post
Share on other sites

For typical player operations, state machine's are really the right tool.  Being an early game you're making, you should really be doing something simple.  For example, assume you're characters have apdate() method called once a frame, for your player character, you'd do something like this:

void Player::Update()
{
  if (Input.KeyPressed(LEFT_KEY)) {
    Velocity.X = -5; // move left
  }
  else if (Input.KeyPressed(RIGHT_KEY)) {
    Velocity.X = 5; // move right
  }
 
  if (IsOnGround) {
    if (Input.KeyPressed(JUMP_KEY)) {
    Velocity.Y = -30; // set player velocity negative to jump, we'll slow down each frame
    IsOnGround = false;
  }
  else {
    // we're in the air, decrease Y velocity each frame to simulate gravity
    Velocity.Y += 2;
  }
 
  if (Weapon.RefireTimer < GetCurrentTime() && Input.KeyPressed(FIRE_KEY)) {
    // shoot a bullet and set refire timer to however long the current weapon's refire time is
    Weapon.RefireTimer = GetCurrentTime() + Weapon.RefirePeriod;
    AddBullet(Weapon.GetBullet());
  }
  // store old location, and move player in each axis
  // If we're colliding with something, set the velocity to 0 in that direction and reset player's position in that axis
  Vector2d OldPosition = Position;
  Position.X += Velocity.X;
  if (CheckCollision(Position)) {
    Position.X = OldPosition.X;
   Velocity.X = 0;
  }
  Position.Y += Velocity.Y;
  if (CheckCollision(Position)) {
    // if we hit the ground, set onGround
    IsOnGround = CheckHitGround(Position);
    Position.Y = OldPosition.Y;
    Velocity.Y = 0;
  }

Share this post


Link to post
Share on other sites

I love the idea of them, but I can't get my head around this issue below.

 
 
State machines are standard everywhere in games. Learn to love them.

I put together this article where I used state machines in several different ways in some simple little prototypes.
 

You see I can shoot and idle, shoot and jump, shoot and fly, shoot and run

 
 
As Nypyren points out, usually they are best when used as discrete things. That is, you are in A, then B, then C.  You can also do work in the transition between A and B, do work in the transition between B and C.
 
That doesn't mean you can't make it work.  Depending on the animation system you are using, you might be able to control the shooting arm separately from the rest of the body. You'll have one set of body actions that control most things, and another set of arm actions for your shooting.

 

Some systems will allow more complex animation blending to make it work.  Others will use inverse kinematics (IK) which is a fancy way to say you tell the system where the hand goes and where the shoulder goes and it uses physics to figure out how all the joints fit together. These take a bit of work to put together and thankfully most professional-grade engines have them implemented already.

Share this post


Link to post
Share on other sites

 

For typical player operations, state machine's are really the right tool.  Being an early game you're making, you should really be doing something simple.  For example, assume you're characters have apdate() method called once a frame, for your player character, you'd do something like this:

void Player::Update()
{
  if (Input.KeyPressed(LEFT_KEY)) {
    Velocity.X = -5; // move left
  }
  else if (Input.KeyPressed(RIGHT_KEY)) {
    Velocity.X = 5; // move right
  }
 
  if (IsOnGround) {
    if (Input.KeyPressed(JUMP_KEY)) {
    Velocity.Y = -30; // set player velocity negative to jump, we'll slow down each frame
    IsOnGround = false;
  }
  else {
    // we're in the air, decrease Y velocity each frame to simulate gravity
    Velocity.Y += 2;
  }
 
  if (Weapon.RefireTimer < GetCurrentTime() && Input.KeyPressed(FIRE_KEY)) {
    // shoot a bullet and set refire timer to however long the current weapon's refire time is
    Weapon.RefireTimer = GetCurrentTime() + Weapon.RefirePeriod;
    AddBullet(Weapon.GetBullet());
  }
  // store old location, and move player in each axis
  // If we're colliding with something, set the velocity to 0 in that direction and reset player's position in that axis
  Vector2d OldPosition = Position;
  Position.X += Velocity.X;
  if (CheckCollision(Position)) {
    Position.X = OldPosition.X;
   Velocity.X = 0;
  }
  Position.Y += Velocity.Y;
  if (CheckCollision(Position)) {
    // if we hit the ground, set onGround
    IsOnGround = CheckHitGround(Position);
    Position.Y = OldPosition.Y;
    Velocity.Y = 0;
  }

Thank you for the large effort above.  What I found though, having already tried a bunch of if / else type of logic that in time it gets very hard to keep track of and a bit sphagetti, hence my looking into state machines.  I'll definitely have a look over your code though and see what I can learn from it.   I've decided to hold off a week or more whilst I do some more Python lessons to make better use of the available then come back to this thread.  Thanks again.


 

I love the idea of them, but I can't get my head around this issue below.

 
 
State machines are standard everywhere in games. Learn to love them.

I put together this article where I used state machines in several different ways in some simple little prototypes.
 

You see I can shoot and idle, shoot and jump, shoot and fly, shoot and run

 
 
As Nypyren points out, usually they are best when used as discrete things. That is, you are in A, then B, then C.  You can also do work in the transition between A and B, do work in the transition between B and C.
 
That doesn't mean you can't make it work.  Depending on the animation system you are using, you might be able to control the shooting arm separately from the rest of the body. You'll have one set of body actions that control most things, and another set of arm actions for your shooting.

 

Some systems will allow more complex animation blending to make it work.  Others will use inverse kinematics (IK) which is a fancy way to say you tell the system where the hand goes and where the shoulder goes and it uses physics to figure out how all the joints fit together. These take a bit of work to put together and thankfully most professional-grade engines have them implemented already.

 

Thank you for the well written answer.  I used to be a full time animator so am quite aware of IK etc.  It's made me think that maybe I need to look at a modular approach to the character if that's what you're referring to?  I'll do some research in Godot and see if I can force an animation of one body part over the rest.  Still, what I also told the other commentor, I'm going to wait a week or more until I learn more Python.  I just want to get some more fundamentals down so I have the tools to tackle this.  I think I understand it from a conceptual perspective. I just need some actual tool knowlege (the language).  Once I have more of that I'll come back to this thread.  I just wanted to say thank you for now until I come back here.  I realised I was jumping the gun a little.  Thanks again

Share this post


Link to post
Share on other sites

If you look at the image attached I have various states and I think I know how to move between them in theory. My issue though is the shooting state. You see I can shoot and idle, shoot and jump, shoot and fly, shoot and run. As it's a state machine and I can only have one state at a time, does that mean I need 4 new states for those combinations? It's a shame if so due to the duplication of so much code. So I thought I'd check here first and see what the community thinks.

 

 

Shoot and Idle, Shoot and jump, could be two separate states, or it could be three possible states with two OR-ed together.  This obviously really depend on the game you are making and the kind of logic you are aiming for.  Most of the time, if you are looking at a 2D game (I'm assuming so since you mentioned Godot), it's safer to keep them separate.

 

I also prefer to present my states in a table rather diagrams.  List your states on the Y axis, and the conditions on the X axis, then the values is what happens when condition is met.  For example:

+-----------------+------------------+-------------------+
| State\Condition | BTN_FIRE_PRESSED | BTN_FIRE_RELEASED |
+-----------------+------------------+-------------------+
| STATE_IDLE      | STATE_IDLE_FIRE  |  -                |
| STATE_IDLE_FIRE | -                | STATE_IDLE        |
| STATE_JUMP      | STATE_JUMP_FIRE  | -                 |
| STATE_JUMP_FIRE | -                | STATE_JUMP        |
+-----------------+------------------+-------------------+

Column are the conditions, and each row represent that state you are in, and what state is next if the condition is met.  You can organize this into a two-dimensional array (or one-dimensional if you are old-school), then switching from one state to another is a matter of assigning your current state to the value in the table.

nextState = STATE_TABLE[currentState][condition]
if (nextState != null) {
   currentState = nextState
}
Edited by alnite

Share this post


Link to post
Share on other sites

Your state machine chart looks good. All the states are mutually exclusive, but shooting is something that can be done in all of them except death. Therefore, call your shooting code in addition to updating the state machine. Perhaps with a check to make sure you're not dead (which I would call a special case). Or if you end up needing multiple states where you can't shoot, then instead of special casing each one, you could add a bool canShoot to your data table of stuff related to each state (or create a table if you don't have one already).

 

Choosing which animation to display can also be done by a table lookup, where you have two animations for each state (one shooting and one not).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Partner Spotlight

  • Forum Statistics

    • Total Topics
      627653
    • Total Posts
      2978440
  • Similar Content

    • By STRATUM the Game
      Hey, everyone! This is my first post here.
      I would like to know what you think about my project called STRATUM. It's a 2D platformer that is heavily based on storytelling and boss fighting while trekking through the world.

      Everything in STRATUM takes place in the first century AD, in a world that wraps our own universe, called  The Stratum. A parallel Universe that is the home of the Christian deities . In this game you will play as a Dacian warrior, unfamiliar with everything in this world, you’ll get to know and understand The Stratum together with him.
      The main thing that I want with STRATUM is to reinvent the known lore and history of the Christian deities and realms. 
      The story is unconventional, it plays down a lot of the mysticism of Hell or Heaven and it gives it a more rational view while keeping the fantastic in it. What do I mean by that? Well, think about Hell. What do you know about it? It's a bad place where bad people go, right? Well, that's not the case in STRATUM. I don't want to describe such a world. In STRATUM, there is a reason for everything, especially for the way Hell is what it is in the game. "Hell" is called The Black Stratum in the game.
      This world is not very different from Earth, but it is governed by different natural laws.
      The story will also involve the reason why this world entered in touch with ours.

       
      What do you think about all that I said? Would you be interested in such a game? I have to say that everything is just a work of fiction made with my imagination. I do not want to offend anyone's beliefs.
      I want this to be a one man game. I have been working alone on it (this was my decision from the beginning) from art to effects to programming to music to sound effects to everything.
      I also have a youtube video HERE if you want to see the way the game moves and the way my music sounds.
      Please, any kind of feedback will be highly appreciated. If you have something bad to say, do it, don't keep it for yourself only. I want to hear anything that you don't like about my project.
       
    • By LimeJuice
      Hi, it's my first post on this forum and I would like to share the game I am working on at the moment.
      Graphics have been made with Blender3D using Cycle as a renderer and I am using Unity3D. It's a 2D game, one touch side-scrolling game for iOS and Android.
      Here some pictures, and you can have a look to the gameplay on this video :
      Feedbacks ?
      And if you want to try it, send me your email and I will add you to the beta tester list!
       
       








    • By Kirill Kot
      An adventure indie game with quests in a beautiful, bright world. Characters with unique traits, goals, and benefits. Active gameplay will appeal to players found of interactivity, especially lovers of quests and investigations.
      Available on:
      Gameroom (just open the web page and relax)
      AppStore
      GooglePlay
      WindowsPhone

    • By Kirill Kot
      Big Quest: Bequest. An adventure indie game with quests in a beautiful, bright world. Characters with unique traits, goals, and benefits.
      Mobile game, now available on Gameroom. Just open the web page and relax.
    • By Kirill Kot
      Big Quest: Bequest. An adventure indie game with quests in a beautiful, bright world. Characters with unique traits, goals, and benefits.
      Mobile game, now available on Gameroom. Just open the web page and relax.
  • Popular Now