Créer son premier jeu 2D avec Godot 3

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Jeremy Bullock nous présente comment créer son premier jeu, en 2D, avec le moteur de jeux Godot 3. Ainsi, au cours de ce tutoriel, vous apprendrez à créer un jeu dans lequel le joueur peut cliquer sur des soucoupes volantes visibles à l'écran. Si le joueur clique à côté d'une soucoupe, il a perdu. Le jeu contient toutes les fonctionnalités que l'on peut attendre d'un jeu :

  • graphismes ;
  • sons ;
  • musique ;
  • système de score ;
  • condition de perte.

II. Vidéos


Votre premier jeu dans Godot 3



Votre premier jeu dans Godot 3


III. Résumé

III-A. Création du projet

Godot 3 est un moteur de jeux vidéo 2D et 3D, gratuit et open source. Vous pouvez le télécharger ici.
Lorsque vous démarrez le moteur de jeux vidéo, une liste de projets s'affiche. Pour ce projet, vous allez créer un « Nouveau Projet » (« New Project »), que vous nommerez « UFO ». Afin d'avoir un dossier spécifique à votre projet, vous pouvez cliquer sur « Créer dossier » (« Create folder ») avant de valider la fenêtre de création de projet.

Une fois le projet ouvert, vous arrivez sur l'éditeur 3D. Pour passer en mode 2D, cliquez sur le bouton « 2D », en haut de la fenêtre.

Pour ce projet, vous avez besoin de quelques fichiers (les ressources graphiques et sonores) disponibles ici. Décompressez l'archive et glissez/déposez les fichiers dans Godot (dans l'explorateur de ressources, par défaut en bas à gauche).

III-B. Création de la soucoupe volante

Créez un nouvel objet de type Area2D dans la hiérarchie de la scène (par défaut, en haut à droite).
Dans Godot, tous les éléments sont des nœuds possédant des propriétés et des enfants. Ici, cet Area2D sera un conteneur pour le Sprite de la soucoupe volante et le reste des éléments de gameplay de cette soucoupe.
Ajoutez un nœud de type Sprite, enfant de l'Area2D. Puis glissez le fichier ufoGreen.png dans la propriété « Texture ».
Il est nécessaire que la soucoupe volante puisse détecter les collisions. Pour ajouter cet aspect, vous devez ajouter le nœud CollisionShape2D, enfant de Area2D (et donc au même niveau que le nœud de type Sprite).

Le nœud CollisionShape2D apporte une « consistance physique » à l'objet (permettant de détecter les collisions) tout comme le nœud Sprite apporte une « consistance graphique » (permettant d'afficher l'objet à l'écran).

Le nœud CollisionShape2D ne possède pas de forme et vous devez donc définir celle-ci grâce à la propriété « Shape ». Ici, nous utilisons un « CircleShape2D ». Par défaut, la forme ne correspond pas au sprite. Vous devez donc redimensionner la forme (grâce aux points sur le côté du cercle).

La forme de collision est légèrement plus grande que le sprite afin de rendre le jeu plus facile, mais aussi de ne pas avoir des joueurs pensant avoir cliqué sur le sprite alors qu'ils étaient légèrement à côté.

Le nœud « Area2D » est renommé en « UFO ».

C'est une bonne idée de renommer les nœuds afin de mieux comprendre leur but (ce qu'ils font dans le jeu) et de rendre le code des scripts plus clair.

Finalement, sauvegardez la scène.

Dans Godot, une scène est constituée de plusieurs nœuds qui formeront un objet « indépendant » à utiliser dans votre jeu. Ainsi, ici, si vous souhaitez importer votre scène UFO dans un autre jeu, c'est possible.

III-C. Fonctionnement de la soucoupe volante

La soucoupe volante doit se déplacer sur l'écran. Pour cela, nous allons ajouter un nœud « Script » enfant du nœud « UFO ». Le langage de script de Godot est appelé « GDScript ». Le langage est similaire au Python.

 
Sélectionnez
extends Area2D

var speed = 100
var direction = Vector2()

var width
var height

func _ready():
    position = get_viewport_rect().size / 2
    direction.x = rand_range(-1, 1)
    direction.y = rand_range(-1, 1)
    direction = direction.normalized()

    width = get_viewport_rect().size.x
    height = get_viewport_rect().size.y

