In the previous lessons, we learned:
In this lesson and the next, we’ll build upon these techniques to create a turret that slows down mobs and another that fires homing missiles.
Then, we will place the turrets in a Tower Defense level, with enemies walking along a path.
We will provide the enemies and the code that makes them walk along the path, as explaining these is outside the scope of this series.
If you want to learn how they work, please open them and see if you can understand them. We included many comments to help you make sense of the code.
For now, let’s create the turret that slows down mobs.
Like scripts, we can extend scenes in Godot. The inherited scene receives all the changes to nodes and properties in the parent scene.
We will use this scene inheritance to change the look of our slow-down turret.
Find the scene file TowerDefense/Turret.tscn
,
right-click on it, and select New Inherited Scene.
A new scene will open with some nodes greyed out. Save it as
TowerDefense/TurretSlowingDown.tscn
. We also want to rename
the root node to keep things consistent.
Any change in Turret.tscn
will also affect
TurretSlowingDown.tscn
. Also, you can add nodes and change
properties in TurretSlowingDown.tscn
, and they will
override the default values from Turret.tscn
.
Note: Contrary to code, which only uses text, scenes are complex beasts, so scene inheritance has some limitations. Changing the structure of the parent scene can cause losses in the inherited scene. We recommend ensuring that the parent scene is complete before creating inherited scenes.
We can now change the look and script of our new turret.
Let’s begin with the texture. Locate the image
tower_area.png
, and assign it to the .
Finally, let’s extend the script. Create a new script file in the
TowerDefense/
directory and call it
TurretSlowingDown.gd
. Assign it to the
TurretSlowingDown node.
We’re done with the setup! Let’s write our code.
Open the TurretSlowingDown.gd
script and replace its
content with this line:
extends "Turret.gd"
Here’s what we want to change in this script:
First, we override the _on_Timer_timeout()
function and
make it do nothing. That way, the turret does not shoot anymore.
func _on_Timer_timeout() -> void:
# We don't want to shoot, so we override the function to do nothing.
return
Similarly, in the _ready()
function, we turn off physics
processing so that the turret does not turn.
func _ready() -> void:
set_physics_process(false)
We then store our slow-down factor and tint as constants. That way, we put a name on the script’s two important values.
# The amount by which we divide the speed of mobs in range of the turret.
const SPEED_DIVIDER := 2.0
# We use this color to tint the mobs in range.
const COLOR := Color(0.4, 0.6, 1.0)
We’re using a color value for the first time. Like
, the is a type built into the Godot engine.It represents a color using three values: an amount of red, green, and blue.
Each value ranges from 0.0
to 1.0
. For
example, pure red is Color(1.0, 0.0, 0.0)
, while pure green
is Color(0.0, 1.0, 0.0)
.
You can right-click on the term
in the script editor and select Pick Color.This will open a color picker in which you can preview the tone that you chose or select a new one.
We can now use those values to slow down and change the color of mobs
that enter. Let’s start with _on_body_entered()
:
func _on_body_entered(body: PhysicsBody2D) -> void:
pass
By overriding the function, we removed the instructions from
Turret.gd
. We could copy over what we had in the parent
script:
func _on_body_entered(body: PhysicsBody2D) -> void:
append(body)
targets.select_target()
However, that would duplicate code. If we wanted to change it later, we’d have to remember to update two different scripts.
Instead, we want to run the code of the parent function.
Luckily, most programming languages have a way to call the parent of the function we’re overriding.
In GDScript, the syntax is to write a dot before the function’s name.
func _on_body_entered(body: PhysicsBody2D) -> void:
# Call the function _on_body_entered() from Turret.gd
_on_body_entered(body) .
Notice the dot. It’s essential! It tells Godot to call the function in the parent script.
The function will call itself infinitely without the dot, and the program will freeze.
This principle is called “super.” We say that we call “the super function.” Other languages often actually use a function or keyword named super instead of a dot.
With that done, we can extend the function with our new functionality.
func _on_body_entered(body: PhysicsBody2D) -> void:
# ...
# We reduce the mob's speed and change its tint.
/= SPEED_DIVIDER
body.speed = COLOR body.modulate
The last line assigns a color to the modulate
value of
the body.
You can change this value manually by selecting any 2D node and going to the Visibility -> Modulate property in the Inspector. Try changing the modulate value of the turret and notice it tints its sprite.
If you leave your mouse a second over the color, it will give you the red, green, and blue color values.
Let’s complete our code by restoring the mobs’ speed and color in
_on_body_exited()
.
func _on_body_exited(body: PhysicsBody2D) -> void:
_on_body_exited(body)
.# We restore the mob's original speed and remove the tint.
*= SPEED_DIVIDER
body.speed = Color(1.0, 1.0, 1.0) body.modulate
The default modulate
value that restores the color is
white, or Color(1.0, 1.0, 1.0)
.
Our turret is complete. You can test it by opening
TowerDefense.tscn
. Drag and drop the
TurretSlowingDown.tscn
scene file to place the turret on
the map.
Run the scene to see how the turret slows down mobs around it.
In the next lesson, we’ll code our final turret: one that shoots homing missiles.
Here’s the final code for TurretSlowingDown.gd
.
extends "Turret.gd"
# The amount by which we divide the speed of mobs in range of the turret.
const SPEED_DIVIDER := 2.0
# We use this color to tint the mobs in range.
const COLOR := Color(0.4, 0.6, 1.0)
func _ready() -> void:
set_physics_process(false)
func _on_Timer_timeout() -> void:
# We don't want to shoot, so we override the function to do nothing.
return
func _on_body_entered(body: PhysicsBody2D) -> void:
# Call the function _on_body_entered() from Turret.gd
_on_body_entered(body)
.# We reduce the mob's speed and change its tint.
/= SPEED_DIVIDER
body.speed = COLOR
body.modulate
func _on_body_exited(body: PhysicsBody2D) -> void:
_on_body_exited(body)
.# We restore the mob's original speed and remove the tint.
*= SPEED_DIVIDER
body.speed = Color(1.0, 1.0, 1.0) body.modulate