In this lesson, we will code the ghost effect pickup.
When the player touches the pickup, the character will be able to move through walls for a short time.
To achieve that, we will split the code across two places:
This is a typical way to code items, powerups, and other pickups. It allows you to later delete, add, and modify pickups without having to modify the character’s code.
We’ll get started by adding the ghost effect code on the character.
When activating the ghost effect, we want to:
Let’s start by adding the missing nodes to the character. Open the
scene ObstacleCourse_Part2/Godot.tscn
.
Add a
node and a second as children of the Godot node. Rename the nodes to TimerGhost and AnimationPlayerGhost.Select the TimerGhost and increase its Wait Time to
3
seconds in the Inspector. That’s the effect’s
duration. Turn on the One Shot property to ensure the timer
does not cycle continuously.
We will now create a new animation that makes the character sprite fade in and out.
Select the AnimationPlayerGhost and create a new animation by clicking on Animation -> New.
Name the animation “ghost.”
We want to animate the modulate property of the Godot node to make all the sprites in the scene blink.
Click the Add Track button in the
editor and select Property Track.In the popup window, select the Godot node and then search for its modulate property.
This approach to creating tracks is an alternative to using the key icon in the Inspector.
Right-click in the animation track at 0.0
seconds and
create a new keyframe by clicking Insert Key.
Then, right-click around 0.4
seconds in the timeline and
insert a second key.
Select the newly inserted white square and make the color next to Value transparent in the Inspector.
To do so, click the white rectangle to open the color picker and pull the A slider to the left.
You should now see a gradient going from white to transparent white in the animation editor, as indicated by the checkerboard pattern.
Lastly, click the loop icon in the animation editor’s top-right to make the animation cycle.
If you play the animation now, you’ll see your character fade in and out.
Also, you can play the hover animation on the first
node to see how both can play simultaneously.With the ghost animation ready, we can code a function that toggles the ghost effect on the character.
We will call that function from the pickup when the player collects it. The function will:
When the timer times out, we will:
Open the Godot.gd
script and reference the newly added
nodes in onready variables.
onready var animation_player_ghost := $AnimationPlayerGhost
onready var timer_ghost := $TimerGhost
We will now define a new function toggle_ghost_effect()
to toggle the ghost effect on the player.
Before we do, we will store the physics body’s collision layers and masks in a variable to restore them when the effect times out.
# We store the active collision layers and masks at the start of the game to
# later toggle them on and off using code.
var start_collision_layer := collision_layer
var start_collision_mask := collision_mask
# This function activates or deactivates the ghost effect depending on the
# `is_on` argument.
func toggle_ghost_effect(is_on: bool) -> void:
if is_on:
start()
timer_ghost.# We turn off collision detection by setting both the collision layer
# and mask to 0.
= 0
collision_layer = 0
collision_mask play("ghost")
animation_player_ghost.else:
# When turning off the effect, we restore the original collision layer
# and mask.
= start_collision_layer
collision_layer = start_collision_mask
collision_mask stop() animation_player_ghost.
Using the is_on
parameter, we can group the code in a
single function. If the value is true
, we apply the ghost
effect. Otherwise, we remove it.
To activate the effect, we’ll call the function from the ghost effect pickup’s script.
However, the Timer.timeout
signal to
our function to turn off the ghost effect.
func _ready() -> void:
# We directly connect the signal to toggle_ghost_effect, and ask Godot to
# call the function with a value of `false`.
connect("timeout", self, "toggle_ghost_effect", [false]) timer_ghost.
Now the question is, how do we call the
toggle_ghost_effect()
function when the player interacts
with the ghost pickup?
We’ll do that in the pickup’s script in the next lesson.
Open the practice Triggering an animation.
This practice serves as a recap for animating and controlling animations.
Here is the complete code for Godot.gd.
extends KinematicBody2D
const DIRECTION_TO_FRAME := {
0,
Vector2.DOWN: + Vector2.RIGHT: 1,
Vector2.DOWN 2,
Vector2.RIGHT: + Vector2.RIGHT: 3,
Vector2.UP 4,
Vector2.UP:
}
const SPEED := 700.0
var drag_factor: float = 0.13
var velocity := Vector2.ZERO
# We store the active collision layers and masks at the start of the game to
# later toggle them on and off using code.
var start_collision_layer := collision_layer
var start_collision_mask := collision_mask
onready var sprite := $Sprite
onready var animation_player_ghost := $AnimationPlayerGhost
onready var timer_ghost := $TimerGhost
func _ready() -> void:
# We directly connect the signal to toggle_ghost_effect, and ask Godot to
# call the function with a value of `false`.
connect("timeout", self, "toggle_ghost_effect", [false])
timer_ghost.
func _physics_process(delta: float) -> void:
var direction := Input.get_vector("move_left", "move_right", "move_up", "move_down")
var desired_velocity := SPEED * direction
var steering_vector := desired_velocity - velocity
+= steering_vector * drag_factor
velocity move_and_slide(velocity)
var direction_to_frame_key := direction.round()
= abs(direction_to_frame_key.x)
direction_to_frame_key.x if direction_to_frame_key in DIRECTION_TO_FRAME:
= DIRECTION_TO_FRAME[direction_to_frame_key]
sprite.frame = sign(direction.x) == -1
sprite.flip_h
# This function activates or deactivates the ghost effect depending on the
# `is_on` argument.
func toggle_ghost_effect(is_on: bool) -> void:
if is_on:
start()
timer_ghost.# We turn off collision detection by setting both the collision layer
# and mask to 0.
= 0
collision_layer = 0
collision_mask play("ghost")
animation_player_ghost.else:
# When turning off the effect, we restore the original collision layer
# and mask.
= start_collision_layer
collision_layer = start_collision_mask
collision_mask stop() animation_player_ghost.