Le script a une fonction _ready() qui est appelée lorsque le nœud (et tous ses enfants) est prêt dans la scène.

Sachant que nous souhaitons que la soucoupe se déplace, nous allons définir une vitesse, une direction de déplacement et une position de départ.
La direction est sélectionnée aléatoirement, puis normalisée afin de s'assurer que la direction a toujours la même longueur (et donc, que la soucoupe a une vitesse uniforme quelle que soit la direction générée). La position de départ est placée au centre de l'écran.
Enfin, on mémorise la taille de la fenêtre afin de pouvoir implémenter le rebond de la soucoupe sur les bords de la fenêtre.

Ensuite, nous implémentons le déplacement de la soucoupe, dans la fonction _process(). La fonction _process() est appelée à intervalles réguliers. La variable delta permet de connaître le temps écoulé depuis le dernier appel à la fonction _process(). Ainsi, il est important d'utiliser la variable delta lors de l'implémentation du mouvement, sans quoi, suivant les aléas de l'ordinateur, le jeu sera saccadé et incohérent pour le joueur.

 
Sélectionnez
func _process(delta):
    position += direction * speed * delta 
    if position.x < 0:
        direction.x = -direction.x
    if position.x > width:
        direction.x = -direction.x
    if position.y < 0:
        direction.y = -direction.y
    if position.y > height:
        direction.y = -direction.y

Après la mise à jour de la position, on met à jour la direction, si la soucoupe a touché un des bords de la fenêtre.

On remarque un petit défaut dans cette méthode. En effet, la soucoupe dépasse le bord de l'écran avant de rebondir. La variable position représente le milieu de la soucoupe. Tant que le milieu de la soucoupe ne dépasse pas la fenêtre, le rebond n'est pas détecté. Pour corriger cela, il faut prendre en compte la taille de la soucoupe.

III-D. Gestion du clic

Chaque nœud possède un ensemble de signaux. Les signaux représentent une action de l'utilisateur (ou un événement), effectuée sur ce nœud, tel un clic de souris ou une collision. Ici, nous souhaitons utiliser le signal input_event() pour lequel nous connectons la fonction suivante :

 
Sélectionnez
_on_UFO_input_event(viewport, event, shape_idx):
    if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.pressed:
        direction.x = rand_range(-1, 1)
        direction.y = rand_range(-1, 1)
        direction = direction.normalized()
        position.x =  rand_range(1, width - 1)
        position.y =  rand_range(1, height - 1)
        speed += 5

Ainsi, la fonction sera appelée à chaque fois que le signal input_event() se produira, donc, à chaque fois que l'utilisateur cliquera sur une soucoupe volante.

La première étape est de vérifier si l'événement est un appui sur le bouton de la souris et que ce bouton est bien le bouton gauche. Si tel est le cas, nous produisons une nouvelle position et une nouvelle direction aléatoires et la vitesse de la soucoupe est augmentée.

III-E. Intégration dans la scène du jeu

Dans une nouvelle scène, créez un nœud Node2D et un Sprite enfant. Ce dernier servira pour afficher l'image de fond du jeu.
Ensuite, ajoutez la scène de la soucoupe, comme enfant du nœud Node2D.

La soucoupe n'est pas visible. En effet, Godot utilise l'ordre des nœuds pour gérer l'ordre d'affichage. En mettant le nœud de la soucoupe après le nœud du fond, la soucoupe est affichée après le fond et sera donc visible.

Finalement, le nœud Node2D est renommé en « Main ».

III-E-1. Lancement du jeu

Maintenant, il ne suffit plus de tester un simple nœud (grâce au raccourci F6), vous pouvez tester tout le jeu (grâce au raccourci F5). Godot vous demandera quelle est la scène principale et vous devez donc lui spécifier la scène « Main ».

III-F. Condition de fin de partie

Pour implémenter la condition de fin de partie, vous devez ajouter un nœud Area2D, enfant du nœud « Main » et un nœud CollisionShape2D enfant du nœud Area2D nouvellement créé. Ce dernier doit couvrir l'intégralité du fond.

