Why is my AnimatedSprite2D is giving null?

Godot Version

godot 4.7 stable

Question

i beg somebody help me, even the dumb ahh chatgpt doesn’t understand shii

Silly question, but did you save the file before running?

Also, paste the whole script.

Player script shouldn’t be an autoload.

here you go:

extends CharacterBody2D

#======= Movement =======
@export var speed := 70.0
@export var acceleration := 750
@export var friction := 700

@export var jump_velocity = -130
@export var gravity_mult := 0.6

@export var max_fall_speed := 160
@export var min_fall_speed := -125

@export var wall_jump_x := 100
@export var wall_jump_y := -100
@export var dash_force_x := 220
@export var dash_force_y := 130

#======= State ========
var is_dead := false
var can_move := true
var dashes := 1
var jumps := 1
var on_wall = false
var dashing = false
var can_climb = false
var jumping_on_wall = false

#======= rename =======
@onready var animation = $AnimatedSprite2D

#======= data ======

#====== Timers ======
var cayote_time = 0.08
var cayote_timer = 0.0

var wall_jump_cayote_time = 0.1
var wall_jump_cayote_timer = 0.0

@export var jump_time := 0.08
var jump_timer := 0.0

func _physics_process(delta: float) → void:

if is_on_ceiling():
	var collision = get_last_slide_collision()
	if collision:
		var collider = collision.get_collider()

		if collider.name == "climb_blocks":
			can_climb = true
		else:
			can_climb = false
			print(can_climb)











#type shi

if is_on_floor():
	cayote_timer = cayote_time
	jumps = 1
	jump_timer = jump_time
	if dashing == false:
		dashes = 1






var direction := Input.get_vector("left", "right", "up", "down")

var wall_side = get_wall_normal()


direction.x = sign(direction.x)
direction.y = sign(direction.y)

if is_on_wall():
	wall_jump_cayote_timer = wall_jump_cayote_time

if not is_on_wall():
	wall_jump_cayote_timer -= delta



if can_move:

#=========================== Gravity ============================
if not is_on_floor():
cayote_timer -= delta
jump_timer -= delta
if not dashing:
if jump_timer <= 0:
velocity += get_gravity() * gravity_mult * delta
velocity.y = clamp(velocity.y, min_fall_speed, max_fall_speed)
#================================================================

#==================== Movement Left / right =====================
#Right / Left
if direction.x != 0:
velocity.x = move_toward(velocity.x, speed * direction.x, acceleration * delta)
animation.flip_h = direction.x < 0
else:
velocity.x = move_toward(velocity.x, 0, friction * delta)

#================================================================
#============================ Jump ==============================
#Jump
if Input.is_action_just_pressed(“jump”) and cayote_timer > 0 and not on_wall:
jump()
#================================================================

#=========================== Climbing ============================

	#wall climbing
	if is_on_wall() and not dashing:
		climbing(Input.get_vector("left", "right", "up", "down"), wall_side)
	elif not is_on_wall() and wall_jump_cayote_timer > 0:
		if Input.is_action_just_pressed("jump"):
			velocity.y = wall_jump_y

#========================================================================

#=========================== Ceiling Climbing ============================
#top climbing
if is_on_ceiling() and can_climb:
ceiling_climbing(Input.get_vector(“left”, “right”, “up”, “down”))
print(can_climb)

#================================================================

#=========================== Dashing ============================
#dash
if Input.is_action_just_pressed(“dash”) and dashes > 0:
dash(Input.get_vector(“left”, “right”, “up”, “down”))

#================================================================

if Input.is_action_just_pressed("down"):
	global_position.y += 0.1

move_and_slide()

animations(Input.get_vector("left", "right", "up", "down"))

func animations(direction):
if direction.y < 0:
pass
if velocity.x == 0:
animation.play(“idle”)

func jump():
velocity.y = jump_velocity
GameData.jumps_total += 1
jumps -= 1

func dash(direction):
GameData.dashes += 1
Camera.apply_shake()
velocity.y = dash_force_y * direction.y
velocity.x = dash_force_x * direction.x
dashes -= 1
if direction.x != 0:
dashing = true
gravity_mult = 0
await get_tree().create_timer(0.15).timeout
gravity_mult = 0.6
dashing = false

func climbing(direction, wall_side):
if direction.x == 0 and not jumping_on_wall:
velocity.y = 0
if Input.is_action_just_pressed(“jump”) and not is_on_ceiling():
velocity.y = wall_jump_y
jumping_on_wall = true
gravity_mult = 0.4
await get_tree().create_timer(0.2).timeout
jumping_on_wall = false
gravity_mult = 0.6
#up
if is_on_wall() and direction.x != 0 and not jumping_on_wall:
velocity.y = -35
if is_on_wall() and Input.is_action_pressed(“down”):
velocity.y = 35
velocity.x = -0.01 * wall_side.x

func ceiling_climbing(direction):
velocity.y = 0
velocity.x = 30 * direction.x
if direction.y > 0:
can_climb = false

func Death():
is_dead = true
Camera.apply_shake()
can_move = false
velocity = Vector2.ZERO
GameData.deaths += 1
print("Deaths: ", GameData.deaths)
await get_tree().create_timer(0.50).timeout
Respawn()

func Respawn():
is_dead = false
global_position = RoomData.respawn_pos
RoomData.room_data()
can_move = true

func _on_spike_coll_body_entered(body: Node2D) → void:
if body is TileMapLayer:
Death()

why not

i just removed my player from autoload and the animatedsprite2D isn’t null anymore, i don’t really understand how it works but thank you

Because autoloads load before everything else, including assets. Effectively you are trying to load something that doesn’t exist yet.

Read up on autoloads in Godot’s documentation. You probably have some misconceptions about how they actually work.

When you setup a script as an autoload, the engine will at startup create an “invisible” node parented to the scene tree root, running that script.

If the same script is also normally attached somewhere in the scene, you’ll basically run it twice “at the same time”, but the autoloaded instance won’t have any children. This will cause errors in parts of the script that expect children to be there.

In your case, that’s @onready var animation = $AnimatedSprite2D. Since the addressed child node isn’t there, animation won’t be initialized on ready, and the autoloaded instance of the script will throw a null-reference error when you try to use animation.

You can easily verify this by putting print(get_path()) into script’s _ready(). In your case it will print 2 different paths, confirming that script is indeed running twice on different nodes - a regular node inside the player scene and a singleton.