Tower Defense Three.JS

Créer un jeu de Tower Defense avec Three.JS – Partie 3 : Raycaster

Ce chapitre est la troisième partie du tutoriel de programmation de notre jeu de type Tower Defense avec Three.JS.

Tower Defense Three.JS
Notre jeu de Tower Defense

Pour bien commencer, je vous suggère de débuter par la première partie de notre tutoriel :

Ce chapitre est également disponible au format vidéo !

Introduction

Dans ce nouveau chapitre, nous allons implémenter un système de Raycaster Three.JS afin de mettre en place des événements souris ou tactiles :

Three.JS Tower Defense part 2 to 3
Un curseur Raycaster – Notre objectif

Événements souris et tactiles – Raycaster

Les variables globales

Commençons par créer quelques variables. Nous allons utiliser ces dernières pour implémenter un Raycaster.

Nous utilisons le Raycaster pour sélectionner des éléments de l’univers 3D avec la souris ou un écran tactile.

Dans le fichier index.html, créons les variables suivantes :

//Variables
[...]

// RAYCASTER
var raycaster;
var mouse 	    = new THREE.Vector2();
var clickableObjs   = new Array();

[...]

Commençons avec la variable raycaster. Elle contiendra une instance de classe Raycaster Three.JS, nous l’initialiserons dans la fonction init.

La variable mouse sera utilisée pour stocker la position du clic.

Pour finir, la structure Array clickableObjs stockera tous les éléments 3D de la scène éligibles à être ciblés par le Raycaster.

Définir certains de nos objets 3D éligibles au ciblage

Commençons par le fichier map.js, c’est dans la fonction loadMap que nous chargeons dynamiquement la carte de jeu.

Dans notre scène, nous souhaitons pouvoir sélectionner les blocs de type 0. Pour cela, ajoutons ces objets 3D à la liste clickableObjs lors de leur création dans le switch - case 0.

Il est également nécessaire de rajouter un paramètre dans la définition de loadMap, pour que nous puissions y utiliser la variable clickableObjs.

export function loadMap(mapdata, scene, clickableObjs)
{
  [...]

  case 0:
      var tmpbloc = basic_cube.clone();
      tmpbloc.position.set(posx, 0, posy);
      scene.add(tmpbloc);

      // This element is targetable by Raycaster
      clickableObjs.push(tmpbloc); 
  break;

  [...]

Désormais, tous les objets 3D de ce type sont désormais éligibles à la sélection du Raycaster.

Puis, modifions l’appel de loadMap dans index.html en conséquence :

loadMap(map0_data, scene, clickableObjs);

Créer un pointeur de souris 3D

Commençons par créer un curseur 3D pour pouvoir visualiser la position d’un clic dans notre carte de jeu.

Pour cela, dans index.html, créons une variable globale cursor_cube :

// Game objs
var cursor_cube = undefined;	// ThreeJS Mesh - RAYCASTER CURSOR

Puis, initialisons cette variable dans la fonction init :

const cursor_material = new THREE.MeshLambertMaterial({ transparent : true , opacity : 0 , color : 0xc0392b});
const cursor_geometry = new THREE.BoxGeometry( 0.5, 4, 0.5 ); // height 4
cursor_cube = new THREE.Mesh( cursor_geometry, cursor_material );
scene.add(cursor_cube);
Raycaster pointeur basique
Un curseur basique pour notre Raycaster

FacultatifIl est également possible de modéliser un curseur 3D un peu plus réaliste. Pour cela, vous pouvez utiliser le tutoriel ci-dessous pour importer un modèle 3D dans votre application :

Tower defense cursor
Un exemple de curseur pour notre jeu !

Implémenter le Raycaster Three.JS

Dans la fonction init, initialisons notre variable raycaster :

raycaster = new THREE.Raycaster();

Lorsque notre Raycaster est prêt, poursuivons avec l’implémentation des événements JavaScript.

Les événements JavaScript

Commençons par créer deux fonction JavaScript, onMouseDown et onMouseUp :

function onMouseUp(event)
{
    //code
}

function onMouseDown(event)
{
    //code
}

Puis, dans la fonction init, connectons ces deux fonctions aux événements JavaScript pointerdown et pointerup :

// ---------------- EVENTS ----------------
document.addEventListener( 'pointerdown', onMouseDown, false );
document.addEventListener( 'pointerup', onMouseUp, false );

Ainsi, la fonction onMouseDown sera appelée lorsque le clic de souris est pressé ou lorsque le doigt touche l’écran tactile, contrairement à la fonction onMouseUp, appelée lors du relâchement de la pression du clic.

Commençons par le code de onMouseDown, et capturons les coordonnées du clic dans notre variable mouse :

function onMouseDown(event)
{    
    event.preventDefault();
    mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

}

Puis, utilisons notre Raycaster pour détecter si des objets de la liste clickableObjs sont ciblés :

function onMouseDown(event)
{
    [...]

    // Checking if the mouse projection is targeting a valid block in the clickableObjs array
    raycaster.setFromCamera( mouse, camera );
    var intersects = raycaster.intersectObjects( clickableObjs ); // get the list of targetable objects currently intersecting with raycaster

}

Si au moins un élément de clickableObjs est ciblé par la trajectoire du Raycaster, nous nous baserons sur le premier élément détecté pour y déplacer le pointeur 3D :

if ( intersects.length > 0 ) // If there is a match mouse/block (if the array is not empty)
{
  var SelectedBloc = intersects[ 0 ].object; // we choose the first targetable element
  cursor_cube.position.set(SelectedBloc.position.x, SelectedBloc.position.y, SelectedBloc.position.z);
  cursor_cube.material.opacity = 0.5;
  cursor_cube.material.emissive.g = 0.5;
}

Dans ce cas, définissons également l’opacité de notre pointeur sur 0.5 et donnons lui une couleur verte.

Mais, si aucun élément de la liste clickableObjs est ciblé, nous cachons le pointeur :

else // no valid block is targeted
{
  cursor_cube.material.opacity = 0;
}

Nous avons terminé la fonction onMouseDown !

Puis, dans le corps de la fonction onMouseUp, réinitialisons la couleur de notre pointeur :

function onMouseUp(event)
{
  cursor_cube.material.emissive.g = 0;
}

Résultat final

Téléchargez le code final : Github.

Félicitations, vous êtes arrivés à la fin de cette troisième partie ! Nous sommes désormais capables de cibler certains éléments de notre carte de jeu grâce a un clic !

Raycaster Pointer three.JS
Notre curseur cubique basique

Ou, si vous avez opté pour l’option d’importer un curseur 3D depuis un fichier externe :

Notre Raycaster en action !

Dans la prochaine partie, nous programmerons la création dynamique d’objets ( de tours) dans notre scène grâce au Raycaster !

Un commentaire

Les commentaires sont fermés.