Work in progress
The content of this page was not yet updated for Godot
4.2
and may be outdated. If you know how to improve this page or you can confirm
that it's up to date, feel free to open a pull request.
Générer des monstres¶
Dans cette partie, nous allons faire apparaître des monstres aléatoirement le long d'un chemin. D'ici la fin, vous aurez des monstres qui parcourront le plateau de jeu.
Double-click on main.tscn
in the FileSystem dock to open the Main
scene.
Before drawing the path, we're going to change the game resolution. Our game has
a default window size of 1152x648
. We're going to set it to 720x540
, a
nice little box.
Allez dans Projet -> Paramètres du projet.
Dans le menu de gauche, naviguez jusqu'à Display -> Window. À droite, mettez la Width à 720
et la Height à 540
.
Création du chemin d'apparition¶
Like you did in the 2D game tutorial, you're going to design a path and use a PathFollow3D node to sample random locations on it.
Cependant, en 3D, c'est un peu plus compliqué de dessiner le chemin. Nous voulons qu'il soit autour de la vue du jeu pour que les monstres apparaissent à l'extérieur de l'écran. Mais si nous traçons un chemin, nous ne le verrons pas dans l'aperçu de la caméra.
Pour trouver les limites de la vue, nous pouvons utiliser des modèles temporaires. Votre fenêtre d'affichage devrait toujours être divisée en deux parties, avec l'aperçu de la caméra en bas. Si ce n'est pas le cas, appuyez sur Ctrl + 2 (Cmd + 2 sur MacOS) pour diviser la vue en deux. Sélectionnez le nœud Camera3D et cochez la case Aperçu dans la vue du bas.
Ajout de cylindres génériques¶
Let's add the placeholder meshes. Add a new Node3D as a child of the
Main
node and name it Cylinders
. We'll use it to group the cylinders. Select Cylinders
and add a child node MeshInstance3D
Dans l'Inspecteur, assignez un CylinderMesh à la propriété Mesh.
Définissez la vue du haut sur la vue de dessus orthogonale en utilisant le menu dans le coin supérieur gauche de la fenêtre d'affichage. Vous pouvez également appuyer sur la touche 7 du pavé numérique.
The grid may be distracting. You can toggle it by going to the View menu in the toolbar and clicking View Grid.
Vous voulez maintenant déplacer le cylindre le long du plan du sol, en regardant l'aperçu dans la vue du bas. Je recommande d'utiliser l'accrochage à la grille pour ce faire. Vous pouvez l'activer en cliquant sur l'icône d'aimant dans la barre d'outils ou en appuyant sur Y.
Move the cylinder so it's right outside the camera's view in the top-left corner.
Nous allons créer des copies du maillage et les placer autour de la zone de jeu. Appuyez sur Ctrl + D (Cmd + D sur MacOS) pour dupliquer le nœud. Vous pouvez également faire un clic droit sur le nœud dans le dock Scène et sélectionner Dupliquer. Déplacez la copie vers le bas le long de l'axe Z bleu jusqu'à ce qu'elle soit juste en dehors de l'aperçu de la caméra.
Sélectionnez les deux cylindres en maintenant la touche Shift et en cliquant sur celui qui n'est pas sélectionné, et dupliquez-les.
Déplacez-les vers la droite en faisant glisser l'axe X rouge.
Ils sont un peu difficiles à voir en blanc, n'est-ce pas ? Faisons-les ressortir en leur donnant un nouveau matériau.
En 3D, les matériaux définissent les propriétés visuelles d'une surface, comme sa couleur, comment elle reflète la lumière, etc. Nous pouvons les utiliser pour modifier la couleur d'un modèle.
Nous pouvons mettre à jour les quatre cylindres en même temps. Sélectionnez toutes les instances de modèles dans le dock Scène. Pour ce faire, vous pouvez cliquer sur la première et faire un shift-clic sur la dernière.
In the Inspector, expand the Material section and assign a StandardMaterial3D to slot 0.
Cliquez sur l'icône de sphère pour ouvrir la ressource du matériau. Vous obtenez un aperçu du matériau et une longue liste de sections remplies de propriétés. Vous pouvez les utiliser pour créer toutes sortes de surfaces, allant du métal jusqu'à la roche ou l'eau.
Expand the Albedo section.
Set the color to something that contrasts with the background, like a bright orange.
Nous pouvons maintenant utiliser les cylindres comme des guides. Repliez-les dans le dock Scène en cliquant sur la flèche grise à côté d'eux. À l'avenir, vous pourrez également modifier leur visibilité en cliquant sur l'icône d'œil à côté de Cylinders.
Add a child node Path3D to Main
node. In the toolbar, four icons appear. Click
the Add Point tool, the icon with the green "+" sign.
Note
Vous pouvez survoler n'importe quelle icône pour voir une info-bulle décrivant l'outil.
Cliquez au centre de chaque cylindre pour créer un point. Ensuite, cliquez sur l'icône Fermer la courbe dans la barre d'outils pour fermer le chemin. Si un point est un peu décalé, vous pouvez le glisser pour le repositionner.
Votre chemin devrait ressembler à ceci.
To sample random positions on it, we need a PathFollow3D node. Add a
PathFollow3D as a child of the Path3D
. Rename the two nodes to SpawnPath
and
SpawnLocation
, respectively. It's more descriptive of what we'll use them for.
Avec ça, nous sommes prêts à coder le mécanisme d'apparition.
Faire apparaître des monstres au hasard¶
Right-click on the Main
node and attach a new script to it.
We first export a variable to the Inspector so that we can assign mob.tscn
or any other monster to it.
extends Node
@export var mob_scene: PackedScene
using Godot;
public partial class Main : Node
{
// Don't forget to rebuild the project so the editor knows about the new export variable.
[Export]
public PackedScene MobScene { get; set; }
}
We want to spawn mobs at regular time intervals. To do this, we need to go back
to the scene and add a timer. Before that, though, we need to assign the
mob.tscn
file to the mob_scene
property above (otherwise it's null!)
Head back to the 3D screen and select the Main
node. Drag mob.tscn
from
the FileSystem dock to the Mob Scene slot in the Inspector.
Add a new Timer node as a child of Main
. Name it MobTimer
.
Dans l'Inspecteur, réglez son Wait Time à 0.5
secondes et activez l'Autostart pour qu'il commence automatiquement au lancement du jeu.
Les timers émettent un signal timeout
à chaque fois qu'ils atteignent la fin de leur Wait Time. Par défaut, ils redémarrent automatiquement, en émettant le signal dans un cycle. Nous pouvons nous connecter à ce signal depuis le nœud Main pour faire apparaître des monstres toutes les 0.5
secondes.
With the MobTimer still selected, head to the Node dock on the right, and
double-click the timeout
signal.
Connectez-le au noeud Main.
This will take you back to the script, with a new empty
_on_mob_timer_timeout()
function.
Codons la logique d'apparition des mobs. Nous allons :
Instancier la scène du mob.
Échantillonner une position aléatoire sur le chemin d'apparition.
Récupérer la position du joueur.
Appeler la méthode
initialize()
du mob, en lui passant la position aléatoire et la position du joueur.Ajouter le mob comme enfant du nœud Main.
func _on_mob_timer_timeout():
# Create a new instance of the Mob scene.
var mob = mob_scene.instantiate()
# Choose a random location on the SpawnPath.
# We store the reference to the SpawnLocation node.
var mob_spawn_location = get_node("SpawnPath/SpawnLocation")
# And give it a random offset.
mob_spawn_location.progress_ratio = randf()
var player_position = $Player.position
mob.initialize(mob_spawn_location.position, player_position)
# Spawn the mob by adding it to the Main scene.
add_child(mob)
// We also specified this function name in PascalCase in the editor's connection window
private void OnMobTimerTimeout()
{
// Create a new instance of the Mob scene.
Mob mob = MobScene.Instantiate<Mob>();
// Choose a random location on the SpawnPath.
// We store the reference to the SpawnLocation node.
var mobSpawnLocation = GetNode<PathFollow3D>("SpawnPath/SpawnLocation");
// And give it a random offset.
mobSpawnLocation.ProgressRatio = GD.Randf();
Vector3 playerPosition = GetNode<Player>("Player").Position;
mob.Initialize(mobSpawnLocation.Position, playerPosition);
// Spawn the mob by adding it to the Main scene.
AddChild(mob);
}
Above, randf()
produces a random value between 0
and 1
, which is
what the PathFollow node's progress_ratio
expects:
0 is the start of the path, 1 is the end of the path.
The path we have set is around the camera's viewport, so any random value between 0 and 1
is a random position alongside the edges of the viewport!
Here is the complete main.gd
script so far, for reference.
extends Node
@export var mob_scene: PackedScene
func _on_mob_timer_timeout():
# Create a new instance of the Mob scene.
var mob = mob_scene.instantiate()
# Choose a random location on the SpawnPath.
# We store the reference to the SpawnLocation node.
var mob_spawn_location = get_node("SpawnPath/SpawnLocation")
# And give it a random offset.
mob_spawn_location.progress_ratio = randf()
var player_position = $Player.position
mob.initialize(mob_spawn_location.position, player_position)
# Spawn the mob by adding it to the Main scene.
add_child(mob)
using Godot;
public partial class Main : Node
{
[Export]
public PackedScene MobScene { get; set; }
private void OnMobTimerTimeout()
{
// Create a new instance of the Mob scene.
Mob mob = MobScene.Instantiate<Mob>();
// Choose a random location on the SpawnPath.
// We store the reference to the SpawnLocation node.
var mobSpawnLocation = GetNode<PathFollow3D>("SpawnPath/SpawnLocation");
// And give it a random offset.
mobSpawnLocation.ProgressRatio = GD.Randf();
Vector3 playerPosition = GetNode<Player>("Player").Position;
mob.Initialize(mobSpawnLocation.Position, playerPosition);
// Spawn the mob by adding it to the Main scene.
AddChild(mob);
}
}
Vous pouvez tester la scène en appuyant sur F6. Vous devriez voir les monstres apparaître et se déplacer en ligne droite.
Pour l'instant, ils se heurtent et glissent les uns contre les autres lorsque leurs chemins se croisent. Nous aborderons ce problème dans la prochaine partie.