DirectX player States help

Hi, I am in the middle of working on a game right now utilizing the DirectX9 library. I am working on my player first and was doing good with the button presses until I switch over to using an enum called player_state to track all my players actions and enum DIRECTIONS to track if player is facing RIGHT or LEFT. Values in the enum player_state were STANDING = 0, STANDING_FIRE = 1, RUNNING = 2, RUNNING_FIRE = 3, JUMPING, JUMPING_FIRE, FALLING, and FALLING_FIRE (etc with their = values)

So originally I was using a couple of bools to track the states like bool player_jumping, player_falling.
I wrote my player jumping like
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (button pressed to jump)
   {
     if (player_jumping == false) //no double jumping
         player_jumping == true
         player y velocity is set in here to ensure they have force to jump
    
     if (player_jumping == true)
         player y velocity -= GRAVITY 
         player y += y velocity

     if (player hits ground)
         player_jumping = false
         player_falling = false
    }//end player jump when button is pressed

if (the jump button is not pressed but player_jumping == true)
    {
    player_falling = true

    continue with the vely -= GRAVITY and player y += vely

    if player hits ground both jumping and falling = false

    }//end falling  


but when I went to using player states and tried to do
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (button pressed to jump)
   {
     if (player_state != JUMPING) //no double jumping
         player_state = JUMPING
         player y velocity is set in here to ensure they have force to jump
    
     if (player_state == JUMPING)
         player y velocity -= GRAVITY 
         player y += y velocity

     if (player hits ground)
         player_state = STANDING
    }//end player jump when button is pressed

if (the jump button is not pressed and (player_state == JUMPING || player_state == FALLING)) 
//jumping and falling because state will be changed to falling inside this "function"
    {
    player_state = FALLING

    continue with the vely -= GRAVITY and player y += vely

    if player hits player_state = STANDING

    }//end falling  


but some problems that occured with using the enum STATES was that while jumping, if I pressed right or left, the player would move all the way to the top of the screen and stay there until I was only pressing the jump button. If I was only pressing the jump button, the player would jump like he was supposed to , but if I released the jump key, the player would not continue his fall back down like supposed to. So the jump was only working if I continuously held the button.
I did go back through and check to make sure that nothing like y values or vely were associated with the right or left key presses. Nothing.

So my problem is that I cannot get the player to jump and fall correctly using the player_state JUMPING and FALLING. After I get these to work correctly, I think it will be easy to add firing while jumping and falling.

and when I was drawing it would look something like

if (player_state == JUMPING)
if (player_direction == RIGHT)
draw right
else if (player_direction == LEFT)
draw left

same thing for all the states because they can only be in one state at a time.

Thanks for all your help in advance!!
Last edited on
Please switch your post category to "Windows Programming" from now on if you want to ask about DirectX Programming.

And, if you need help, send me a PM, I'll give you more details (Maybe I can help)

Hope this helps.
but some problems that occured with using the enum STATES was that while jumping, if I pressed right or left, the player would move all the way to the top of the screen and stay there until I was only pressing the jump button. If I was only pressing the jump button, the player would jump like he was supposed to , but if I released the jump key, the player would not continue his fall back down like supposed to. So the jump was only working if I continuously held the button.

This shows that your jumping -> falling and falling -> jumping transitions get an unintentional "corruption" in your enum implementation, if they pass through the if(directional_button_pressed) part of your program.

The exact structure of 'if' conditions you'll have depends on your desired player behavior (and can vary), although for side-viewed 2D (I understand this is for side-viewed 2D(?), like a 2D platform ) generally speaking you'll want to determine whether the character is currently standing or jumping while the 'jump' key is pressed, thus determining vertical velocity (and subtract gravity), and then check your horizontal direction (left or right) and -- if no directional button is pressed -- simply determine what animation sequence to draw (left or right facing) without added horizontal velocity or, if a directional button is pressed, then add a horizontal velocity and (if need be) update your drawn animation's direction.

