Accessing some (but not all) information from a PackedScene

Please excuse the long post. I was initially just going to ask about deriving from PackedScene, but I figured that including my other options and the surrounding context would make things clearer. I have some questions, but I’m also looking for thoughts and feedback in general.

Godot Version

4.2.1

Background

In my game, attack definitions (called GameActions) are defined as trees of nodes, which are then saved as Scenes. This will hopefully allow me to easily build modular attack systems with multiple parts.

For example, an attack that applies an effect to nearby enemies and heals the user might look like this:

RootNode      (GameActionRoot)
├AOE          (GameActionNode)
│└ApplyEffect (GameActionNode)
└HealPlayer   (GameActionNode)

Each node within that structure has its own properties – AOE might include a parameter for range and damage, for example.

AOE (GameActionNode):
    Range: 10
    Shape: Circle
    Damage: 0
    HitsTeam: Enemy

The problem

As well as the behaviors provided by the branch and leaf nodes, each attack definition also needs to include some information about the whole thing. Things like its icon, its tooltip, its name, etc. I initially simply put these in the RootNode.

Those parameters have to be accessed far before the complicated tree is relevant. The tree isn’t necessary until the attack is initialized, but the icon, name, and tooltip all need to be accessible to the UI.

But when I store the trees as a PackedScene, these variables are no longer accessible at all, until I unpack the entire thing. I’m not really sure what the best way around this is.

I’ve listed a few options below, and I’d like to hear other people’s thoughts.

Option 1: Just Unpack the thing

Unpack the tree immediately, the moment it’s put into the button.

Pros:

  • Easy

Cons:

  • Feels a bit silly to have an entire unnecessary tree structure being held by my lightweight AttackButton object.
  • Probably wouldn’t work in-editor. Attack buttons would only unpack attack definitions at runtime, meaning that in-editor they’d be missing their icons.
  • No way to determine at compile-time that the PackedScenes I’m providing are actually GameActions.

Option 2: Use a resource to hold additional information

Instead of giving the UI a reference to the GameAction PackedScene itself, create a resource that holds attack names, icons, tooltips for the UI, as well as a reference to the attack definition scene that this information refers to.

Like this:

class GameActionReference: Resource {
    [Export] string AttackName;
    [Export] string Tooltip;
    [Export] Texture2D Icon;
    [Export] PackedScene GameAction;
}

Pros:

  • Keeps UI lightweight
  • Separates appearance and functionality
  • Should probably work in-editor

Cons:

  • Have to make and keep track of two files for each GameAction now (the PackedScene and the Resource with a reference to it)
  • More chances to mess up
  • Still no way to ensure type safety

Option 3: Use Resources instead of nodes

Instead of using Godot’s Node structure to store my tree, make a new Resource type that can contain itself.

class GameAction: Resource {
    List<GameAction> children;
}

class GameActionRoot: GameAction {
   // icons, tooltips, etc.
}

Pros:

  • Type safety, finally
  • Don’t have to worry about accessing information – it’s all there, all the time.

Cons:

  • Can’t use Godot’s convenient hierarchy
  • Inspector gets much more cluttered
  • Lose Transform information, making code that handles previews at different locations more annoying to write

Option 4: Extend PackedScene??

Okay, I don’t even know if this is possible. But I was wondering if I could write my own extension of PackedScene, so that some information was available immediately, without unpacking the scene.

class GameActionPackedScene: PackedScene {
    // tooltips, icons, etc.
}

Pros:

  • Icons, textures, and tooltips immediately accessible
  • Only one file per attack definition
  • Type safety

Cons:

  • I have no idea if this is possible
  • If it is possible, I’d have no idea how to save a scene as one of these new objects.

Alright, that’s everything. If anyone has any advice on this sort of thing or has solved a similar problem, I’d love to hear it. I might be way overcomplicating all this…

Some more options I’ve found out about:

  • Adding metadata to a PackedScene. Could work, but seems like an abuse of the system. Currently bugged and nonfunctional anyway.

  • Adding a script to the outside of a PackedScene. I’ve seen some things indicating this may be possible, but I haven’t figured out how to do it. Maybe it’s only possible for Scenes in the hierarchy, and not PackedScene Resource files.

  • Using PackedScene.GetState() to access properties of packed nodes. This looks clunky and potentially difficult to use (properties are indexed by int, not by name), but if I can get it to work, this would be exactly what I’m looking for.