Ce chapitre est la seconde partie du tutoriel de programmation de notre jeu de type Tower Defense avec Three.JS.
Ce tutoriel est disponible au format vidéo !
Pour bien commencer, je vous suggère de débuter par la première partie :
Introduction
Dans la partie précédente, nous avons pu créer un univers de base composé des acteurs principaux de Three.JS (camera, scène, éclairage …) et un cube au centre de la scène.
Dans cette seconde partie de notre projet, nous allons développer les fonctionnalités liées au chargement dynamique de la carte de jeu. Voici un visuel de notre objectif :
Chargement dynamique de la carte de jeu
Création du module JavaScript map.js
Commençons par créer un module JavaScript dans un nouveau fichier : map.js
. Commençons par y inclure Three.JS :
// --- map.js --- import * as THREE from '../js/build/three.module.js';
Les données de la carte de jeu
Puis, créons un objet JavaScript composé d’un Array
à deux dimensions sur l’index data
. C’est dans cette variable que sera stocké la composition de notre carte de jeu :
// ATTENTION - For this game, map width and length will be the same ! export var map0_data = { "data" : [ [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0] ] };
Notre double tableau aura ici la même longueur dans les deux dimensions !
Le mot-clé export
est utilisé pour exporter notre variable hors du module map.js
, dans index.html
.
Chaque coordonnée du double Array
de notre variable représente un bloc de notre carte de jeu :
- La valeur
0
représente une case normale. - La valeur
1
représente une case du chemin qui sera emprunté par les ennemis.
La fonction loadMap
Toujours dans le module map.js
, créons une fonction loadMap
. Cette fonction acceptera deux paramètres :
mapdata
– Une structure de données de carte ( équivalent a la variablemap0_data
).scene
– Une scène Three.JS.
export function loadMap(mapdata, scene) { [...] }
Dans le corps ce cette fonction, créons deux variables :
size_Y
– La hauteur du doubleArray
dansmapdata.data
.size_X
– La largeur du doubleArray
dans
.mapdata.data
Puis, déclarons deux objets 3D Mesh
sans les ajouter à la scène :
var size_Y = mapdata.data.length; var size_X = mapdata.data[0].length; const material = new THREE.MeshLambertMaterial({ }); const geometry = new THREE.BoxGeometry( 2, 2, 2 ); var basic_cube = new THREE.Mesh( geometry, material ); const road_material = new THREE.MeshLambertMaterial({ color : 0x2c3e50}); var road_cube = new THREE.Mesh( geometry, road_material );
Le premier cube matérialisera chaque bloc de base ( valeur 0
dans le double Array
), et le second représentera chaque bloc du chemin ( valeur 1
dans le double Array
).
Puis, créons une imbrication de deux boucles for
, pour parcourir chaque coordonnée du double Array
mapdata.data
.
for(var x = 0 ; x < size_X ; x++) { for(var y = 0 ; y < size_Y ; y++) { //code } }
Cette imbrication de structures for
, va boucler sur chaque coordonnée possible de notre carte de jeu.
Dans l’imbrication de boucles for
, créons deux variables, posx
et posy
. Ces dernières prennent pour valeur la position du bloc de carte à créer en fonction de la coordonnée couramment analysée.
Pour rappel, l’axe Y de Three.JS correspond à la hauteur. C’est pour cela que nous positionnons nos blocs sur les axes X et Z.
Ainsi :
var posx = (x*2) - (size_X/2)*2; // position x var posy = (y*2) - (size_Y/2)*2; // position y ( ATTENTION, this is the Z axis in three.js universe)
Toujours dans les boucles for
, créons une structure switch
analysant la valeur de la case aux cordonnée courantes. Deux cas sont possibles :
- Si la valeur de coordonnée courante est un
0
, nous plaçons un bloc basique dans la scène à la position (posx , 0 , posy) XYZ. - Si la valeur de coordonnée courante est un
1
, nous plaçons un bloc de chemin dans la scène à la position (posx , -0.2 , posy) XYZ.
Notons que le bloc de chemin sera placé légèrement plus bas que les blocs basiques, c’est pour cela que leur position sur l’axe Y est de -0.2
.
Pour rappel, l’axe Y de Three.JS correspond à la hauteur. C’est pour cela que nous positionnons nos blocs sur les axes X et Z.
switch(mapdata.data[y][x]) { case 0: // If [x/y] value is 0 - We are creating a basic block var tmpbloc = basic_cube.clone(); tmpbloc.position.set(posx, 0, posy); scene.add(tmpbloc); break; case 1: // If [x/y] value is 0 - We are creating a road block var tmpbloc = road_cube.clone(); tmpbloc.scale.y = 0.8; tmpbloc.position.set(posx, -0.2, posy); scene.add(tmpbloc); break; }
Notre fonction loadMap
est désormais terminée !
Utilisation de notre module map.js
dans index.html
Chargerons dès à présent ce nouveau module dans index.html
. Nous importons la variable map0_data
et la fonction loadMap
:
import {map0_data , loadMap } from './map.js';
Supprimons le cube de test ajouté à la scène dans le chapitre précédent. Puis, appelons loadMap
dans notre fonction d’initialisation init
:
function init() { [...] // ---------------- CALLING LOADING AND INIT FUNCTIONS ---------------- loadMap(map0_data, scene); // ---------------- STARTING THE GAME MAIN LOOP ---------------- render(); }
Le premier argument est map0_data
, importé de map.js
, le second est notre scène Three.JS !
Pour finir, notre caméra est un peu trop proche du centre de la scène, modifions la ligne de code créée dans le chapitre précédent :
camera.position.set(-15, 15, -15);
Résultat final
Téléchargez le code final : Github.
Félicitations, vous êtes arrivés à la fin de cette seconde partie ! Voila l’état de notre projet à l’issue de ce deuxième article :
Dans la prochaine partie, nous étudierons la capture des événements de la souris et tactiles :
[…] Créer un jeu de Tower Defense avec Three.JS – Partie 2 Étiquettesgamedevthree.jsthreejs […]
[…] August 24, 2021September 2, 2021 thomassifferlen No comments Disponible en Français […]