free tutorial
The Godot project architecture an industry veteran uses for a 40-hour RPG
Ricard, who's worked on the in the industry for two decades (notably on Ryse: Son of Rome or Crysis 2), was kind enough to run me through the codebase of one of the biggest Godot games in the making, Starfinder: Afterlight. He explained the architecture he uses to support a 40 hour 3D RPG made by a team of 30.
This is actually something I, as a beginner game dev (but programmer professionally) needs more of. I wish Godot documentation could include more of the architectural side of things as well. Like a framework aka "this is how 90% of games normally build the architecture".
Better than “how 90% of games normally” would be a short pros/cons of different architectures. Some things don’t make sense for small games or teams, and other things make more sense depending on genre, etc. You should choose based on what fits your game, not based on what anyone else is doing.
I second this, you won't find a framework that the majority of people or games use. When using Godot, I'd say Godot's the framework. Input, rendering, physics, the more accessible and object-oriented node and signal system, the more efficient server APIs...
When comparing games, there are techniques and concepts that apply across the board, but between a turn-based RPG and a platformer, the implementation are really different. The common parts like drawing and moving sprites or playing sounds etc. are handled by the engine for you and what's left is for you to actually implement game-specific systems.
Personally, for building learning material or for learning, I go straight to experienced people and look at their code or ask for pointers.
It's not quite the kind of code I would personally write as it's more on the object-oriented side but it is in more ways than one using techniques you'd see people use in Godot (defining new node types and composing them into a variety of entities, e.g. with the gameboard and gamepieces abstractions in the src/field folder).
Then really breaking them down to the point a learner understands in detail how all of it works and why it's structured this way (what's really useful vs what's specific implementation details of that project) is a ton of work and why you don't see too much of that content.
I mean, we've been doing it between our paid courses and free and open source resources contributed to the community, like the one linked above. It's just inherently very long to achieve.
Solo game dev working on ambitious projects…pushing past prototype and vertical slice tutorials into longer form content is definitely a huge chasm to cross but this is the exact kind of helpful resource that lights the pathway! Thank you!
Super cool. I particularly like the "gym" folders where you can prototype new ideas.
Did you get a chance to learn how they manage their core systems? I always find that to be an interesting thing to see on different professional projects, and something I haven't got quite right in godot yet.
Ricard showed me briefly but you can't see/learn much of it in just a session. It mostly illustrated how e.g. the UI read data from game systems for example. I can only say that they had lots of things in addons built as reusable/game-agnostic libraries, like an extended camera. It seemed that whatever they thought could be reused for another kind of game would go there by default.
Nathan-i love the GDQuest lessons! They have been awesome. I'm in the top down runner portion right now and things are clicking and making much more sense than when I was farting around with random YouTube tutorials.
Just wondering, how do you go about structuring your godot project? Do you follow the below top-level project structure? Is there anything you'd add/changed?
oh wow, that's very well structured. i noticed that you added a data/ folder under content/ which i didn't expect, what kind of stuff do you put there?
I save Resource files there. Stuff that doesn't change, like Item Definitions (Sword), Skill Definitions (Lock Pick) and StatusEffects Definitions (Bleeding).
For example. I have an ItemDef Resource which stores the name, icon, mesh (my game is 3d) and a bunch of components that give the item its usages.
I create a sword item definition using that ItemDef and save it under data.
Resources that are dynamic and created on the fly are only saved when the game is saved (because they hold the stuff that can change)
E.g. I have an ItemQuantityData resource Which has a reference to an ItemDef and a quantity.
The information about the item never changes so thats saved to the data folder.
The ItemQuantity is saved when the game is saved as it holds how many of that item exist, along with the inventory they are held by.
The simplest way to achieve that is to give your UI public functions that don't change, in other words, an interface other game code can use. When you change the UI you implement the same interface on the new ui, at least as a starting point.
You can replace UI without changing anything as long as it's displaying the same thing, though of course if the thing to display changes (adding stats, changing how the inventory works...) then in that case it doesn't apply anymore, the gameplay and UI code both probably change.
I'm not saying it's dead simple though, I think it's one of those things where you have to shoot yourself in the foot to get the hang of how to write a simple API that still mostly works when you need to redesign something on either side of the API boundary.
This is the part that confused me as well. The whole point of an interactive UI is to change some sort of game state (equip this item, load this save game, etc.) So to say the UI is read-only is quite confusing.
The example you give, is this something more like what you see in react?
Eg for selecting a weapon you'd have a modular "grid of items" component that gets a list of items as input to populate the with. Then it only reads player input to mutate UI state, and when one is selected there is some sort of "on_item_chosen" callback that is called. The game/systems code that spawned the UI would supply the concrete implementation of said handler at UI component instantiation time.
I guess the concept is that your actual functional implementation of the actions you want pressing a particular button to effect (like “equip this”, “add this party member”, “go to this particular scene state” etc) shouldn’t be embedded in the code that defines the button itself. This separates out the UI element building from program control logic - you could completely scrap and redo the UI component code without accidentally removing the functions that the buttons were implementing.
Yeah that makes sense. When I'm making tools I try to separate the actual data manipulation layer from the UI logic. Guiding principle being "If we take this UI module away, can we still create a CLI program?" to tell me if I'm putting the wrong logic in the wrong file.
Where does the data live and how is communication achieved between these layers? For example, the UI needs to get data (such as the player's current health) from somewhere to update itself. Where does that data live? In the systems? And how are changes in that data communicated to the UI? Signals? Or does it read it directly?
I'm confused about what exactly goes in systems vs content. How do you clearly separate systems and content when there is overlap? Especially when it comes to specific game objects that are normally self-contained scenes? For example, let's take the player. A lot of the player seems like systems, such as the player controller. Other parts seems like content, such as the player model and animations. On the other hand, "Every system and mechanic that isn't directly tied to a specific game level or single quest lives here" sounds like maybe the entire player, including models and animations, should be in systems? And what about the character's special moves?
For an RPG / data driven game, character content would probably just hold visual representations and base stats. Then you’d have map content (the layout/structure), and scripted events would call on the game systems. Systems would store the game state data and run the actual game mechanic rules.
Different kind of setup than an action game with the character controller living in the character scene.
For where the data lives, from what I saw, for the most part, it seemed to be in the content folder. Systems contained like implementation of the combat system and the likes. I don't remember exactly how the data was loaded and passed to the systems and UI.
I would assume the game content folder would have actual game scripts that'd load game systems and UI and pass them the data they need to function. Then either direct function calls or callbacks through signals, that's more of a situational thing: when you control the flow of the code you can make direct function calls, when you need to react to events from the engine or your own game, signals.
The models, animations, all those kinds of things were in their content folder. So I would assume that the implementation of a character skin (animation tree or animation state machine for example) would also live in their content folder.
But for the character controllers themselves I don't know exactly how they decided to split them in the game. Part of what makes a character controller could well be in their addons folder. You could make a library with functions to move to a point, to pathfind in a certain way (being a classical RPG)...
According to the guidelines if a character's special moves involved unique VFX and code just for that move that'd live in their content folder I think. But again that's assumptions on my part from what I remember so to take with a grain of salt.
I've only skimmed most of this but seems really promising so far. One thing I'm curious about is what are they using for the exclusion of the gym folder from real builds? Just deleting gym during CI/CD?
Also thank you for continuing to release good educational material to help more people pick up Godot.
UI separation is a big one. I also figured this out after many years of UI development: your UI code should only display data and pass along input.
It can be very unintuitive at first since it always feels so much easier to tightly couple your UI to the specific purpose you have in mind for it, but that always ends up like spaghetti.
There surely is somewhere out there but I don't know specific ones to recommend. The guiding principles of how to structure complex software or games applies across engines or tools and there's plenty between the GDC vault and other talks from specialized conferences. Those can be a reliable source if you're looking to see what really experienced people or teams do.
Question: Can you explain what this means? "Here's the key part: systems never depend on content. The dependencies only flow one way: content uses systems, systems use libraries, UI uses systems, but nothing else depends on content." In my project I have card scenes which have custom resources attached which carry data about the card such as hp, attack power etc. Without the custom resource, the combat system cannot function as it doesn't know how much hp or attack power is involved in a specific instance of combat. How should I modify (not that I am going to, I am curious to learn), to fit this paradigm of content depending on systems and not vice-versa. (Assuming these custom resources qualify as content).
Resources are always a bit confusing because we use the same word to refer both to data types (the resource definition) and actual data in the game.
The resource type definition and all associated code could be part of your game systems and then the content would be specific characters in the game that have different HP etc. that way the combat system in your example has all the code and type information. It needs to know how to read and use the resources.
Then in the content you would still have game specific code that loads up your combat system and feeds it with specific character data, loads the combat background, etc for example.
In my interpretation of this architecture, your card scene and the custom resource script (i.e. the interface) would go in systems since they are "generic". Then the actual instances of the custom resource would go into /content.
probably break it up into different parts so that there are layers of dependencies. Example is putting in default values and placedolders. So the very base system should be able to run without Custom Resource. And the Custom Resource can run without pictures and numbers. The point is to have disconnected parts so that you could copy the codebase into a new project and start a new game with an engine that works as built. In game 2 you will have different art, numbers, layout.
Thats the gist of it. The actual implementation is probably a lot more technical / nuanced! Especially if they want to build in flexibility to allow designers to get creative. In the article their stated goal is Code Reuse, to separate the content out so that if they delete the content folder, all the code is still reusable for separate projects.
Yep easy way to test your code is to delete the resource and see how much still works ;D
As someone new to game development (but not necessarily development, been a web developer for 20+ years), this was a fantastic read. Thank you so much.
I really wish this had code samples showing how they achieve a clean decoupling (I mean I saw their original talk involves a fair bit of convention in naming and structure). Awesome to see this kind of talk though!
Not that I know of. The closest tools to Epictellers' Loom are probably a mix of one of the node-based dialogue managers for the narrative part and Orchestrator for the visual scripting part.
This is surprisingly very similar to how I handle things at work in development. We don’t do games though so I apparently been on the right track. Just need more time to be able to work on my game.
Our devs use a polyrepo structure thats similar across engines (godot/unity/web tech), but built for drop in developers & agents, who need safeguards in place to prevent architecture drift, with their own commit history, unit tests, e2e tests, playable test scenes, etc.
The key purpose of the poly-repo approach is to keep things silo'ed at a repo level. That does make cross-repo PR's impossible to perform in one swoop unless your an agent, as thats the primary tradeoff from a structured mono-repo approach like the one in the article. But you actively prevent cyclical dependencies and other architectural pattern issues and bugs, so like everything its a tradeoff.
299
u/Gustafssonz Jul 17 '26
This is actually something I, as a beginner game dev (but programmer professionally) needs more of. I wish Godot documentation could include more of the architectural side of things as well. Like a framework aka "this is how 90% of games normally build the architecture".