Tower Defense Three.JS

Créer un jeu de Tower Defense avec Three.JS – Partie 1 : Les bases

Avant de commencer ce grand projet, si vous êtes encore débutants avec Three.JS, je vous conseille fortement de maîtriser les concepts de base expliqués dans notre parcours de formation :

Si vous êtes prêts, commençons !

Introduction et présentation du projet

Dans ce grand tutoriel, nous allons développer ensemble, étapes par étapes, un jeu de type Tower Defense avec Three.JS !

Le Tower Defense (souvent abrégée en TD) est un type de jeu vidéo où l’objectif est de défendre une zone contre des vagues successives d’ennemis se déplaçant suivant un itinéraire ou non, en construisant et en améliorant progressivement des tours défensives.

Wikipédia

Ainsi, dans un monde au style 3D orthographique, nous développerons un univers composé d’une route de foret, qui devra être défendue de vagues d’ennemis par des tours.

Le but du jeu sera d’empêcher les ennemis d’arriver au bout du chemin.

Tower Defense Three.JS
Notre jeu de Tower Defense

Ce tutoriel est disponible au format vidéo !

Lors des différentes phases de développement, nous aborderons les thèmes suivants :

  • Bases de Three.JS
  • Chargement de modèles 3D
  • Animation de modèles 3D
  • Raycaster
  • Programmation orientée objet et JavaScript de base

Création d’un univers de base

Commençons la première étape de notre projet ! Créons un fichier index.html :

<head>
  	<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' />

  	<style>
    
      body
      {
        margin: 0; touch-action: none;
        background-image: -webkit-gradient(linear, 0 0, 100% 100%, color-stop(0, #877fa8), color-stop(100%, #f9ae91));
        background-image: -webkit-linear-gradient(135deg, #877fa8, #f9ae91);
        background-image: -moz-linear-gradient(45deg, #877fa8, #f9ae91);
        background-image: -ms-linear-gradient(45deg, #877fa8 0, #f9ae91 100%);
        background-image: -o-linear-gradient(45deg, #877fa8, #f9ae91);
        background-image: linear-gradient(135deg, #877fa8, #f9ae91);
      }
      
  		canvas { width: 100%; height: 100% ; touch-action: none;}
  	</style>

  	<script  type="module"></script>
</head>

<body>
</body>

Puis, dans cette base de code, attaquons le concret dans la balise script !

Commençons par importer Three.JS et MapControls dans notre projet et créons quelques variables :

<script  type="module">
  
    import * as THREE from '../js/build/three.module.js';
    import { MapControls } from '../js/examples/jsm/controls/OrbitControls.js';

    // Basic Threejs variables
    var scene;
    var camera;
    var renderer;
    var clock;
    var controls;

[...]

Puis, créons une fonction init. Cette dernière sera appelée à la fin de notre code JavaScript, ce sera le point d’entrée de notre projet :

<script  type="module">
[...]

function init()
{

}

init();
</script>

Dans cette fonction, nous initialiserons les variables précédemment crées ainsi que les bases de notre univers Three.JS.

Les acteurs de base

Pour rappel, n’hésitez pas a vous rafraîchir la mémoire sur les concepts de base de Three.JS :

Commençons par les variables clock et scene, respectivement de type Clock et Scene :

function init()
{

  clock = new THREE.Clock();
  scene = new THREE.Scene();

}

Ensuite, notre moteur de rendu 3D renderer , de type WebGLRenderer.
Toujours dans la fonction init :

// ---------------- RENDERER ----------------
renderer = new THREE.WebGLRenderer( { antialias : true ,  alpha: true} );
renderer.setPixelRatio( window.devicePixelRatio  );
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );  // we add the HTML element to the HTML page

Poursuivons avec l’initialisation de la variable camera. Dans ce projet nous utiliserons OrthographicCamera :

// ---------------- CAMERA ----------------
const aspect = window.innerWidth / window.innerHeight;
const frustumSize = 10;
camera = new THREE.OrthographicCamera( frustumSize * aspect / - 2, frustumSize * aspect / 2, frustumSize / 2, frustumSize / - 2, 1, 1000 );

camera.position.set( -5, 5, -5 );
camera.lookAt(new THREE.Vector3(0,0,0));
scene.add( camera );

Contrôler la caméra

Puis, initialisons une instance de MapControls pour contrôler la camera. Pour rappel, MapControls est une classe des add-on officiels de Three.JS :

// ---------------- CAMERA CONTROLS ----------------
controls = new MapControls( camera, renderer.domElement );

controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false;
controls.minDistance = 2;
controls.maxDistance = 20;
controls.maxPolarAngle = Math.PI / 2;

Si vous souhaitez plus d’informations sur le contrôle de camera de base :

Nos variables de base sont enfin initialisées ! Occupons nous désormais de remplir notre scène.

L’éclairage de la scène

Commençons par l’éclairage de notre scène. Comme vous le savez, l’éclairage de la scène est la plupart du temps indispensable pour que les objets 3D y soient visibles.

Toujours dans notre fonction init :

// ---------------- LIGHTS ----------------
var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.2 );
scene.add( ambientLight );

const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.6 );
directionalLight.position.set( - 1, 0.9, 0.4 );
scene.add( directionalLight );

Un cube au centre de la scène

Poursuivons le code de notre fonction init avec la création d’un cube au centre de la scène :

var cube;

[...]

const material = new THREE.MeshLambertMaterial();
const geometry = new THREE.BoxGeometry( 2, 2, 2 );
cube = new THREE.Mesh( geometry, material );
scene.add( cube );

La boucle principale d’animation

Pour finir, occupons nous de la boucle principale d’animation. Créons une fonction render basique :

function render()
{
    var delta = clock.getDelta();			//get delta time between two frames
    var elapsed = clock.elapsedTime;	//get elapsed time


    controls.update(); // only required if controls.enableDamping = true, or if controls.autoRotate = true
    renderer.render( scene, camera ); 	// We are rendering the 3D world
    requestAnimationFrame( render );	// we are calling render() again,  to loop
}

N’oubliez pas d’appeler render à la fin de notre fonction init pour démarrer la boucle principale :

function init()
{
    [...]

    // ---------------- STARTING THE GAME MAIN LOOP ----------------
    render();
}

Résultat final

Téléchargez le code final : Github

Félicitations, vous êtes arrivés à la fin de cette première partie ! Voila l’état de notre projet à l’issue de ce premier article :

Three.JS Orthographic Cube
Tower Defense – Partie 1

Dans la prochaine partie, nous étudierons comment implémenter les fonctionnalités liées à la carte de jeu, restez connectés !

(4 commentaires)

Les commentaires sont fermés.