Lorsque vous voulez déplacer votre forme de collision, vous devez déplacer le nœud Area2D le contenant, et non la forme de collision. Aussi, vous avez le bouton Bouton pour empécher la sélection d'un noeud enfant permettant d'éviter la sélection du nœud enfant par inadvertance.

Encore une fois, nous devons connecter le signal input_event() à une fonction afin de détecter que le joueur clique hors d'une soucoupe volante (clic sur le fond). Toutefois, pour implémenter une telle fonction, il nous faut un script qui accueillera le code. Créez un nouveau script, pour le nœud « Main ».

Voici le code de la fonction :

Main.gd
Sélectionnez
_on_UFO_input_event(viewport, event, shape_idx):
    if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.pressed:
        hit = true

Nous avons aussi besoin de modifier le code de la fonction _process :

Main.gd
Sélectionnez
var hit = false

func _process(delta):
    if !$UFO.hit == true and hit == true:
        print("lose")
        $UFO.lose = true
    $UFO.hit = false
    hit = false

Finalement, les variables suivantes ont été ajoutées au script UFO.gd :

 
Sélectionnez
var hit = false
var lose = false
var clicks = 0

Celles-ci sont modifiées dans la fonction de détection des clics :

 
Sélectionnez
_on_UFO_input_event(viewport, event, shape_idx):
    if lose:
        return
    if event is InputEventMouseButton and event.button_index == BUTTON_LEFT and event.pressed:
        direction.x = rand_range(-1, 1)
        direction.y = rand_range(-1, 1)
        direction = direction.normalized()
        position.x =  rand_range(1, width - 1)
        position.y =  rand_range(1, height - 1)
        speed += 5
        hit = true

La fonction _process() du script Main.gd permet de vérifier si le joueur a cliqué sur la soucoupe ou s'il a cliqué sur le fond et uniquement sur ce dernier. Dans tous les cas, les variables hit de la soucoupe et du script principal sont réinitialisées à « false ».

III-G. Ajout du son

Ajoutez un nœud AudioStreamPlayer2D enfant du nœud de la soucoupe. Le nœud est renommé « HitSound ». Pour jouer du son, vous devez ajouter la ligne :

 
Sélectionnez
$HitSound.play()

à la fin de la fonction de détection du clic sur la soucoupe. Ensuite, vous devez placer le son à jouer dans la propriété « Stream » du nœud « HitSound ».

III-H. Ajout de la musique

Le procédé est similaire pour ajouter de la musique. Ajoutez un nœud « AudioStreamPlayer2D » au nœud « Main », définissez la musique à jouer grâce à la propriété « Stream » et cochez la propriété « Autoplay ».

III-I. Afficher du texte

Ajoutez un nœud Label au nœud « Main ». Renommez le nouveau nœud « ClicksLabel ». Modifiez sa propriété « Text » en « Clicks: 0 ». Sa valeur sera modifiée à travers le code. Personnalisez la police et la couleur grâce aux autres propriétés. Vous pouvez utiliser un fichier TTF grâce à l'assignation d'une DynamicFont.

Un deuxième nœud Label est ajouté au nœud « Main » pour le texte de fin de partie. Il est renommé « LoseLabel ». De même que pour le premier texte, vous pouvez lui assigner une police, une taille et une couleur. Déplacez-le au centre de l'écran.

Il ne reste plus qu'à écrire le code pour mettre à jour le compteur de clics et afficher ou non le texte de fin de partie. Cela se fait dans le fichier Main.gd :

 
Sélectionnez
func _ready():
    $LoseLabel.hide() # Cache le texte de fin de partie au commencement de la partie

func _process(delta):
    if !$UFO.hit == true and hit == true:
        print("lose")
        $UFO.lose = true
        $LoseLabel.show()
    if $UFO.hit == true: # Mise a jour du compteur de clics
        $UFO.clicks += 1
        $ClicksLabel.text = "Clicks: " + str($UFO.clicks)
    $UFO.hit = false
    hit = false

IV. Conclusion

Félicitations, vous avez créé votre premier jeu dans le moteur de jeux Godot. Pour continuer, n'hésitez pas à expérimenter et à jouer avec les fonctionnalités du moteur, ni à vous plonger dans la documentation officielle. Évidemment, il vous est possible de poser vos questions sur le forum de Developpez.com.

V. Commenter

Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2018 La rubrique 2D/3D/Jeux. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.