Trouble Running a Script from within a Resource

Godot Version

4.6.2.stable.steam

Question

I’m currently working on a system to handle enemies through resources (tho I don’t know whether that’s a good idea). Every enemy is handled by a generic enemy object, which holds onto some resource that contains its enemy type’s stats, attacks, and animations. When trying to get enemies to play an idle animation given by this resource, I ran into some issues.

I have an Enemy object with a script that looks like this:

class_name EnemySpawn
extends Node2D

var resource : EnemyResource

func spawn(spawn_resource: EnemyResource) -> void:
    set_resource(spawn_resource)

func set_resource(new_resource: EnemyResource) -> void:
    resource = new_resource
    $Sprite2D.set_texture(resource.sprite)

func _physics_process(delta: float) -> void:
    resource.animate($Sprite2D, delta)

The EnemyResource looks like this:

class_name EnemyResource
extends Resource

@export var sprite : Texture2D
@export var animation : Script
@export var animation_speed: int

func animate(target: Sprite2D, delta: float): 
    animation.play_animation(target, delta, animation_speed)

The animation script I’m trying to run is of type GenericAnimation, which looks like this:

class_name GenericAnimation
extends Script

func play_animation(target: Sprite2D, delta: float, speed: int) -> void:
    pass

And finally, the specific animation I’m trying to play looks like this:

extends GenericAnimation

func play_animation(target: Sprite2D, delta: float, speed: int) -> void:
    target.rotation += delta * speed

For whatever reason, the script that plays the animation isn’t executing. Through good ol’ print statements, I know that _physics_process() is running, as is animate() on EnemyResource, but it stops short of running anything inside play_animation().

I’ve checked some of the obvious answers: I know that the generic version of play_animation() that just passes isn’t being accidentally executed, I know that the animation is visible when it does run, and I know that the specific EnemyResource I’m using does (at least in theory) point to the correct script.

I’m guesing I might be misunderstanding something about how Godot’s resource and/or script systems work. Does anyone know why the animation script might not be executing?

You shouldn’t use the Script class, make it a Resource instead:

class_name GenericAnimation
extends Resource
# in the EnemyResource class
@export var animation : GenericAnimation

Also, instead of overriding an empty placeholder function, you should make GenericAnimation an abstract class:

@abstract class_name GenericAnimation
extends Resource

@abstract func play_animation(target: Sprite2D, delta: float, speed: int) -> void

Thanks for the tips!! It’s super helpful to know about abstract classes, and that definitely makes for much nicer code. Unfortunately this didn’t seem to work when I tried it, though there could be a detail I’m missing.

This led me to static functions, which seems to be what I need. Making play_animation() static allows the function to be called smoothly from the resource - though abstract classes and static functions aren’t compatible, which makes it a lot less pretty </3