Player velocity becomes 0 for 1 frame during State Machine transition
Hello!
I am currently making a game with a character that can run sideways and jump (for now), and I've already ran into a peculiar issue that I am not sure how to fix.
I am using a class-based State Machine to handle state transitions, and the player's velocity stutters slightly when changing states. If I debug this, I can clearly see that for 1-2 frames, when the player changes states, the player's X velocity is set to 0.
I suspect this is caused by CurrentState.Exit() and CurrentState = state in the StateMachine script, essentially leaving the player stateless for a frame and thus input is not being read. But even if my assumption is correct, I would have no idea how to handle this without violating the state pattern.
Any help is greatly appreciated, thank you in advance!
Relevant code:
public class StateMachine
{
public State CurrentState { get; private set; }
public void Initialize(State state)
{
CurrentState = state;
state.Enter();
}
public void ChangeState(State state)
{
CurrentState.Exit();
CurrentState = state;
state.Enter();
}
}
public abstract class State
{
protected Player Player;
protected StateMachine SM;
protected State(Player player, StateMachine sm)
{
Player = player;
SM = sm;
}
public virtual void Enter()
{
//Debug.Log($"Entering state: {this}");
}
public virtual void HandleInput()
{
}
public virtual void LogicUpdate()
{
}
public virtual void PhysicsUpdate()
{
}
public virtual void LateUpdate()
{
}
public virtual void Exit()
{
}
}
public class PlayerState : State
{
public float HorizontalInput;
public PlayerState(Player player, StateMachine stateMachine) : base(player, stateMachine)
{
}
public override void HandleInput()
{
base.HandleInput();
HorizontalInput = Input.GetAxisRaw(Constants.Axes.Horizontal);
}
public override void PhysicsUpdate()
{
base.PhysicsUpdate();
Player.rb.velocity = new Vector2(HorizontalInput * Player.RunSpeed, Player.rb.velocity.y);
}
}
public class AirState : PlayerState
{
public bool JumpButtonHeld;
public float JumpQueueDuration;
public AirState(Player player, StateMachine stateMachine) : base(player, stateMachine)
{
}
public override void Enter()
{
base.Enter();
Player.Grounded = false;
JumpQueueDuration = 0f;
}
public override void LogicUpdate()
{
base.LogicUpdate();
JumpButtonHeld = Input.GetButton(Constants.Buttons.Jump);
if (JumpButtonHeld)
JumpQueueDuration += Time.deltaTime;
else
JumpQueueDuration = 0f;
bool queue = (JumpQueueDuration > 0f) && (JumpQueueDuration <= Constants.Game.ActionQueueDuration);
if (Player.Grounded)
{
if (queue)
SM.ChangeState(Player.Jumping);
else
SM.ChangeState(Player.Standing);
}
}
public override void LateUpdate()
{
base.LateUpdate();
if (Player.rb.velocity.y < -Player.MaxFallSpeed)
Player.rb.velocity = new Vector2(Player.rb.velocity.x, -Player.MaxFallSpeed);
}
}
public class JumpingState : AirState
{
public bool Ascending;
public float JumpStart;
public float JumpHeight;
public JumpingState(Player player, StateMachine stateMachine) : base(player, stateMachine)
{
}
public override void Enter()
{
base.Enter();
Ascending = true;
JumpStart = Player.transform.position.y;
JumpHeight = 0f;
}
public override void Exit()
{
base.Exit();
}
public override void HandleInput()
{
base.HandleInput();
}
public override void LogicUpdate()
{
base.LogicUpdate();
JumpHeight = Player.transform.position.y - JumpStart;
if (Ascending && !JumpButtonHeld)
EndJumpEarly();
if (!Ascending && Player.rb.velocity.y < 0f)
SM.ChangeState(Player.Falling);
}
public override void PhysicsUpdate()
{
base.PhysicsUpdate();
if (Ascending)
{
Ascend();
}
}
public override void LateUpdate()
{
base.LateUpdate();
}
void Ascend()
{
if (JumpHeight <= Player.MaxJumpHeight)
Player.rb.velocity = new Vector2(Player.rb.velocity.x, Player.JumpSpeed);
else
Ascending = false;
}
private void EndJumpEarly()
{
if (Player.rb.velocity.y > 0f && JumpHeight >= Player.MinJumpHeight)
{
Player.rb.velocity = new Vector2(Player.rb.velocity.x, 0f);
Ascending = false;
}
}
}
Your answer
Follow this Question
Related Questions
Twiching Velocity using RigidBody.addForce. 0 Answers
My game is slower after changing my computer 0 Answers
Getting player's local direction 0 Answers
In my StateMachineBehaviours public variables do not update in the inspector 0 Answers
How can I 'instantly' reset my state machine back to its first state to replay my animation? 0 Answers