Invalid call - nonexistent function

Godot Version

4.1

Question

the function run_away() in ghost_body.run_away() gives me an error:
“Invalid call. Nonexistent function ‘run_away’ in base ‘Nil’.”
i dont know if i forgot something or not, is there a way to fix this?

ghost_body does not have a valid reference.

but it does:
@onready var ghost_body = $theghost as BodySprite
is this actually valid though?

I’m not familiar with the as BodySprite syntax for @onready, but I have seen Godot silently fail on some incompatible assignments. Have you checked to see if ghost_body has a value after this assignment?

i checked and i dont think it has a value after it
btw BodySprite is a class

so is there a solution to this?

Its likely your path to the node (or spelling) is wrong.
Drag the node from the scene tree into your code page and press ctrl and drop the node.
This will give you the correct path to it. You can then add the type as BodySprite.

Here’s a better way:
Public variables, example:
@export var ghost_body:Node
Set up nodes in Inspector and save the scene

Try removing as BodySprite, and see if ghost_body has a value.

according to the tutorial im using, it isnt the wrong one but ill use the actual name anyway, still didnt work

also tried removing as BodySprite, ghost_body seems to have a value

i also putted @export var ghost_body:Node, but they all still got the same error

Post more of the code please

ok

func run_away_from_pacman():
	if run_away_timer.is_stopped():
		theghost.run_away()
		run_away_timer.start()
		
	current_state = GhostState.RUN_AWAY
	
	# stop timers
	update_chasing_target_position_timer.stop()
	scatter_timer.stop()
	
	var empty_cell_position = tile_map.get_random_empty_cell_position()
	navigation_area_2d.target_position = empty_cell_position

I think the issue is in your BodySprite class. I think either you don’t have a class_name BodySprite in your code, or you didn’t change the class type to BodySprite in the scene tab:

class_name BodySprite is in another gd file, and i didnt change the name though
but i tried to replace theghost in theghost.run_away() with bodysprite and it gives me an error saying “Identifier “bodysprite” not declared in the current scope.” (before that i tried adding the bodysprite class name in the bottom of another class name but it says that class name should only be used once so i erased it)
EDIT: fixed the bottom problem

Post the complete script file that has the error in it and the file where you define the BodySprite class.
A screenshot of your Scene Tree for both would be good as well.

Otherwise it’s just guessing what’s wrong with your code and no one can properly help you. Complete context for resolving errors is important.

the script that has the error in it:

extends Area2D

class_name Ghost

enum GhostState {
	SCATTER,
	CHASE,
	RUN_AWAY
}

signal direction_change(current_direction: String)

var current_scatter_index = 0
var direction = null
var current_state: GhostState


@export var speed = 65
@export var movement_targets: Resource
@export var tile_map: MazeTileMap
@export var image: CompressedTexture2D
@export var chasing_target: Node2D
@onready var update_chasing_target_position_timer = $updateChasingTargetPositionTimer
@export var bodysprite:Area2D
@onready var navigation_area_2d = $NavigationAgent2D
@onready var scatter_timer = $scatterTimer
@onready var run_away_timer = $runAwayTimer

func _ready():
	navigation_area_2d.path_desired_distance = 4.0
	navigation_area_2d.target_desired_distance = 4.0
	navigation_area_2d.target_reached.connect(on_position_reached)
	
	call_deferred("setup")
 



 
func _process(delta):
	move_ghost(navigation_area_2d.get_next_path_position(), delta)
 

func move_ghost(next_position: Vector2, delta: float):
	var current_ghost_position = global_position
	var new_velocity = (next_position - current_ghost_position).normalized() * speed * delta
	
	caculate_direction(new_velocity)
	position += new_velocity

func caculate_direction(new_velocity: Vector2):
	var current_direction
	
	if new_velocity.x > 1:
		current_direction = "right"
	elif new_velocity.x < -1:
		current_direction = "left"
	elif new_velocity.y > 1:
		current_direction = "up"
	elif new_velocity.y < -1:
		current_direction = "down"
		
	if current_direction != direction:
	
		direction = current_direction
		direction_change.emit(direction)


func setup():
	print(tile_map.get_navigation_map(0))
	navigation_area_2d.set_navigation_map(tile_map.get_navigation_map(0))
	NavigationServer2D.agent_set_map(navigation_area_2d.get_rid(), tile_map.get_navigation_map(0))
	scatter()
 
 
func scatter():
	scatter_timer.start()
	current_state = GhostState.SCATTER
	navigation_area_2d.target_position = movement_targets.scatter_targets[current_scatter_index].position
 
func on_position_reached():
	if current_state == GhostState.SCATTER:
		scatter_position_reached()
		speed = 65
	elif current_state == GhostState.CHASE:
		chase_position_reached()
		
	elif current_state == GhostState.RUN_AWAY:
		run_away_from_pacman()


func chase_position_reached():
	print("kill pacman")


func scatter_position_reached():
	if current_scatter_index < 3:
		current_scatter_index += 1
	else:
		current_scatter_index = 0
	navigation_area_2d.target_position = movement_targets.scatter_targets[current_scatter_index].position
	
	








func _on_scatter_timer_timeout():
	starting_chasing_pacman()

func starting_chasing_pacman():
	if chasing_target == null:
		print("no chasing target, chasing wont work obviously lol")
	current_state = GhostState.CHASE
	update_chasing_target_position_timer.start()
	navigation_area_2d.target_position = chasing_target.position


func _on_update_chasing_target_position_timer_timeout():
	navigation_area_2d.target_position = chasing_target.position


func run_away_from_pacman():
	if run_away_timer.is_stopped():
		bodysprite
		run_away_timer.start()
		
	current_state = GhostState.RUN_AWAY
	
	# stop timers
	update_chasing_target_position_timer.stop()
	scatter_timer.stop()
	
	var empty_cell_position = tile_map.get_random_empty_cell_position()
	navigation_area_2d.target_position = empty_cell_position
	
	
	
	


func _on_run_away_timer_timeout():
	starting_chasing_pacman()

the script that defines the BodySprite class:

extends Sprite2D

class_name BodySprite


@onready var animation_player = $"../AnimationPlayer"




func _ready():
	self.texture = (get_parent() as Ghost).image
	animation_player.play("ghost_moving")

func run_away():
	animation_player.play("thetwostates")
	animation_player.play("frightened_moving")

the scene tree (note that its the character scene, not the main one):
Captura de tela 2024-10-02 172817

waiting for a reply

In your first post you said this line defined ghost_body.
@onready var ghost_body = $theghost as BodySprite
This is not in any of the code you posted.
Did you change it to this:?
@export var bodysprite:Area2D
If so, you will need to provide a value for that export in the editor.

i tried to replace theghost in theghost.run_away() with bodysprite

I think you are really getting things mixed up here.
When you add “as BodySprite” you force the variable ghost_body to become a BodySprite object. So you don’t replace ghost_body with bodysprite that will only confuse the issue.

At this point it might be helpful to link the tutorial you are following.

yeah i changed it to @export var bodysprite:Area2D since someone suggested it
btw heres the tutorial im following:

Is the script of theghost node different from the BodySprite class?