I. Sommaire▲
Vous pouvez retrouver les autres épisodes de cette série dans le sommaire dédié.
II. Vidéo▲
Godot Engine - Jeu de plateformes 2D - Amélioration du déplacement
III. Résumé▲
Dans cet épisode, nous allons améliorer le déplacement du joueur, lui permettre de sauter et rajouter une caméra pour le suivre.
III-A. Amélioration du déplacement▲
Pour que le code soit plus facilement compréhensible, nous allons créer une fonction move() s'occupant du déplacement du personnage. Cette fonction prend trois paramètres :
- la vitesse « speed » ;
- l'accélération « acceleration » ;
- le temps delta entre deux appels.
Le temps delta permet de connaître le temps réel écoulé entre deux appels des fonctions mettant à jour l'état du jeu. En l'utilisant, les déplacements des éléments de votre jeu auront toujours la même vitesse, quelle que soit la vitesse du PC. Pour plus de détails, suivez ce lien.
Le nouveau code résultant est le suivant :
extends RigidBody2D
export var player_speed =
200
export var acceleration =
5
var current_speed =
Vector2
(
0
,0
)
func move
(
speed, acc, delta):
current_speed.x =
lerp
(
current_speed.x, speed, acc *
delta)
set_linear_velocity
(
Vector2
(
current_speed.x, get_linear_velocity
(
).y))
func _ready
(
):
set_fixed_process
(
true)
func _fixed_process
(
delta):
var btn_right =
Input.is_action_pressed
(
"btn_right"
)
var btn_left =
Input.is_action_pressed
(
"btn_left"
)
if
btn_left:
move
(-
payer_speed, acceleration, delta)
elif
btn_right:
move
(
player_speed, acceleration, delta)
else
:
move
(
0
, acceleration, delta)
La fonction lerp() permet d'effectuer une interpolation linéaire entre deux valeurs. Ainsi, la vitesse du personnage ne passe pas de 0 à player_speed instantanément, mais suit une croissance adoucie.
Le reste du code n'est qu'une modification de ce que nous avons vu dans l'épisode précédent.
III-B. Ajouter une caméra▲
Godot propose un nœud (« Camera2D », car nous sommes dans un monde en 2D) pour intégrer une caméra. Il suffit de l'ajouter à la scène. En l'ajoutant comme enfant du joueur et en activant la propriété « Current » de la caméra, celle-ci va automatiquement suivre le joueur.
Vous pouvez ajuster la propriété « smoothing » pour rajouter un délai entre le joueur et la caméra.
III-C. Faire sauter le joueur▲
III-C-1. Idée▲
Pour savoir si le joueur est sur une plateforme et donc, qu'il a le droit de sauter, ou s'il est dans l'air et qu'il n'a donc pas le droit de sauter, nous utilisons un « lancer de rayon ». En simulant un rayon, nous pouvons déterminer si celui-ci rencontre un objet. Si nous lançons un court rayon vers le bas et qu'il rencontre un objet, nous pouvons considérer le joueur comme marchant sur une plateforme. S'il ne rencontre aucun objet, c'est qu'il n'y a que du vide sous le joueur et donc, qu'il ne peut pas sauter.
III-C-2. Implémentation▲
Dans Godot, un rayon est un nœud « RayCast2D ». Dans ses propriétés, nous devons l'activer « enabled » et augmenter sa taille afin qu'il sorte du joueur.
III-C-3. Script▲
III-C-3-a. Avoir accès à un nœud▲
Notre nœud « RayCast2D » est un enfant du « RigidBody2D » où le script est implanté. Nous devons donc récupérer un accès au nœud du lancer de rayon pour pouvoir utiliser ses fonctions. La fonction get_node() permet de récupérer un accès à un nœud spécifique en donnant le chemin menant au nœud.
III-C-3-b. Éviter de détecter la collision avec le joueur▲
Le rayon part du joueur et traverse une partie du joueur. La fonction is_colliding() va toujours retourner vrai, car le rayon va rencontrer au minimum un objet : le joueur. Pour que cela ne soit plus ainsi, il est possible d'ajouter une exception, indiquant que le rayon ne doit pas détecter la collision avec tel ou tel objet. La fonction est add_exception().
III-C-3-c. Code▲
extends RigidBody2D
export var player_speed =
200
export var jumpforce =
200
export var acceleration =
5
export var extra_gravity =
400
var raycast_down =
null
var current_speed =
Vector2
(
0
,0
)
func move
(
speed, acc, delta):
current_speed.x =
lerp
(
current_speed.x, speed, acc *
delta)
set_linear_velocity
(
Vector2
(
current_speed.x, get_linear_velocity
(
).y))
func is_on_ground
(
):
if
raycast_down.is_colliding
(
):
return
true
else
:
return
false
func _ready
(
):
raycast_down =
get_node
(
"RayCast2D"
)
raycast_down.add_exception
(
self)
set_fixed_process
(
true)
set_applied_force
(
Vector2
(
0
, extra_gravity))
func _fixed_process
(
delta):
var btn_right =
Input.is_action_pressed
(
"btn_right"
)
var btn_left =
Input.is_action_pressed
(
"btn_left"
)
var btn_jump =
Input.is_action_pressed
(
"btn_jump"
)
if
btn_left:
move
(-
payer_speed, acceleration, delta)
elif
btn_right:
move
(
player_speed, acceleration, delta)
else
:
move
(
0
, acceleration, delta)
if
is_on_ground
(
):
if
btn_jump:
set_axis_velocity
(
Vector2
(
0
, -
jumpforce))
III-C-3-d. Éviter que le joueur puisse appuyer continuellement sur le bouton de saut▲
Nous utilisons un fichier externe définissant une fonction, qui, au lieu de retourner simplement vrai ou faux suivant l'appui d'une touche, est capable de déterminer si l'appui vient d'être fait, ou s'il est relâché.
### Classe pour la gestion des entrées. Retourne quatre états.
var input_name
var prev_state
var current_state
var input
var output_state
var state_old
### Récupère le nom de l'entrée et le stocke
func _init
(
var input_name):
self.input_name =
input_name
### Vérifie l'entrée et la compare aux états précédents
func check
(
):
input =
Input.is_action_pressed
(
self.input_name)
prev_state =
current_state
current_state =
input
state_old =
output_state
if
not
prev_state and
not
current_state:
output_state =
0
### Relâché
if
not
prev_state and
current_state:
output_state =
1
### Vient d'être pressé
if
prev_state and
current_state:
output_state =
2
### Pressé
if
prev_state and
not
current_state:
output_state =
3
### Vient d'être relâché
return
output_state
Pour charger le script, vous devez utiliser la fonction preload().
Voici le code résultant de l'utilisation de input_state :
extends RigidBody2D
var input_states =
preload
(
"res://scripts/input_states.gd"
)
export var player_speed =
200
export var jumpforce =
200
export var acceleration =
5
export var extra_gravity =
400
var raycast_down =
null
var current_speed =
Vector2
(
0
,0
)
var btn_right =
input_states.new
(
"btn_right"
)
var btn_left =
input_states.new
(
"btn_left"
)
var btn_jump =
input_states.new
(
"btn_jump"
)
func move
(
speed, acc, delta):
current_speed.x =
lerp
(
current_speed.x, speed, acc *
delta)
set_linear_velocity
(
Vector2
(
current_speed.x, get_linear_velocity
(
).y))
func is_on_ground
(
):
if
raycast_down.is_colliding
(
):
return
true
else
:
return
false
func _ready
(
):
raycast_down =
get_node
(
"RayCast2D"
)
raycast_down.add_exception
(
self)
set_fixed_process
(
true)
set_applied_force
(
Vector2
(
0
, extra_gravity))
func _fixed_process
(
delta):
if
btn_left.check
(
) ==
2
:
move
(-
payer_speed, acceleration, delta)
elif
btn_right.check
(
) ==
2
:
move
(
player_speed, acceleration, delta)
else
:
move
(
0
, acceleration, delta)
if
is_on_ground
(
):
if
btn_jump.check
(
) ==
1
:
set_axis_velocity
(
Vector2
(
0
, -
jumpforce))
IV. Commenter▲
Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.