Sites


Godot Game Engine

Adding mechanics with GDScript

What we have done in the editor so far was just putting together the resources that we want to use in the game and organize them. But how do we make things happen? How does the player interact with the world? How do we calculate the score? All this will need code to happen.

For this purpose Godot uses its own scripting language GDScript which takes a lot from Python. It is made to be simple to learn, readable, and is delivered with a lot of predefined classes that fasten the game development. It doesn't need compilation and is dynamically typed. Of course, this is not made to speed up rendering but make it so easy to use that it's worth the choice. Most of the optimisation is done in the engine and GDScript gives a lot of performance improvement over Python in the game context. For those who need more control of the internal workings of their game, C++ can also be used.

To read this chapter, it is better to have some basic knowledge of some programming concepts. You may find courses about python in our manual.

The main part of the code structure is given by Godot itself. Scripts will be attached to nodes and extend the classes those nodes are based on. We will just need to define what is specific to the game: mostly variables and functions.

Variables

Variables are explicitely declared:

  • at the top of the script file if they need to be shared through functions,
  • in the function themselves.

Use the keywordvar to declare the variable. As GDScript is dynamically typed, there is no need to define if it is an integer or a string or any other type. This will be done when a value is given.

 var speed

Of course you can affect a default value at the beginning:

 var speed = 100

Or at any time in any function to which the variable is accessible:

 speed = 100

GDScript comes up with standard types (like int, float, string, bool, null, array, dictionary…) but also has some specific types related to common maths calculation in a game (such as Rect2, Vector2, Vector3…) and some engine-specific types (such as Color, Image, Object, InputEvent…). It is not really the purpose of this manual to describe then intensively. Refer to Godot's in-editor reference for more information about each type.

Note that one can also define constants with theconst keyword instead ofvar.

We will sometimes want to "export" a script variable. When doing so, the variable will be displayed in the inspector for the nodes that the script extends. This is a good practice coders should apply for important variables. It helps non-coders and game designers to test several values and improve the gameplay without risking to break all the code. We will give an example for that later on.

 export var speed = 100

Functions

To declare a function you simply need to use the func keyword like this:

 func function_name().
# Function magic goes here 
If you had a look at Python, you will notice that there is no def, and no self which is considered as implied. On the other hand, conditions, while or for loops are really similar.

Predefined Godot functions begin with an underscore. For example the default _ready() pre-inserted in any new script as we will soon see.

 func _ready():
# Initialization goes here 

Of course, as our script extends the base class, each function is a method of a class and might be called as a member.

 var player = get_node("player")
 player.do_this()

Let's make things move with a script

Enough words for now, let's see the process of adding a script.

  1. Select the root node of the scene and click the script button on the top right section of the panel.
  2. In the window Create Script for Node, there should not be much to change. Give a name to the script file, eventually a path if you made directories for them or enable Built-in Script if you don't want the script to be stored externally. Of course we would consider to have separate file as a better practice.
  3. The Script tab of the main view is then enabled and a script template displayed. We can see that the script extends Node2D (that means that all variables and methods of Node2D are available to this script) and a _ready() function that we'll customize. The Inspector displays resource properties like path and name.
  4. In the _ready function, deletepass and add instead print("test"). Save the script and play the game or the scene. This will play the game but also display the Debugger and the Output panel. If everything is fine, "test" should appear in the output panel.
     
  5. That's a first step, and we see everything is working, so let's go on.
  6. In our scene, let's add a Label node in which we will display the number of passed buildings. As you may see, the label is empty. Its value could be set in the Inspector, but in this example we will manipulate it from a script because we need to set it dynamically.
  7. Let's create a function for it and call itscore. If we want it to be used at the very beginning we need to call it in the _ready function. So we get this:
     func score():
    print("In score function") # Check that everything works

    func _ready():
    # Initialization goes here
    print("Test")
    score()
  8. If you play, you should get both the "test" and "in score function" messages in the output panel. If there is an error, the debugger should display it and say which script causes it and at which line. In the example below, there is an unexpected End Of Line (EOL) error at line 15 caused by a missing " before the closing parenthesis.

    Click on the continue button (the only one active) to pass through and be able to close the game window and go back to your script.
  9. If you want to have more debugging message and pause the playing process to follow what is happening, you may define breakpoints. Place the cursor on the line where you want the game rendering to stop, press F9 or use Debug > Toggle breakpoints to add or remove breakpoints. When playing the game, Godot will stop at each breakpoint so you can see the messages or the values of each variable. Use Step Into or Step Over buttons to go on.
  10. Let's now change the text in the Label. First we need to access the Label node. A really common way is to use the get_node() method. Let's first test if the node exists:
     if (get_node("Label")):
        print("Label found")
    else:
        print("No label node")
  11. If a node named Label is found, the first message is displayed. Which is good. On the other way, change the label name to match your need. Finally, we need to know how to set the text in the game. If you have no idea of what to use just go to the Helptab, in the Search in Classes column, look for Label. Click on it to display all the method available for that class. On top we have a Public Methods, especially on called set_text(), which looks appropriate. Click on it to display details which say simply «set the label text». It could be worse. Let's use it and play:

     if (get_node("Label")):
        get_node("Label").set_text("0")
    else:
        print("No label node")
The next thing would be to replace the text by an integer that would be incremented each time the bat passes an obstacle. But fist, we need to spawn buildings and the make the bat move. Here is how we will set buildings:
 
 var obstacles = []
var spawn_ofs = 1000
export var spawn_distance = 500

func spawn_obstacle():
var obs = preload("res://pipes_random.scn").instance()
obs.set_pos(Vector2(spawn_ofs, 0))
spawn_ofs += spawn_distance
add_child(obs)
print("Obstacle spawned at ", obs.get_pos())

First we declare our variables: obstacles, spawn_ofs (initial offset) and spawn_distance. See that we added export keyword before the third variable. This will make it displayed in the Inspector to let the game or level designer play with the value and equilibrate the game, without having to open the script file.

Then we added a function which preloads the scene containing the buildings and instantiates them. We set the position of the new instance in a Vector2 using a variable x value. We then update values for the next instance and add the instance as a child of the current node.

Our function will be used as the bat will move. So that is now what we have to do now.

// show autoload

Il y a une erreur de communication avec le serveur Booktype. Nous ne savons pas actuellement où est le problème.

Vous devriez rafraîchir la page.