Error with class attachment stuff

Godot Version

4.1.3

Question

Why does my attached class throw a nonexistent function error when clearly attached, referenced, and instantiated?

Here’s my hierarchy. It is attached in a screenshot. Here are the scripts, also attached.

Player.gd

extends CharacterBody2D

@onready var animation_handler = $AnimationHandler
@onready var input_handler = $InputHandler
@onready var state_machine = $StateMachine

func _ready():

# Add states
state_machine.add_state("IDLE")
state_machine.add_state("MOVING")
state_machine.add_state("ATTACKING")
state_machine.add_state("BLOCKING")
state_machine.add_state("CUSTOM_STATE_A")
state_machine.add_state("CUSTOM_STATE_B")

# Set initial state
state_machine.change_state("IDLE")

func _physics_process(delta: float):
# Update the state machine
state_machine.update(delta)
input_handler.update(delta)

# Perform actions based on the current state
match state_machine.current_state:
	"IDLE":
		# Perform idle actions
		pass
	"MOVING":
		# Perform moving actions
		pass
	"ATTACKING":
		# Perform attacking actions
		pass
	"BLOCKING":
		# Perform blocking actions
		pass
	"CUSTOM_STATE_A":
		# Perform actions for custom state A
		pass
	"CUSTOM_STATE_B":
		# Perform actions for custom state B
		pass
	# Add more cases for additional states here

InputHandler.gd

extends Node

Define variables

var direction_input: Vector2 = Vector2.ZERO
var lock_direction
var light_pressed
var heavy_pressed
var quick_pressed
var block_pressed

Update function called every frame

func _process(delta: float):
check_direction_input()
check_lock_direction_input()

Function to check for direction input

func check_direction_input():
direction_input.x = Input.get_action_strength(“right”) - Input.get_action_strength(“left”)
direction_input.y = Input.get_action_strength(“down”) - Input.get_action_strength(“up”)

Function to check for lock direction input

func check_lock_direction_input():
lock_direction = Input.is_action_pressed(“lock”)

func check_block_pressed():
block_pressed = Input.is_action_pressed(“block”)

func check_attack_pressed():
light_pressed = Input.is_action_pressed(“light”)
heavy_pressed = Input.is_action_pressed(“heavy”)
quick_pressed = Input.is_action_pressed(“quick”)

Function to reset all inputs

func reset_inputs():
direction_input = Vector2.ZERO
lock_direction = false
light_pressed = false
heavy_pressed = false
quick_pressed = false
block_pressed = false

AnimationHandler.gd

extends Node

class_name AnimationHandler

var animation_player: AnimationPlayer

func _ready():
# Get the AnimationPlayer node
animation_player = $AnimationPlayer

Method to load an animation

func load_animation(animation_name: String, animation_path: String) → void:
var animation = load(animation_path)
animation_player.add_animation(animation_name, animation)

Method to unload an animation

func unload_animation(animation_name: String) → void:
animation_player.remove_animation(animation_name)

Method to play an animation

func play_animation(animation_name: String) → void:
if animation_player.has_animation(animation_name):
animation_player.play(animation_name)

Method to stop the currently playing animation

func stop_animation() → void:
animation_player.stop()

StateMachine.gd

extends Node

StateMachine class

class StateMachine:
var current_state: String
var frame: int
var overridden_states: Dictionary
var weapon_states: Dictionary
var states: Dictionary

# Initialize the state machine
func _init():
	current_state = "IDLE"
	frame = 0
	overridden_states = {}
	weapon_states = {}
	states = {}

# Function to change the state
func change_state(new_state: String):
	if states.has(new_state):
		current_state = new_state
		reset_frame()

# Function to handle state updates
func update(delta: float):
	frame += 1
	var state = current_state
	if overridden_states.has(current_state):
		state = overridden_states[current_state]
	elif weapon_states.has(current_state):
		state = weapon_states[current_state]

# Method to increase frame count
func Frame():
	frame += 1

# Method to reset frame count
func reset_frame():
	frame = 0

# Method to override a state with a new state
func override_state(original_state: String, new_state: String):
	if states.has(original_state):
		overridden_states[original_state] = new_state

# Method to remove state override
func remove_override_state(original_state: String):
	if overridden_states.has(original_state):
		overridden_states.erase(original_state)

# Method to add weapon-defined state
func add_weapon_state(state: String, new_state: String):
	if states.has(state):
		weapon_states[state] = new_state

# Method to remove weapon-defined state
func remove_weapon_state(state: String):
	if weapon_states.has(state):
		weapon_states.erase(state)

# Method to add a new state
func add_state(state: String):
	states[state] = true

I would have to guess it’s from your input handler script that doesn’t have an update function. What does the error say exactly?

Invalid call. Nonexistent function ‘add_state’ in base ‘Node2D (StateMachine.gd)’.

Your posts formatting got messed up, try using the code block button or three ticks when pasting code.

Did you define all of the state machine script as part of class StateMachine:? This would mean all the functions are indented like so

class StateMachine:
    var current_state: String
    var frame: int
    #etc..

    func add_state(state: String):
        states[state] = true

Maybe you ment to use class_name StateMachine the difference is class makes a new type which seems to never be instantiated, but class_name gives a globally usable name to the current script, which you also do not use.

let me try and paste them again

Link to 5 items

here is a link to a onedrive containing the items. The pasting was weird so I had to do this

Yeah the state machine is defined as a single type, it’s basically an empty script because of class StateMachine: at the top. If you do not intend to create multiple StateMachines within this script then you need to get rid of that line.

Here’s how you can paste code blocks

```gd
extends Node
class_name StateMachine

func add_state(state: String):
    states[state] = true
```

looks like this

extends Node
class_name StateMachine

func add_state(state: String):
	states[state] = true

So class name is preferable to just defining a class? That’s odd. I use many programming languages and have never seen that. I’m gonna have some reading to do

It did the trick. Thanks!