I’m very new to Godot, and I’m having an issue implementing state machines. I’m getting that error when I run the playtest “Invalid call. Nonexistent function ‘Enter’ in base ‘Nil’.” I’ve been following a tutorial on how to do it and everything is set up the same way for the state class so I’m not sure what’s wrong. Here’s the code for the state machine that’s getting the error. The error is at line 17.
class_name StateMachine
extends State
@export var current_state: State
var states: Dictionary = {}
func _ready():
for child in get_children():
if child is State:
states[child.name] = child
child.transitioned.connect(on_child_transition)
else:
push_warning("State machine contains child which is not 'State'")
current_state.Enter()
func _process(delta):
current_state.Update(delta)
func _physics_process(delta):
current_state.Physics_Update(delta)
func on_child_transition(new_state_name: StringName) -> void:
var new_state = states.get(new_state_name)
if new_state != null:
if new_state != current_state:
current_state.Exit()
new_state.Enter()
current_state = new_state
else:
push_warning("Called transition on a state that does not exist")
P.S. sorry if my post isn’t formatted well, I created an account just for this so I’m not too familiar with posting guidelines or anything.
Not sure why you have null references. You should only really use null, when you’re expecting null to appear. They’re not used to check for bugs, because they only hide bugs. They don’t fix them.
Here’s a simple state machine. I don’t see any .new() anywhere.
class_name BaseState
func Enter() -> void:
# Perform Enter Animation
# Enable State Controls
pass
func Exit() -> void:
# Disable State Controls
# Perform Exit Animation
pass
func Update(delta : float) -> void:
# Called every frame.
# Delta is the elapsed time since the previous frame.
pass
I’m not following. What is the TestState and where would it be declared? Also does anything go into the Enter and Exit functions or do I just leave those at pass? Sorry again I’m pretty new to this
The base state would be like an empty template. It’s like a custom variable. You make that and save them inside a folder. Then you create another script that uses that base for your new states and save them inside a folder too. Make sure to use all the same functions as your base state, so you’re consistent and organized.
class_name TestState extends BaseState
var PlayerInput: bool = false
func Enter() -> void:
# Perform Enter Animations and Sounds
PlayerInput = true
func Exit() -> void:
PlayerInput = false
# Perform Exit Animations and Sounds
func Update(_delta: float) -> void:
if Input.is_action_just_pressed("Accept_Button"):
if PlayerInput == true:
Accept_Input()
if Input.is_action_just_pressed("Cancel_Button"):
if PlayerInput == true:
Cancel_Input()
func Accept_Input() -> void:
print("You pressed the A button.")
func Cancel_Input() -> void:
print("You pressed the B button.")
I tried just copy and pasting this to see if it would work, and it does launch but it doesn’t print the “You pressed the a button” message or B button message, I just attached the input script to the player, is that wrong?
Those are my own custom buttons. You will have to make your own and put the names there. Oh, make sure to add extends Node on the StateMachine before you add them to a node.