Some Common Nodes and Navigation Through Game Loop
Custom Button Design
For this game we are not using Godot’s build in node/class “Button” as option for our in-game buttons, nor we will use it’s theming features. Instead, we are going to create our own Button, flexible enough for reuse anywhere in the game. With few options and unique appearance.
As shown on the image, it’s “TextureRect” with two child: “TextureRect” and “Label”.
Parent node “TextureRect” contains button’s texture. It’s child “TextureRect” is just the frame, while child “Label” represents text in the button.
This is good time to use Godot’s tool feature – which will allow use to instance buttons as the children of menus and make them as we need them to be.
As our entire base button is custom, we also want custom apparance when it’s enabled/disabled.
So we are placing two functions to make this easy doable. Function “enable” will change color of the texture to it’s default color, for this game it’s shade of blue – with RGB (0.21, 0.6, 1.0). And it will also connect button to signal “gui_input” in case that it was disconnected.
Similar to the “enable” function, “disable” will set the color to the gray – hinting the player that button is disabled. And disconnect the “gui_input” signal if it was previously connected.
Speaking of “gui_input” signal – it’s default signal triggered for button no matter where it is instanced. This is not the one we use to trigger unique method call after button is placed in some menu – that one needs to be post created.
As shown in the image, upon pressing the button, by default it will change textures for both base and frame making sure that “pressing” is visible to the player. And finaly, it will instance “button” sound.
Note: Advantages of using Godot’s theme for buttons or making a custom button are many. But probabbly the most important one is fast application of changes and limitation of buttons functionalities as well as it’s properties, especially if it’s going to be provided to the designers for the future use. Making custom button can also be defined as class, with a bunch of unique properties where we could allow attachment of different sound, effects, etc.
Menus, From One to Another and Back Again
Usually, when we are starting game development, we jump directly to the main feature.
This might work just fine for testing ideas, making prototype or just playing around with the engine.
However, when there is idea shaped and stable enough, and there is plan to make it into the full game. We might want to make sure to have working game scene transitions and navigations through the menus first.
So as mentioned in part one, our game loop starts in the “main” node.
Meaning that any child instantiated in it will be there from the very start of the game – for this game that will be Main Menu scene. You can do it like we did in line six, as show in image below or simply drag and drop scene as child of “main” node.
This is scene is currently active user interface, meaning that it will define itself as “ui” in the “global.gd”, if you remember, only one “ui” can be valid at the time. So this scene will be main user interface element when game starts.
Note: Starting point for every game starts in the “main” functions, node in our case – even though it might not be called “main”. However, starting subscene can vary from game to game. Some developers prefer to show company logo, some kind of splash screen or something else. For larger game with heavy assets, at this point usually loading screen shows up, and then game will progress to the Main Menu when assets are loaded.
Main Menu
As you can see in the previous image, our Main Menu is consisted of several buttons where buttons: Play, create and options will lead user to the their own menu. We will go through creation, functions and purpose of each one after we deconstruct Main Menu first.
Play Button – is gray, meaning it’s disabled since there isn’t any existing character.
However, when there is playable character and we press it – the game will transit to the gameplay stage.
In short, currently active “ui” global’s (Main Menu) will be removed and Loading Screen will be instantiated as child of “UI”. Once when world is ready, Loading Screen will be also removed and “gameplay” user interface will be instantiated as child of “UI” defining itself as “ui” in the “global.gd”.
World will be instantiated as child of “main” node.
We can see example of this in the next image.
Create Button – the most interesting button at the moment, so let’s see what it does.
Well, very similar to the button “Play”, but instead of calling for Loading Screen, it will bring “Creation Menu” scene in front of the player. Take a look at how it looks in the next image.
Note: You might want to make sure to disable this button at some point, otherwise – player could keep going and creating new characters after there is no more memory – “kind of” since it would take a lot of time to do it.
Creation Menu
Before we dive into explaining all features from the “Creation Menu” let us mention the way button “Back” works.
Let’s deal now with interesting features from the scene.
Color palette (Skin, eyes and hair color):
It’s Godot’s build in node/class “GridContainer”.
It’s two lines of code, the first one releases the it’s parent node, in this case “Creation Screen” and second one instantiate calls for instantiation of “Main Menu” scene.
As we can see on the image, first we declare all wanted colors.
Then under the “_ready” function “ColorRect” will be created and added as child of the “GridContainer” with all listed properties. And lastly bound to the function “on_colorRect_gui_input” – which will allow us upon pressing bound “ColorRect” to apply it’s color to the asset of the player’s character, eyes color in this case.
Character name:
For making input when it comes to the name of our character we chose to use another Godot’s build int node/class called “TextEdit”, due to it’s useful functionalities in this case.
Variable “max_length” represents maximum characters per name while variable “current_text” is used to compare new input with the old and see if there is still room for another character – this happens in the function “_on_text_changed” connected via “TextEdit” signal “text_changed”.
Common Godot’s “_process” function in this case just making sure that defined global’s character is named equally to the text from our “TextEdit”.
This is example of “fast prototyping”, in practice it’s better to make this happen when button “Create” is pressed, and not allowing it to loop each frame as it is for now.
Button Create:
Pressing the button “Create” will triggers similar code lines as button “Back” with one line added – “Global.save_character()”. About this function will discus later on when we dive character save system and approach we used for this game – for now it’s good enough to know that this line as it is named saves our character.
After all code lines are executed we are back to the Main Menu, but – now there are some changes.
Back to Main Menu
As you have noticed, there, in the character list is the button with text “John” (name of character).
Since there is existing character, buttons Play and Delete are enabled by default. Before we jump into gameplay world and it’s user interface, let’s expand our understanding of button Play and explain functionalities of button Delete.
Function “_process” of the script “mainMenu.gd” will make sure that buttons Play and Delete are enabled or disabled as needed. In it’s first part, code lines 12-14, it will disable both buttons since there isn’t any existing character in the character menu. This is done by calculating chilrens of the same menu.
Next, in the code lines 16-20, it will also make sure to disconnect button’s signals, if they are previously connecter, in case there was existing character.
In following code lines under “else” the process will go other way around, enabling and connecting buttons if the are not previously connected.
Note: Placing all of above inside “_process” function is yet another practice of fast codding, while we don’t worry much of memory usage. There are better ways to activate these code lines only if needed. One way would be to use unique signal and triggers it when character is created or deleted.
When button Delete is pressed, data for the currently selected character (node defined as “character” in global.gd) will be deleted and then “refresh” method will be called for node “vBoxContainer_characters” making sure that it shows only characters from existing data.
Save and Load System
Autoload “global.gd” is the most accessible script in this game. So it makes sense to place there save and load functions for characters as well as options later on. Regardless, it does not have to be the case, we will for example make sure that options saving and loading calls comes from other script.
In this case saving character date is quite easy. When function from the image is called, it will provide path to the character data.
Since only one “Global.character” can be defined at the time, it can use information of the save name from it, we don’t even have to make it to accept argument of character/data name.
Then file/data for new character will be created or rewritten, if character is existing.
As you can see on the image above, after variables as level, power, armor, etc., are stored, file will be closed.
Function “load_character” comes with one argument and that’s the character name, used to find it’s data.
So you might wondering why we need now argument, why just not pull the name from the defined global character.
The trick with it is that we use button with character name from the character lists to load certain data. So now we are not dealing with currently defined global character but making game to define the new one by using button’s text (character name) as argument for “load_character” function.
Loading Screen
As shown on the next image, our Loading Screen scene is made of several node.
Parent “Control” node and it’s children and one sub-child.
ColorRect node is just colors of the background, in this case it’s black.
TextureProgressBar represents bar which shows how far game is loaded – it’s child Label here says just “Loading…” but with a little additional code it can shows percentage of loading progress or “n” of “n” loaded scene/objects.
Note: It’s nice to show something useful to the player during this “boring” stage of the game – like some kind of hints or share some interesting information of game world.
The way “loadingScreen.gd” works is that it uses path to the node defined via variable “scene” to load the scene within “_process” function.
Once when “ResourceLoaded” loads thread load is loaded – scene will be instantiated and “Loading Screen” will be removed.
User interface elements in this game are not memory heavy, so we don’t need to load them through loading screen.
Instead, once when world is loaded and instantiated, we will use common “instantiate” method to bring user interface for the gameplay to the stage.
It also needs to be instantiated after the world, otherwise there will be crashes since many elements from the gameplay user interface are connected to the valid character instance, etc
Options Menu and it’s Save/Load System
On the next image you can see appearance of Options Menu with few setting choices provided to the player.
When it comes to the saving and loading current options settings, we use similar approach as we done in the character save and load system.
When we instantiate Options Menu, we also pause the game. So it’s important to set “process_mode” to “Node.PROCESS_MODE_ALWAYS” – otherwise player would stuck in the freezes options menu and the only way out would be to force restart the game.
In the code lines 8-10 we can see example of applying current options settings to the check box for audio mute and sliders for music an sounds previously loaded in the global script “option.gd” or not – if there isn’t such a save file, default values will take a place.
One thing that vary and triggers different code lines than it’s usually do it’s Back button. Reason for this is that Options Menu can be instantiated during different game stages. Same menu can be called while playing the game and while being in the Main Menu.
So depending on the case, we need to make sure the right user interface element is instantiated after pressing the button Back. In the code line sixteen we are checking if there is valid world instantiation.
If “true” System Menu will be called in the UI, and if Options Menu is called from the Main Menu, the same one will be instantiated back.
When button Okay is pressed, we need to apply current settings to the game as well as to set values to their proper variables in the “options.gd” before we call for method “save_options”. Beside this, we need to release the Options Menu and call the same code lines as button Back does – to make sure that player will be in the right game corner after Options Menu is gone.
Saving and loading optionsis almost the same as they are for the character, just with different stored and received values.
One difference is tha “load_options” does not requires any argument since it can be just one save file for options settings.
Next up is Part 3: