Création du jeu "Like coins" sur Godot Engine. Partie 1

Godot Engine se développe très rapidement et gagne le cœur des développeurs de jeux du monde entier. C'est peut-être l'outil le plus convivial et le plus facile à apprendre pour créer des jeux, et pour vous en assurer, essayez de faire un petit jeu 2D. Pour une bonne compréhension du processus de développement de jeux, vous devriez commencer par les jeux 2D - cela abaissera le seuil d'entrée dans un système de jeu plus sérieux. Bien que la transition vers la 3D en elle-même ne soit pas aussi difficile qu'il y paraît, après tout, la plupart des fonctions du moteur Godot peuvent être utilisées avec succès en 2D et en 3D.


Présentation


La chose la plus simple à laquelle vous pouvez penser est un jeu dans lequel notre personnage principal collectera des pièces. Pour compliquer un peu, ajoutez un obstacle et du temps, comme facteur limitant. Le jeu aura 3 scènes: Player , Coin et HUD (cet article n'est pas considéré), qui seront combinées en une seule scène Main .



Paramètres du projet


Avant de vous lancer dans l'écriture de scripts (scripts), ce qui représente environ 80 à 90% du temps total consacré à la création du jeu, la première chose à faire est de configurer notre futur projet. Dans les grands projets, il est utile de créer des dossiers séparés pour stocker des scripts, des scènes, des images et des sons, et nous devons certainement en tenir compte, car qui sait quel sera le résultat final.


Je veux tout de suite faire une réserve que cet article suppose que vous êtes un peu familier avec le moteur Godot et que vous avez des connaissances et des compétences pour utiliser cet outil, bien que je me concentre sur le fait que vous rencontrez le moteur Godot pour la première fois, je suis toujours Je vous conseille d'abord de vous familiariser avec le composant de base du moteur, d'étudier la syntaxe de GDScript et de comprendre la terminologie utilisée (nœuds, scènes, signaux, etc.), puis de revenir ici et de continuer votre connaissance.

Dans le menu du programme, accédez à Project -> Project Settings .


Encore une petite digression. Je donnerai toujours des exemples basés sur le fait que l'utilisateur final utilise l'interface en langue anglaise du moteur, malgré le fait que le "moteur Godot" prend en charge la langue russe. Ceci est fait afin de se débarrasser des éventuels malentendus ou embarras associés à une traduction incorrecte / inexacte de certains éléments de l'interface du programme.

Recherchez la section Display/Window et définissez la largeur sur 800 et la hauteur sur 600 . Toujours dans cette section, définissez Stretch/Mode sur 2D et Aspect à Keep . Cela empêchera l'étirement et la déformation du contenu de la fenêtre lors du changement de sa taille, mais pour empêcher la fenêtre d'être redimensionnée, décochez simplement la case Resizable . Je vous conseille de jouer avec ces options.


Accédez maintenant à la section Rendering/Quality et activez l' Use Pixel Snap dans le volet droit. À quoi ça sert? Les coordonnées des vecteurs dans le moteur Godot sont des nombres à virgule flottante. Étant donné que les objets ne peuvent être dessinés que d'un demi-pixel, cette différence peut entraîner des défauts visuels pour les jeux qui utilisent pixelart . Et il convient de noter qu'en 3D, cette option est inutile. Gardez cela à l'esprit.


Scène de joueur


Commençons par créer la première scène - Player .


L'avantage de n'importe quelle scène est qu'initialement, elles sont indépendantes des autres parties du jeu, ce qui permet de les tester librement et d'obtenir le résultat qui y était initialement prévu. En général, la division d'objets de jeu en scènes est un outil utile pour créer des jeux complexes - il est plus facile de détecter les erreurs, d'apporter des modifications à la scène elle-même, tandis que d'autres parties du jeu ne seront pas affectées, elles peuvent également servir de modèles pour d'autres jeux et elles fonctionneront certainement aussi bien. comme ils travaillaient avant le transfert.

La création d'une scène est une action trivialement simple - sur l'onglet Scene , cliquez sur + (Ajouter / Créer) et sélectionnez le nœud Area2D et changez immédiatement son nom afin de ne pas vous tromper. Il s'agit de notre nœud parent et pour étendre les fonctionnalités dont vous avez besoin pour ajouter des nœuds enfants. Dans notre cas, ce sont AnimatedSprite et CollisionShape2D , mais ne nous précipitons pas, mais commençons dans l'ordre. Ensuite, «verrouillez» immédiatement le nœud racine:



Si la forme de collision corporelle (CollisionShape2D) ou l'image-objet (AnimatedSprite) sont décalées, étirées par rapport au nœud parent, cela entraînera certainement des erreurs imprévues et plus tard il sera difficile de les corriger. Lorsque cette option est activée, le «parent» et tous ses «enfants» se déplaceront toujours ensemble. Cela semble drôle, mais l'utilisation de cette fonctionnalité est extrêmement utile.


AnimatedSprite


Area2D nœud très utile si vous avez besoin de connaître un événement de chevauchement avec d'autres objets ou de leur collision, mais en soi, il est invisible à l'œil nu et pour rendre visible l'objet Player ajoutez AnimatedSprite . Le nom du nœud nous dit que nous allons traiter des animations et des sprites. Dans la fenêtre Inspector , accédez au paramètre Frames et créez un nouveau SpriteFrames . Travailler avec le panneau SpriteFrames consiste à créer les animations nécessaires et à leur charger les sprites correspondants. Nous n'analyserons pas en détail toutes les étapes de la création d'animations, laissant cela pour une étude indépendante, je dirai seulement que nous devrions avoir trois animations: walk (animation de marche), idle (état de repos) et die (animation de mort ou d'échec). N'oubliez pas que la valeur de SPEED (FPS) doit être 8 (bien que vous puissiez choisir une valeur différente - appropriée).



