Can we load a script in a Dict and then call it from another script?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By nwgdusr999

I’m trying to make a sort of dynamic action loader to add generic actions to nodes. Ex: in Global:

var ACTION_BY_ID = {
	ACTION_ATTACK: load("res://scripts/actions/ActionAttack.gd"),
	ACTION_MOVE: load("res://scripts/actions/ActionMove.gd")}

Then in a LoaderScript:

static func add_action_by_id(var actionId: int) -> Node2D:
	var action: Action = Global.ACTION_BY_ID.get(actionId);
	var actionNode = load(str("res://characters/actions/", action._get_name(), ".tscn")).instance();

Is it possible to do something like this? Loading a script in a dictionary and using it in a different script? The last line above throws error: “Attempt to call function ‘instance’ in base ‘null instance’ on a null instance.”

Action (abstract; not to be instanced) would be something like this:

extends Node2D
class_name Action
static func _get_name() -> String:
	return "ErrorAbstractAction";

And an actual extending Action:

extends "res://scripts/actions/Action.gd"
class_name ActionAttack

static func _get_name() -> String:
	return "ActionAttack";

As I’m looking at this, I’m thinking that I could just put the path of the Action in the Global script Dictionary and then load it in the LoaderScript… But my idea was to load each a Action only once in Global, and not many times in the LoaderScript… But thinking some more; think I’ll have to load them all in the LoaderScript, make the LoaderScript a Singleton and just reference the Actions by ID or something… Wow getting confusing…

nwgdusr999 | 2019-12-08 23:49

That’s why, with some of my projects, I’ll first draw it out on paper.

Ertain | 2019-12-08 23:56

I don’t really get what you are trying to do, but it seems the problem is that the load is not finding the correct scene, which returns null, and null does not have the instance() method.

But if you are doing all that already, why not add the scenes to the map, preloading them instead of load, and instancing the scenes itself:

var ACTION_BY_ID = {
ACTION_ATTACK: preload("res://characters/actions/ActionAttack.tscn"),

var actionNode = action.instance();

But if you actually need what you want keep what you are doing just check what the str method is returning and the node path is actually a valid one for your case.

tastyshrimp | 2019-12-09 20:11

Thx! Sorry for delay but I think it was a compiling bug with Godot… I’m not sure why, but sometimes Godot seems to throw a bunch of errors, then just restarting the editor clears them and every thing works fine… So I’m really not sure why, I moved all that block of code from one class to the other, then moved it back, and bam, it worked, same code exactly… Really weird!

So yeah, it seems you can!

nwgdusr999 | 2019-12-14 12:18