-
Notifications
You must be signed in to change notification settings - Fork 0
2. Game Structure
Coming from robot programming, you might find yourself stumped by how to structure a Godot project. If that sounds like you, this article is for you!
"Game Structure" encompasses a lot of things, but in this article, I'll talk more about the organization of a project from a broad standpoint--- organizing objects, scripts, game logic, etc.
Further reading: Godot Docs
Understanding the difference between Nodes and Scenes is a crucial yet difficult step to grasp when migrating to Godot (whether from robot-code or from other engines)! Nodes are the individual objects that make up your project. Stuff like individual meshes, colliders, and similar components are classified as Nodes. Nodes can also be made children of other nodes in a hierarchical fashion, seen below:
Any series of nodes, organized in that kind of hierarchical organization, can be made into a Scene. The game can instantiate scenes through code--- in this sense, one might think of a Scene from an OOP perspective as a "class" (or a specific subsystem on a robot, if that's what you're used to) which contains member variables (which in this case could be meshes, physics objects, etc.). This "class" is then instantiated, sometimes multiple times, to generate the desired behavior for your game. It is important to note that Nodes also have properties, which are similar to member variables, so this allegory shouldn't be taken too far. Scenes must have one (and exactly one) top level Node, under which everything else is a child / descendant. Additionally, scenes are saved as files in the File Manager (more on this later).
Take, for example, our earlier example of a game's hierarchy. We could condense the "Character" into a Scene in order to organize our project and isolate development on the "Character". You can do this easily by right-clicking on any node and selecting "Save Node as Scene" After doing this, the explorer will look like this:
Clicking on the circled "scene" icon will open the editor for that scene. You will also observe that the Scene will be saved as a file on the disk, and thus accessible through the File Manager tab as well.
In order for your game to run, it needs an "entry point"--- when you launch the application, where does it go? Most games would use a Main Menu for this, where players can load saves and change settings, but games without saves or settings don't necessarily need one. Think Flappy Bird, or the Dinosaur Game for example.
In Godot, we do this by setting a Main Scene. When the game is loaded, this scene is instantiated once and everything there begins running. You can set it by clicking Project (on the top) -> Project Settings -> Run -> Main Scene.
You'll want to instance scenes in code and manually in the editor for various reasons. For example, when designing a level, you might want to place a bunch of trees that you have saved as a scene. To do this by hand, simply drag the file from the File Manager to the editor viewport window (where you can see everything in your project).
To instantiate in code is a bit more complicated. It's covered more in later tutorials here, but for now, the Official Documentation is your best friend!
It's also possible to wipe everything that's currently instanced and replace it with an instance of a specific Scene, for example, when switching between a Main Menu and a game world. See here.
All projects in Godot read from the files on your hard-drive to determine what data is in your project. Everything inside your project's directory on your machine can be seen in the Godot editor through the File System tab (also sometimes referred to as your project "Resources"). Files stored in the Resources of your project can then be used as assets inside your scenes, for example, adding a mesh from the Resources into a world scene.
Godot does not force you into using any sort of structure for your Resources, but not structuring this tab properly will result in confusion later down the line, especially when working in teams. Consider creating directories for each kind of resource. For example, a directory for meshes, scripts, and images might look something like this:
Further reading on resource organization can be found here, on the official docs.
This is much more abstract and up to whatever structure the user would like to use. However, for many games which work based on rounds, high-scores, waves, or anything else that has to run for the entire runtime of the game, you'll need a way to keep code running even between rounds. To do this, many games will have a featureless Node which serves no purpose but to contain a script on it. That script is responsible for juggling the transition between rounds, menus, etc.
A lot of interacting with objects depends on scripting. We will focus on using GDScript in this tutorial. To add a script, right click the object and click Attach script. The script will automatically have template code.
Further reading: Godot Docs
While using Object Oriented Programming in GDScript is not required, it can be very useful in numerous situations. ClassDB
contains information about all the built in classes in Godot. When a script file is created, the extends
keyword is used to indicate which class methods are going to be inherited from the parent class. Each script file is a class on its own, but you can create subclasses by typing class [name]
: and then adding each subclass item below it. GDScript is similar to Python because it is an indentation based language. Syntax such as keywords can be found at here, on the official docs.
Nodes have three special methods than run at certain times:
_ready()
- runs when the code starts
_process()
- runs every frame, good for input and visuals
_physics_process()
- runs at exactly 60hz, good for character movement
Further reading: Godot Docs
Signals are sent when something specified happens to a node. For example, a button getting pressed. Other nodes can call a function when that occurs. Signals allow one game object to react to a change in another without them referencing each other. This allows your code to be more flexible because coupling, the interdependence of objects is significantly decreased.
For example, if a player character takes damage, their life bar will react to that change using signals.
Signals are used as method arguments. To use them, create a node, for example a button, and then go to the Node tab next to the Inspector tab. There will be a list of all of the available signals on the selected node. Double click on a signal to open the node connection window. You can then connect the signal to the desired node. After connecting the node an icon will be displayed next to the function. The icon will display information about the connection. Afterwards, the name of the connection can be inputted to a function.
Another option is to use the connect()
and get_node()
method to make the connection only through code.