Collisionshape2d


Pour que Area2D détecte les collisions, vous devez lui fournir la forme d'un objet. Les formes sont déterminées par le paramètre Shape2D et incluent des rectangles, des cercles, des polygones et d'autres types de formes plus complexes, et les tailles sont déjà modifiées dans l'éditeur lui-même, mais vous pouvez toujours utiliser l' Inspector pour un réglage plus précis.


Scénarios


Maintenant, afin de «faire revivre» notre objet de jeu, vous devez définir un script pour celui-ci, selon lequel les actions définies par nous, qui sont prescrites dans ce scénario, seront exécutées. Dans l'onglet Scene , créez un script, laissez les paramètres par défaut, supprimez tous les commentaires (lignes commençant par le signe «#») et procédez à la déclaration des variables:


 export (int) var speed var velocity = Vector2() var window_size = Vector2(800, 600) 

L'utilisation du mot-clé d' export vous permet de définir la valeur de la variable de speed dans la fenêtre du panneau Inspector . Il s'agit d'une méthode très utile si nous voulons obtenir des valeurs personnalisées qui sont faciles à modifier dans la fenêtre Inspector . Réglez la Speed sur 350 . La valeur de velocity déterminera la direction du mouvement, et window_size est la zone limitant le mouvement du joueur.


L'ordre supplémentaire de nos actions est le suivant: nous utilisons la fonction get_input() pour vérifier si la saisie au clavier est en cours. Ensuite, nous déplacerons l'objet, en fonction des touches enfoncées, puis jouerons l'animation. Le joueur se déplacera dans quatre directions. Par défaut, le moteur Godot a des événements attribués aux touches fléchées ( Project -> Project Settings -> Input Map ), nous pouvons donc les appliquer à notre projet. Pour savoir si une touche particulière est enfoncée, vous devez utiliser Input.is_action_pressed() en lui glissant le nom de l'événement que vous souhaitez suivre.


 func get_input(): velocity = Vector2() if Input.is_action_pressed("ui_left"): velocity.x -= 1 if Input.is_action_pressed("ui_right"): velocity.x += 1 if Input.is_action_pressed("ui_up"): velocity.y -= 1 if Input.is_action_pressed("ui_down"): velocity.y += 1 if velocity.length() > 0: velocity = velocity.normalized() * speed 

À première vue, tout semble bien, mais il y a une petite nuance. La combinaison de plusieurs touches enfoncées (par exemple, vers le bas et vers la gauche) provoquera l'ajout de vecteurs et dans ce cas, le joueur se déplacera plus rapidement que s'il se déplaçait simplement vers le bas. Pour éviter cela, nous utiliserons la méthode normalized() - elle retournera la longueur du vecteur à 1 .


Ainsi, les événements de frappe ont été suivis, vous devez maintenant déplacer l'objet Player . La fonction _process() nous aidera à cela, qui est appelée chaque fois qu'un changement de trame se produit, il est donc conseillé de l'utiliser pour les objets qui changent souvent.


 func _process(delta): get_input() position += velocity * delta position.x = clamp(position.x, 0, window_size.x) position.y = clamp(position.y, 0, window_size.y) 

J'espère que vous remarquerez le paramètre delta , qui à son tour est multiplié par la vitesse. Il faut expliquer ce que c'est. Le moteur de jeu est initialement configuré pour fonctionner à une vitesse de 60 images par seconde. Néanmoins, il peut y avoir des situations où l'ordinateur ou le moteur Godot lui-même ralentit. Si la fréquence d'images n'est pas cohérente (le temps nécessaire pour que les images changent), cela affectera la "fluidité" du mouvement des objets du jeu (par conséquent, le mouvement est "saccadé"). "Godot Engine" résout ce problème (comme la plupart des moteurs similaires) en introduisant la variable delta - elle donne la valeur pour laquelle les images ont été modifiées. Grâce à ces valeurs, vous pouvez "aligner" le mouvement. Faites attention à une autre fonction remarquable - clamp (renvoie la valeur dans les deux paramètres spécifiés), grâce à elle, nous sommes en mesure de limiter la zone que le Player peut déplacer en définissant simplement la valeur minimale et maximale de la zone.