So your vertical state determination could be done first, and your horizontal velocity and drawn animation could be subsequently determined by whether any directional key is currently pressed.

Your description for determining jump/stand seems appropriate, (you should also include a clause for drawing a direction when both directional buttons are pressed at once).


if I pressed right or left, the player would move all the way to the top of the screen and stay there until I was only pressing the jump button


So it seems like somewhere in your if(directional_button_pressed) part of your program, you're setting a value to the player_state enum (thus preventing it from following it's intended behavior as described in your original post), otherwise you wouldn't be getting this behavior. Make sure that the vertical position is calculated first (by subtracting gravity from y_velocity etc) and that the if(directional_button_pressed) part only changes player_direction and adds the potential horizontal velocity if pressed while jumping -- but does not affect player_state.

(Again generally-speaking) player_state for jumping/falling/standing should be affected only by y_velocity reaching 0 due to gravity subtractions, or collisions with the environment causing the player to fall off a ledge (or something similar) -- and of course by pressing "jump" while standing. For general purpose movement directional-facing shouldn't set any value to player_state as far as the jump/fall/stand cycle of transitions are concerned.

Clarificational edit: (A left/right directional button-press would, for example, change player_state into "walking" if ((standing)&&(!jumping)) etc., but it shouldn't affect the vertical transitioning of the jump/fall/stand states).

Last edited on
Alright, I think I see what you are saying. I was able to go through and turn most of my stuff to using the two enums, player_state and player_direction. I don't have a problem between the states now, I didn't need a falling state, instead I just kept using the JUMPING state because the animations is the same.

And to fix the problem where he kept rising to the top of the screen if I pressed left or right arrow keys, I did what you said by determining first if he was jumping or not. And inside of the Jumping function I put an inner condition to check if pressing left or right and incrementing the x position that way. So something like

1
2
if (player_state != JUMPING)
   go ahead and do all my non jumping actions like moving left right shoot


then outside of that I had my checks to see if the jump button was pressed and if the player was still falling. So the actions I can perform right now without problems are standing, running, running and firing, jumping/falling.

But now that I want to add jumping and firing, I don't know how to transition out of the Jumping state into something like Jumping_FIRE and then back into jumping. I think that was the problem I was having with Falling, because I would say
1
2
if (player is jumping and no button pressed)
   change player state to falling


Which immediately stops the falling action because now player is not jumping and no button is being pressed.

So now that I want to say

While the player is jumping and he wants to fire

I can't use state JUMPING_FIRE and move back to JUMPING.

I need the player_state to change because that is how I determine what image to draw.
JUMPING_FIRE is a state that should be entered and exited while within the state of JUMPING. You can't fire-while-jumping if you're not already jumping. So you should be looking to put all your code that sets JUMPING_FIRE inside the part of the program where you have already determined that your character is already in a jumping state for the current loop.

So, if (player_state!=JUMPING) determines events where you are either on the ground and stay on the ground, or events where you are on the ground but enter the jumping state for the first time (since you last where on the ground).

On the other hand, the else if (player_state==JUMPING) part determines events where keys are pressed while the character is already in mid-air -- already in a jumping state.

So you want something similar to this for JUMPING_FIRE:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
if(character_state!=JUMPING)
{

        //ground-related keyboard events handled and animations set

}

else if(character_state==JUMPING) //mid-air-related keyboard events handled and animations set
{
        if(fire_button_pressed)
        {
                // set character_state to JUMPING_FIRE, use appropriate animation etc
        }
}

else if(character_state==JUMPING_FIRE) //if the loop finds the chartacter in mid-air _and_ firing
{
        if(!fire_button_pressed)
        {
                //fire button is released, return to JUMPING state
        }
}


JUMPING_FIRE would have to be exited while still in mid-air. Either by releasing the fire key (potentially forcing one full loop of the firing animation to play through before exiting the state, and then returning to the JUMPING state) or by the character colliding with the ground or some other environment element -- which forces the jumping to cease and subsequently forces the character_state::JUMPING_FIRE to cease (since it is a state you can only have while in mid-air, as a "sub-state" of jumping). So at this point you could force a STANDING state and next loop if the fire key is still pressed you'll normally enter a FIRING (while on ground) state because you'll be ((STANDING)&&(fire_key_pressed)).


Last edited on
My opinion is changing the enum definition
Eg

enum STATE
{
STANDING = 0, STANDING_FIRE = 1, MOVING = 2, MOVING_FIRE = 3, JUMPING = 4, JUMPING_FIRE = 5, FAILING = 6, FAILING_FIRE = 7
};

enum DIRECTION
{
LEFT = 0, RIGHT = 1 //more...
};
........................

The similar definition :

enum STATE
{
STANDING = 0, MOVING = 1, JUMPING = 2, FAILING = 3
};

enum DIRECTION
{
LEFT = 0, RIGHT = 1 //more...
};

bool bFire;


I think you should make a specific machine for "Fire"..........
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(bFire == false && ...) //fire button is pressed
bFire = true;

if(bFire)
{
//Update...
switch(player_state) //If you want
{
case STANDING : [...] break;
case MOVING : [...] break;
case JUMPING : [...] break;
case FAILING : [...] break;
}
//Time, and everything...
if(...)//fire button is released or anything else you specified
bFire = false;
}



Anything is switch...(case)....'

1
2
3
4
5
//Handling keys....
if(....) A proper key is pressed
player_state = ...
else
..........................



1
2
3
4
5
6
7
8
9
10
//Update the animation (and player direction)
switch(player_state)
{
case STANDING : [...] break;
case MOVING : [...] break;
case JUMPING : [...] break;
case FAILING : [...] break;
}

//Update particles,.... 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//Rendering (with player direction here)...
if(bFire == false)
switch(player_state)
{
case STANDING : [...] break;
case MOVING : [...] break;
case JUMPING : [...] break;
case FAILING : [...] break;
}
else if (bFire == true)
switch(player_state)
{
case STANDING : [...] break;
case MOVING : [...] break;
case JUMPING : [...] break;
case FAILING : [...] break;
}
//Do more 


Thanks, but I'll review your code again. This is only a code improvement suggestion.
Please view the PM I sent to you. (by mobile)
Last edited on
Thank you all so much for your help on this. I am going to give your ideas and suggestions a try!!! I think Ogoyant's example of switching between jumping and jumping fire might be what I am looking for when I am trying to switch between character states.
I think I am also going to try what Jackson Marie suggested, instead of having all the clutter of a million different states because I want to add _FIRE after each action, just make firing be inside of the primary actions.

Thank you for your time and knowledge, I know these will help me clean up my code a lot and help make this into the game I see in my head.
Glad to hear it helped reptilenut77. Yes, if you intend to have "fire" versions for all your states it would definitely make sense to use a bool instead. Also, like Jackson Marie suggested, a switch would make it less clutter-like, especially when having several states to keep track of.

The main switch should contain all possible states since a game loop can find the character in any of those states (and they have to be handled for the remainder of that game loop). However, as I pointed out before, some states will have others as prerequisites in order to be entered -- so for example if you wanted to include a double-jump type of behavior, you'd have JUMPING as a prerequisite in order to enter the state, and a requirement would be ((JUMPING)&&(jump_button_pressed)&&(hasnt_jumped_twice)). But you'd need a DOUBLE_JUMPING case in your main switch to allow handling of the already-entered state in the succeeding loops, and to allow it's eventual exit. Pretty much like in the JUMPING_FIRE example.

So, keep your desired behavior in mind and map out your code flow, and think of what states are prerequisites for entering others, but allow all of them a case in the main switch to allow eventual exit/branching etc, depending on your desired behavior.

Glad it helped you,

Ogoyant
Last edited on
Topic archived. No new replies allowed.