Hi, I was following the 2.5d rpg course, and after I did the Auto Properties class, i started to get an error that everytime that the character enter the “idle” state it start an infinite loop and i do not know why, i even copied and paste all the classes and is still not working, maybe i pressed something in the framework that broke this?, also I am getting this warning in the debbuging but that is all i am getting:
W 0:00:01:0510 _update_caches: AnimationMixer: ‘Idle’, Value Track: ‘Sprite3D:texture’ uses a non-numeric type as key value with UpdateMode.UPDATE_CONTINUOUS. This will not be blended correctly, so it is forced to UpdateMode.UPDATE_DISCRETE.
<C++ Source> scene/animation/animation_mixer.cpp:879 @ _update_caches()
that could be the problem?
Hey Nicolas,
Can you post your statemachine, along with the classes involved to I can better look at it? As well as your heirchy. Thanks in advanced!
Edit : is entirely related to the animator after looking closer at the error
Hi!! sure,
public partial class StateMachine : Node
{
[Export] private Node currenState;
[Export] private Node[] states;
public override void _Ready()
{
currenState.Notification(GameConstants.NOTIFICATION_ENTER_STATE);
}
public void SwitchState<T>()
{
Node newState = null;
foreach(Node state in states){
if(state is T){
newState = state;
}
}
if(newState == null){return;}
currenState.Notification(GameConstants.NOTIFICATION_ENTER_STATE);
currenState = newState;
currenState.Notification(GameConstants.NOTIFICATION_EXIT_STATE);
}
}
public abstract partial class PlayerState : Node
{
protected Player characterNode;
public override void _Ready()
{
characterNode = GetOwner<Player>();
SetPhysicsProcess(false);
SetProcessInput(false);
}
public override void _Notification(int what)
{
base._Notification(what);
if (what == GameConstants.NOTIFICATION_ENTER_STATE)
{
GD.Print("Enter");
EnterState();
SetPhysicsProcess(true);
SetProcessInput(true);
}
else if (what == GameConstants.NOTIFICATION_EXIT_STATE)
{
GD.Print("Exit");
SetPhysicsProcess(false);
SetProcessInput(false);
}
}
protected virtual void EnterState(){}
}
public partial class PlayerMoveState : PlayerState
{
[Export(PropertyHint.Range, "0,20,0.1")] private float speed = 5;
public override void _PhysicsProcess(double delta)
{
if (characterNode.direction == Vector2.Zero)
{
characterNode.StateMachineNode.SwitchState<PlayerIdleState>();
return;
}
characterNode.Velocity = new(
characterNode.direction.X, 0, characterNode.direction.Y
);
characterNode.Velocity *= speed;
characterNode.MoveAndSlide();
characterNode.Flip();
}
protected override void EnterState()
{
characterNode.AnimPlayerNode.Play(GameConstants.ANIM_MOVE);
}
public override void _Input(InputEvent @event)
{
if (Input.IsActionJustPressed(GameConstants.INPUT_DASH))
{
GD.Print("dash state");
characterNode.StateMachineNode.SwitchState<PlayerDashState>();
}
}
}
public partial class PlayerIdleState : PlayerState
{
public override void _PhysicsProcess(double delta)
{
if (characterNode.direction != Vector2.Zero)
{
characterNode.StateMachineNode.SwitchState<PlayerMoveState>();
}
}
public override void _Input(InputEvent @event)
{
if (Input.IsActionJustPressed(GameConstants.INPUT_DASH))
{
GD.Print("dash state");
characterNode.StateMachineNode.SwitchState<PlayerDashState>();
}
}
protected override void EnterState()
{
base.EnterState();
GD.Print("idle state");
characterNode.AnimPlayerNode.Play(GameConstants.ANIM_IDLE);
}
}
public partial class PlayerDashState : PlayerState
{
[Export] private Timer dashTimerNode;
[Export(PropertyHint.Range, "0,20,0.1")] private float speed = 10;
public override void _Ready()
{
base._Ready();
dashTimerNode.Timeout += HandleDashTimeout;
}
protected override void EnterState()
{
base.EnterState();
GD.Print("dash state");
characterNode.AnimPlayerNode.Play(GameConstants.ANIM_DASH);
characterNode.Velocity = new(
characterNode.direction.X, 0, characterNode.direction.Y
);
if (characterNode.Velocity == Vector3.Zero)
{
characterNode.Velocity = characterNode.SpriteNode.FlipH ?
Vector3.Left :
Vector3.Right;
}
characterNode.Velocity *= speed;
dashTimerNode.Start();
}
public override void _PhysicsProcess(double delta)
{
characterNode.MoveAndSlide();
characterNode.Flip();
}
private void HandleDashTimeout()
{
GD.Print("idle state");
characterNode.Velocity = Vector3.Zero;
characterNode.StateMachineNode.SwitchState<PlayerIdleState>();
}
}
public partial class Player : CharacterBody3D
{
[ExportGroup("Required Nodes")]
[Export] public AnimationPlayer AnimPlayerNode { get; private set; }
[Export] public Sprite3D SpriteNode { get; private set; }
[Export] public StateMachine StateMachineNode { get; private set; }
public Vector2 direction = new();
public override void _Input(InputEvent @event)
{
direction = Input.GetVector(
GameConstants.INPUT_MOVE_LEFT, GameConstants.INPUT_MOVE_RIGHT,
GameConstants.INPUT_MOVE_FOWARD, GameConstants.INPUT_MOVE_BACKWARD
);
}
public void Flip()
{
bool isNotMovingHorizontally = Velocity.X == 0;
if (isNotMovingHorizontally) { return; }
bool isMovingLeft = Velocity.X < 0;
SpriteNode.FlipH = isMovingLeft;
}
}
and my heirchy is:
I just created the animationPlayer from scratch again and still i am getting this error where the enter state is getting an infinite loop, i do not know when this is happening and why
as you can see in the screen i am getting enter and exit idle state in an infinite loop (674+) updating
I got help in discord and the problem was here:
currenState.Notification(GameConstants.NOTIFICATION_ENTER_STATE);
currenState = newState;
currenState.Notification(GameConstants.NOTIFICATION_EXIT_STATE);
i changed to this:
currenState.Notification(GameConstants.NOTIFICATION_EXIT_STATE);
currenState.Notification(GameConstants.NOTIFICATION_ENTER_STATE);
currenState = newState;
and it worked
I’m glad your issue was resolved! Thanks for posting an update (which might in turn help another stuent!) Have a great day and code code code
thanks!! but now i am getting another error haha, the problem is that the dash animation is triggering and exiting really fast, and starting again an infinite loop, something is happening with my notifications i think:
public partial class PlayerIdleState : PlayerState
{
public override void _PhysicsProcess(double delta)
{
if (characterNode.direction != Vector2.Zero)
{
characterNode.StateMachineNode.SwitchState<PlayerMoveState>();
}
}
public override void _Input(InputEvent @event)
{
if (Input.IsActionJustPressed(GameConstants.INPUT_DASH))
{
characterNode.StateMachineNode.SwitchState<PlayerDashState>();
}
}
protected override void EnterState()
{
base.EnterState();
characterNode.AnimPlayerNode.Play(GameConstants.ANIM_IDLE);
}
}
public partial class PlayerDashState : PlayerState
{
[Export] private Timer dashTimerNode;
[Export(PropertyHint.Range, "0,20,0.1")] private float speed = 10;
public override void _Ready()
{
base._Ready();
dashTimerNode.Timeout += HandleDashTimeout;
}
protected override void EnterState()
{
base.EnterState();
characterNode.AnimPlayerNode.Play(GameConstants.ANIM_DASH);
characterNode.Velocity = new(
characterNode.direction.X, 0, characterNode.direction.Y
);
if (characterNode.Velocity == Vector3.Zero)
{
characterNode.Velocity = characterNode.SpriteNode.FlipH ?
Vector3.Left :
Vector3.Right;
}
characterNode.Velocity *= speed;
dashTimerNode.Start();
}
public override void _PhysicsProcess(double delta)
{
characterNode.MoveAndSlide();
characterNode.Flip();
}
private void HandleDashTimeout()
{
characterNode.Velocity = Vector3.Zero;
characterNode.StateMachineNode.SwitchState<PlayerIdleState>();
}
}
public abstract partial class PlayerState : Node
{
protected Player characterNode;
public override void _Ready()
{
characterNode = GetOwner<Player>();
SetPhysicsProcess(false);
SetProcessInput(false);
}
public override void _Notification(int what)
{
base._Notification(what);
if (what == GameConstants.NOTIFICATION_ENTER_STATE)
{
GD.Print("Enter");
EnterState();
SetPhysicsProcess(true);
SetProcessInput(true);
}
else if (what == GameConstants.NOTIFICATION_EXIT_STATE)
{
GD.Print("Exit");
SetPhysicsProcess(false);
SetProcessInput(false);
}
}
protected virtual void EnterState(){}
}
again!! fixed!! was easy!! hahaha always happen something like this xD
currenState.Notification(GameConstants.NOTIFICATION_EXIT_STATE);
currenState.Notification(GameConstants.NOTIFICATION_ENTER_STATE);
currenState = newState;
i had like that and have to change it to this:
currenState.Notification(GameConstants.NOTIFICATION_EXIT_STATE);
currenState = newState;
currenState.Notification(GameConstants.NOTIFICATION_ENTER_STATE);
was so easy hahaha, i was only changing the state after sending the notification, so it never changed xD
Somethign I am noticing now about how your states are handled, you should exit a state, set the new state and then enter the state. That could be causing an issue
Ah I was just typing this hahaha good find
thanks for all the help Foss
This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.