Scenes, Scripts, Resources - How to structure my project?

Godot Version

4.3

Question

I’m currently developing my first game and I’m really struggling with the idea of how my general architectures should look. I’ll give you an example of the structure I have in mind, and maybe someone of you can explain, how they would translate this structure into Godot!

So, imagine a turn based combat system. I have characters, one hero on the left side (which the user can control) and multiple enemies on the right side. Each character has a stack of tokens representing their health, the tokens should neatly stack on top of each other. Furthermore a character has a dice tray containing a various amount of different dice, which determine attacks or other special abilities of the character. The dice also should be placed neatly aside of each other.
Depending if it’s a hero or an enemy, the health and dice should be displayed inverted (so health stack on the left side of the hero, but on the right side of the enemy, and so on).

Later I want to have the player fight in different levels, and each level consists of multiple enemy waves.

Currently I’m working a lot in code, but that kind of defeats the purpose of scenes for me, ideally I want for example to create an enemy as a scene, but then define different attributes of that enemy, but it get’s really complicated fast, and I don’t know what the best approach would be.

Here you can see the logical structure:

  • Character
    • Hero/Enemy
      • Unique Ability (optional)
      • Graphic (Sprite)
      • Health Stack (should handle positioning of tokens)
        • Health Token (various different types with different graphics and effects)
      • Dice Tray (should handle positioning of dice, can be open or closed)
        • Dice (various different types with different sides
          • Die Side (6 per dice, with different values, graphics, valid targets, etc.)

Here is what it looks like:

As I said I’m doing a lot in code, which is why the enemy scene looks like this currently (not ideal, you don’t see anything, i just put in placehodler sprites, so it’s not completely empty)

Can anybody give me a rough idea on what a good translation into Godot classes and Scenes would look like?

I’ve read about the @tool decorator, thinking about the @export decorator a lot, but just can’t wrap my head around what would be an efficient solution, that allows me to use the editor to it’s full potential, but also doesn’t burden me with a lot of manual work and duplication.

Thanks for any help.

Here I can only provide suggestions and you have to then think through each feature and try to separate them while thinking about the bigger picture of your game, which only you know. One think I would advise is to not spend too much time stressing about the perfect architecture. You can always come back later and change stuff if you find out your code is getting spaghettified. I have lost entire days in the past just thinking about how to structure things and not getting any real work done.

As far as I know Godot does not have any systems that would help you to visualize your type of game in the editor. Everything that happens using Script will only be displayed at runtime and since your game is very procedural in nature a lot of stuff has to be done using script. Here I would still suggest that you try and think about which logic you could remove from your scripts and offload as much of what you can to Godot. For example I don’t know how you are handling you backgrounds but this is one thing that could probably be extracted from you purely script based approach. You can also extract dices, chips, cards and other building blocks of your game into separate scenes and then combine them back together to gain usability. This will also make it easier to test those components individually. With those you can create a template to use for the enemies and “player controls” You can then probably also just put player controls in the editor since they are not procedural (I think?).

@export is an insanely strong feature of Godot that I recommend you use whenever possible. You also do not have to always use it to define strict values but implement underlying code to accept boundaries through export so you can then play around with values when testing out your game. Keep in mind that you can also extend Resource, it can really come in handy.

Also keep in mind that you can attach the same script to multiple different nodes and that you can define a class_name that will then allow you to create that “node” more easily in the scene. You could use this to extract base functionality of your enemies and then build on top of that when they have features too specific to implement only using @export.

Do not be too afraid of creating separate scenes and scripts when you cannot find a clean way to generalize. What can also really help with this is if you have a strong style guide for you file tree structure and naming conventions so you do not get lost in everything when you eventually have to do this.

Godot also has a series of really good articles on this topic: Best practices — Godot Engine (stable) documentation in English

I hope my answer helped you at least a bit and good luck with your game :slight_smile:

1 Like

Thank you for your detailed answer, much appreciated!

Yeah I agree with you that I shouldn’t worry too much to achieve a perfect structure.

I guess it just feels wrong to basically ditch the editor except for maybe a background sprite or a marker and do everything in code.

How I imagine it would work best for me is if I can “build” my characters in editor. But I’m not sure @export is really capable of this stuff, I’m running into issues currently.

Let’s take the health stack for example. In the Editor, I want an array of Chips (a chip is a scene and a class currently), and for each chip I want to edit the exported variables (type, value, etc.).

I’m struggling to understand if and how this would be possible.

@export var chips: Array[PackedScene] = [] does wild stuff, but seems inherently wrong, because I only want to allow the chip scene.

However, @export var chips: Array[Chip] = [] only allows me to set instatiated nodes from the chip_stack scene itself, but I want to have an instantiated scene of a new chip in there!

I’m still struggling to fully understand the difference between class and scene in the context of game architecture.

So to sum up:
In the editor, I want to fill up a health stack of a character with health tokens and for each token choose a type (defined by the token class) and a value. These tokens should be children of the health stack and the stack should handle the alignment in the editor and the game. Is that possible?

Look, basically, there is no need to create separate scenes to keep the game correct; I prefer to create a node that holds the first one, then copy it and add it to the children. Regarding their positions, I can use a container, and in another section, each die can be a class that controls the features of the die, but I should have nodes for the user interface. This way, the flexibility and structure of the program will be appropriate…

I said this so you have an idea of your work and feel that as you think about these matters, you realize there are many ways to approach each stage, and none of them are really wrong or impossible. My best advice is to start; if it doesn’t work, try to fix it, and make changing your approach the last priority. Since this is your first game, I think the deeper you go in your style, the better!

@Mahan thanks for your input. I have already started and am looking for a way to efficiently use the editor for my needs.

I think I have a breakthrough now using Godot Notifications and the @tool and @export keyword! Here’s an example of how I managed to get a health stack working:

My chip stack called “Chips” has a tool script attached to it and that tool listens for changes to the children, which then triggers an automated positioning in the editor.

@tool
extends Node2D
class_name ChipStack

func _notification(what: int) -> void:
  if what == NOTIFICATION_CHILD_ORDER_CHANGED and Engine.is_editor_hint():
    call_deferred("stack_chips")

func stack_chips() -> void:
    var chips = self.get_children().filter(func(c): return c is Chip)
    for i in range(chips.size()):
      chips[i].position = Vector2(0, -i * 14)

The Chip itself has a exported variable for the texture, so I can change the texture from the editor.

@tool
@export var chip_texture: Texture2D:
    get:
      return $Sprite2D.texture
    set(value):
      $Sprite2D.texture = value

Now I can add, delete and reorder children, and they will be neatly stacked on top of each other, as you can see here:

Well, there is a problem; you need to sort them during the game as well. Is it not possible for them to increase or decrease or change during the game? If not, then you just needed a tool, which you now have. However, if they are supposed to be dynamic (as is expected in this game), you should know that a tool script does not run in the game.

I should be able to just work with the children in game aswell.

with get_children() i can get all chips and then do whatever whith it, even instantiate a new Chip scene as a child and call the order function again.

I’m using the in-editor method to create the basic different heroes or enemies. In game (when removing a chip for example upon taking damage), I will do it with code of course.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.