0 votes

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";
asked Dec 8, 2019 in Engine by nwgdusr999 (117 points)

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...

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

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.

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!

Please log in or register to answer this question.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.