State machine function call throwing an error when ran

Godot Version

godot 4.3 beta3

Question

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 StateMachine

var CurrentState : BaseState = TestState.new()

func _ready() -> void:
	CurrentState.Enter()

func _physics_process(delta: float) -> void:
	CurrentState.Update(delta)
	
func ChangeState(newstate: BaseState) -> void:
	CurrentState.Exit()
	CurrentState = newstate.new()
	CurrentState.Enter()
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
1 Like

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?

I should say I did add the actions in settings

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.

1 Like

Ah ok yea, I just had to add extends Node, thanks so much for the help!

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.