Error: Cannot call method 'play' on a null value

Godot Version

Godot 4.3.stable

Question

Hello. I’m trying to call a sprites’s animation called “caught” in an enemy kill area. the idea was if the character enters the enemy’s kill area, it will play a startled animation before the mission fails and the game restarts.

Below is what i’ve done so far (i commented out the line that broke the code while trying to add the animation in)

Here’s the code for my enemy’s kill area (the enemy movement is on another script)

extends Area2D

@onready var timer: Timer = $Timer
@onready var caught_growl: AudioStreamPlayer2D = $caught_growl
#@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D2
@onready var animated_sprite_2d: AnimatedSprite2D = $"../AnimatedSprite2D"

func _on_body_entered(_body: Node2D) -> void:
	print("Oh No!")
	caught_growl.play()
	#sprite.play("caught")
	animated_sprite_2d.play("alert") #change enemy skin to angry face
	timer.start()
	
func _on_timer_timeout() -> void:
	get_tree().reload_current_scene()

and here is the script for my player

extends CharacterBody2D

@export_subgroup("Nodes")
@export var gravity_component : GravityComponent
@export var input_component : InputComponent
@export var movement_component : MovementComponent
@export var animation_component : AnimationComponent
@export var jump_component : AdvancedJumpComponent

@onready var sprite: AnimatedSprite2D= $AnimatedSprite2D2
@onready var LadderRayCast: RayCast2D= $LadderRayCast

const SPEED = 400
const PUSH_FORCE = 500.0
const MIN_PUSH_FORCE = 460.0

func _physics_process(delta: float) -> void:
	var LadderCollider = LadderRayCast.get_collider()
	
	if LadderCollider: _ladder_climb(delta)
	else: _movement(delta)
	
	move_and_slide()
	
	for i in get_slide_collision_count():
		var c = get_slide_collision(i)
		if c.get_collider() is RigidBody2D:
			var push_force = (PUSH_FORCE * velocity.length() / SPEED) + MIN_PUSH_FORCE
			c.get_collider().apply_central_impulse(-c.get_normal() * push_force)

func _ladder_climb(_delta):
	var direction := Vector2.ZERO
	direction.y = Input.get_axis("climb_up","climb_down")
	direction.x = Input.get_axis("move_left","move_right")
	
	if direction: velocity = direction * SPEED
	else: velocity = Vector2.ZERO
	
	if velocity: sprite.play("ladder")
	else: sprite.stop()

	
func _movement(delta):
		gravity_component.handle_gravity(self,delta)
		movement_component.handle_horizontal_movement(self, input_component.input_horizontal)
		animation_component.handle_move_animation(input_component.input_horizontal)
		jump_component.handle_jump(self,input_component.get_jump_input(), input_component.get_jump_input_released())
		animation_component.handle_jump_animation(jump_component.is_going_up, gravity_component.is_falling)

VERY very new to Godot and I don’t know what i’m doing most of the time, please be easy on me. Thank you! xx

Your enemy has a different scene tree from the player, this line tries to get a child named “AnimatedSprite2D2” which I’m betting your enemy doesn’t have, but your player does.

You can use the parameter from body_entered to operate on what ever the Enemy intersected. It would be best to include a if statement confirming what the body is, up to you if you have proper collision masking.

func _on_body_entered(body: Node2D) -> void:
	if body.name == "player":
		print("Oh No!")
		caught_growl.play()
		body.sprite.play("caught") # using body (probably player)'s sprite
		animated_sprite_2d.play("alert") #change enemy skin to angry face
		timer.start()

Hello!! thank you for your reply, using this if syntax does make my script play everything as normal, its just… it still doesnt play the animation when
body.sprite.play("caught") # using body (probably player)'s sprite
is used (but everything else is fine!)

Do you get any errors or warnings? If not, maybe the player is overriding the animation in one of the components?

nope… no errors or warning :frowning:

can i ask what
body.sprite.play(“caught”)
syntax does?

(body refers to the player, and play refers to the action to play the animation… but what is sprite?)

So we try to deduce body is the same node with the player.gd script on it, that’s why I added the if body.name == "player": assuming that’s the name of your node with the player.gd script. Once we know this is true we can use the script’s variables through the dot notation.

body.anything_from_player_gd, such as body.gravity_component, or body.LadderRayCast.

Similarly, the sprite variable from player.gd refers to a AnimatedSprite2D, which has the play method.

oh!! i get it.

I think that might get me closer to solving this (maybe i just got the wrong reference to the animated sprite)

thank you! xxxx