N'oubliez pas d'animer notre objet. Veuillez noter que lorsque l'objet se déplace vers la droite, vous devez retourner AnimatedSprite (en utilisant flip_h ) et notre héros regardera dans la direction où il se déplace directement lors du déplacement. Assurez-vous que dans AnimatedSprite le paramètre Playing est activé afin que l'animation commence à jouer.


 if velocity.length() > 0: $AnimatedSprite.animation = "walk" $AnimatedSprite.flip_h = velocity.x < 0 else: $AnimatedSprite.animation = "idle" 

Naissance et décès


Lors du lancement du jeu, la scène principale doit être informée des scènes clés sur son état de préparation pour démarrer un nouveau jeu, dans notre cas, nous devons informer l'objet Player du début du jeu et définir les paramètres initiaux pour celui-ci: position d'apparence, animation par défaut, exécuter set_process .


 func start(pos): set_process(true) #     Vector2(x, y) position = pos $AnimatedSprite.animation = "idle" 

Nous fournissons également un événement de mort d'un joueur lorsque le temps est écoulé ou que le joueur rencontre un obstacle, et la définition de set_process (false) empêchera la fonction _process () d'être exécutée pour cette scène.


 func die(): $AnimatedSprite.animation = "die" set_process(false) 

Ajout de collisions


C'était au tour de faire détecter au joueur des collisions avec des pièces et des obstacles. Ceci est plus facilement mis en œuvre en utilisant des signaux. Les signaux sont un excellent moyen d'envoyer un message afin que d'autres nœuds puissent les détecter et répondre. La plupart des nœuds ont déjà des signaux intégrés, mais il est possible de définir des signaux "utilisateur" à leurs propres fins. Des signaux sont ajoutés si vous les déclarez au début du script:


 signal pickup signal die 

Parcourez la liste des signaux dans la fenêtre Inspector (onglet Node ) et faites attention à nos signaux et aux signaux qui existent déjà. Maintenant, nous sommes intéressés par area_entered () , il suppose que les objets avec lesquels la collision se produira sont également de type Area2D . Nous connectons le signal area_entered () à l'aide du bouton Connect , et dans la fenêtre Connect Signal sélectionnez le nœud en surbrillance (Player), laissez le reste par défaut.


 func _on_Player_area_entered( area ): if area.is_in_group("coins"): #  emit_signal("pickup") area.pickup() 

Pour que les objets puissent être facilement détectés et interagis avec eux, ils doivent être identifiés dans les groupes appropriés. La création des groupes eux-mêmes est désormais omise, mais nous y reviendrons certainement plus tard. La fonction pickup() détermine le comportement de la pièce (par exemple, elle peut jouer une animation ou un son, supprimer un objet, etc.).


Scène de pièces


Lors de la création d'une scène avec une pièce, vous devez faire tout ce que nous avons fait avec la scène "Player", sauf qu'il n'y aura qu'une seule animation (surbrillance) dans AnimatedSprite . Speed (FPS) peut être augmentée à 14 . Nous allons également modifier l'échelle de AnimatedSprite - 0,5, 0,5 . Et les dimensions de CollisionShape2D devraient correspondre à l'image de la pièce, l'essentiel n'est pas de la mettre à l'échelle, à savoir changer la taille en utilisant les marqueurs appropriés sur le formulaire dans l'éditeur 2D, qui
ajuste le rayon du cercle.



Les groupes sont une sorte d'étiquetage des nœuds qui vous permet d'identifier des nœuds similaires. Pour que l'objet Player réagisse au toucher avec des pièces, les pièces doivent appartenir au groupe, appelons-les coins . Sélectionnez le nœud Area2D (avec le nom "Coin") et affectez-lui une balise dans l'onglet Node -> Groups , créant le groupe correspondant.



Pour le nœud Coin , créez un script. La fonction pickup() sera appelée par le script de l'objet Player et indiquera à la pièce quoi faire lorsqu'elle fonctionne. La méthode queue_free() supprimera en toute sécurité un nœud de l'arborescence avec tous ses nœuds enfants et effacera la mémoire, mais la suppression ne fonctionnera pas immédiatement, elle sera d'abord déplacée vers la file d'attente à supprimer à la fin de la trame actuelle. C'est beaucoup plus sûr que de supprimer un nœud immédiatement, car d'autres "participants" (nœuds ou scènes) du jeu peuvent encore avoir besoin de ce nœud pour exister.


 func pickup (): queue_free () 

Conclusion


Maintenant, nous pouvons créer la scène Main , faites glisser les deux scènes: Player et Coin souris dans l'éditeur 2D, et vérifiez comment le mouvement du joueur et son contact avec la pièce fonctionnent en démarrant la scène (F5). Eh bien, je suis pressé de dire que la première partie de la création du jeu "Like Coins" est terminée, laissez-moi prendre un congé et remercier tout le monde pour leur attention. Si vous avez quelque chose à dire, complétez le matériel ou si vous avez vu des erreurs dans l'article, assurez-vous de le signaler en écrivant un commentaire ci-dessous. N'ayez pas peur d'être dur et critique. Vos «commentaires» vous diront si je vais dans la bonne direction et ce qui peut être corrigé pour rendre le matériel encore plus intéressant et utile.

Source: https://habr.com/ru/post/fr429234/


All Articles