Mis à jour le jeudi 31 août 2017
  • 20 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

Vous pouvez obtenir un certificat de réussite à l'issue de ce cours.

J'ai tout compris !

Programmez des bonus en jeu

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Nous sommes proches d'avoir un FPS fonctionnel et complet ! Il nous manque encore une étape pour que le gameplay de base soit terminé : les bonus en jeu. Que ce soit pour donner des munitions, des armes ou des ressources pour regagner de la vie, ils sont essentiels pour que les joueurs puissent rester sur le champ de bataille suffisamment longtemps !

Accrochez-vous, c'est notre dernier obstacle de tout le cours : la suite sera bien plus légère ! ;)

Préparer le jeu à recevoir les props

Depuis le début de la création de notre scène, il y a un fichier qui ne change pas d'un iota… Arena.js. Je me suis dit qu'il devait se sentir un peu seul, alors qu'est-ce que vous diriez de le retrouver pour la durée de ce chapitre ? ^^ 

Mais avant cela, il nous faut préparer le jeu ! D'abord, nous allons devoir préparer Armory.js en lui donnant une nouvelle catégorie : bonuses. Dans le fichier Armory.js, nous allons donc ajouter à la suite du tableau weapons le tableau suivant.

this.bonuses=[
    {
        'name': 'mHealth', 
        'message' : 'Gros pack de santé',
        'type':'health',
        'value': 75
    },
    {
        'name':'lHealth',
        'message' : 'Petit pack de santé',
        'type':'health',
        'value': 20
    },
    {
        'name' : 'lArmor',
        'message' : 'Petit pack d\'armure',
        'type':'armor',
        'value': 20
    }
];

Vous pourrez ajouter d'autres objets comme ceux-ci plus tard. Pour l'instant, allez voir  Arena.js  : nous allons nous concentrer sur la création des objets.

Créer les modèles physique des props

Dans l'ordre, nous allons créer les fonctions d'ajout de props suivant : les bonus en jeu (armure, santé), les armes, puis les munitions. Mettons-nous y tout de suite ! 

En premier lieu, vous allez créer le modèle de prototype. Tout ce que nous allons faire ensuite est créé dedans. :) 

Arena.prototype = {

}

newBonuses

Notre première fonction va gérer la création des bonus selon la position renseignée son type, armure ou vie. Les paramètres seront tous les mêmes pour l'instant, mais je vous recommande si vous voulez créer un vrai FPS de les rendre reconnaissables. Un joueur se sentira frustré s'il confond deux objets. ^^

Dans le Arena.prototype, nous allons donc écrire le code suivant.

newBonuses : function(position,type) {
    var typeBonus = type;
    var positionBonus = position;
    
    // On crée un cube
    var newBonus = BABYLON.Mesh.CreateBox("bonusItem",  2, this.game.scene);
    newBonus.scaling = new BABYLON.Vector3(1,1,1);
    
    // On lui donne la couleur orange
    newBonus.material = new BABYLON.StandardMaterial("textureItem", this.game.scene);
    newBonus.material.diffuseColor = new BABYLON.Color3((255/255), (138/255), (51/255));

    // On positionne l'objet selon la position envoyée
    newBonus.position = positionBonus;
    
    // On le rend impossible à être séléctionné par les raycast
    newBonus.isPickable = false;
    
     // On affecte à l'objet son type
    newBonus.typeBonus = typeBonus;

    return newBonus;
},

Le code est relativement simple, il n'y a aucune nouvelle notion ici. Notez bien le isPickable = false qui permet d'éviter qu'on puisse sélectionner les objets avec les rayons que nous traçons tout au long du jeu. On retourne l'objet créé pour le réutiliser ensuite.

newWeaponSet

newWeaponSet possède une forme similaire à newBonuses avec scaling comme seule différence.

newWeaponSet : function(position,type) {
    var typeWeapons = type;
    var positionWeapon = position;

    var newSetWeapon = BABYLON.Mesh.CreateBox(this.Armory.weapons[typeWeapons].name, 1, this.game.scene);
    newSetWeapon.scaling = new BABYLON.Vector3(1,0.7,2);


    newSetWeapon.material = new BABYLON.StandardMaterial("weaponMat", this.game.scene);
    newSetWeapon.material.diffuseColor = this.Armory.weapons[typeWeapons].setup.colorMesh;
    newSetWeapon.position = positionWeapon;
    newSetWeapon.isPickable = false;
    newSetWeapon.typeWeapon = type;

    return newSetWeapon;
},

scaling permet à cet objet d'avoir une forme qui ressemble à une arme. Encore une fois, si vous voulez sortir un jeu de type FPS, il vaut mieux avoir un modèle d'arme reconnaissable. 

newAmmo

Le code est encore une fois très similaire… Pour tout dire, il n'a aucune différence avec le précédent. :p 

newAmmo : function(position,type) {
    var typeAmmos = type;
    var positionAmmo = position;
    var newAmmo = BABYLON.Mesh.CreateBox(this.game.armory.weapons[typeAmmos].name, 1.0, this.game.scene);
    newAmmo.position = positionAmmo;
    newAmmo.isPickable = false;
    newAmmo.material = new BABYLON.StandardMaterial("ammoMat", this.game.scene);
    newAmmo.material.diffuseColor = this.game.armory.weapons[typeAmmos].setup.colorMesh;
    newAmmo.typeAmmo = type;

    return newAmmo;
},

Pour l'instant, nos fonctions sont prêtes, mais rien ne les apelle ! Vous allez donc voir comment appeller les objets depuis le serveur.

Génerer les objets depuis le serveur

Si vous allez dans le fichier server.js, vous pourrez voir bonusBoxesweaponBoxes et ammosBoxes. Avec ces trois tableaux, vous avez la position et le type de chaque objet. Et le plus magique, c'est que quand vous appelez Game dans NetworkManager, il vous suffit de récupérer le deuxième paramètre pour avoir la liste ! C'est pas beau, ça ? ^^ 

Dans Game, vous avez donc deux éléments en plus :

// On récupère props en plus
Game = function(canvasId,playerConfig,props) {
    
    -------------------- DEFINITION DES VARIABLES -------------------
    
    -----------------------------------------------------------------
    
    // On envoie props à Arena
    var _arena = new Arena(_this,props);
----------------------------- SUITE DE GAME -------------------------

On appelle donc props en plus et on l'envoie à Arena. Maintenant que vous avez tous les objets à générer, il faut les traiter ! Allez dans l'objet Arena et ajoutez à la fin de celui-ci :

// Liste des objets stockés dans le jeu
this.bonusBox=[];
this.weaponBox=[];
this.ammosBox=[];

// Les props envoyés par le serveur
this.bonusServer = props[0];
this.weaponServer = props[1];
this.ammosServer = props[2];

for (var i = 0; i < this.bonusServer.length; i++) {
    // Si l'objet n'a pas été pris par un joueur
    if(this.bonusServer[i].v === 1){
        var newBonusBox = this.newBonuses(new BABYLON.Vector3(
            this.bonusServer[i].x,
            this.bonusServer[i].y,
            this.bonusServer[i].z),
        this.bonusServer[i].t);
        
        newBonusBox.idServer = i;
        this.bonusBox.push(newBonusBox);
    }
}

for (var i = 0; i < this.weaponServer.length; i++) {
    if(this.weaponServer[i].v === 1){
        var newWeaponBox = this.newWeaponSet(new BABYLON.Vector3(
            this.weaponServer[i].x,
            this.weaponServer[i].y,
            this.weaponServer[i].z),
        this.weaponServer[i].t);
        
        newWeaponBox.idServer = i;
        this.weaponBox.push(newWeaponBox);
    }
}

for (var i = 0; i < this.ammosServer.length; i++) {
    if(this.ammosServer[i].v === 1){
        var newAmmoBox = this.newAmmo(new BABYLON.Vector3(
            this.ammosServer[i].x,
            this.ammosServer[i].y,
            this.ammosServer[i].z),
        this.ammosServer[i].t);
        
        newAmmoBox.idServer = i;
        this.ammosBox.push(newAmmoBox);
    }
}

Beaucoup de code, mais pas mal de redondances. Détaillons cela pas à pas :

  • On crée trois tableaux, qui vont stocker tous les objets dans la scène.

  • On récupère tous les props envoyés par Game.

  • On fait trois boucles for qui vérifient si l'objet existe (la valeur v stockée dans server sera une valeur qui va changer si un joueur prend un bonus, pour que tous voient la même chose).

  • Si l'objet existe, on le crée en donnant la position du bonus renvoyée par le serveur, ainsi que son type.

  • On donne à cet objet un idServer pour le distinguer des autres quand un de ces objets disparaîtra de la map.

  • On envoie l'objet dans son tableau assigné.

Et ainsi, on crée et ajoute tous les objets. Maintenant qu'ils existent, nous allons interagir avec eux ! :) 

Modifier le joueur selon les bonus

Le joueur ne réagit pas pour l'instant face aux objets. Il est temps de lui donner la possibilité de récupérer les bonus que nous avons créés pour lui ! 

Premièrement, nous allons créer une fonction dans Arena qu'on va nommer _checkProps. Cette fonction sera appelée à chaque frame depuis runRenderLoop dans Game

// On check les props
this._ArenaData._checkProps();

Avec cette fonction appelée à chaque frame, nous allons simplement vérifier la distance entre le joueur et les objets. Si cette distance est inférieure à une certaine valeur, l'objet est considéré comme récupéré. Dans Arena, nous ajoutons désormais :

_checkProps : function(){
    // Pour les bonus
    for (var i = 0; i < this.bonusBox.length; i++) {
        // On vérifie si la distance est inférieure à 6
        if(BABYLON.Vector3.Distance(
            this.game._PlayerData.camera.playerBox.position,
            this.bonusBox[i].position)<6){
            var paramsBonus = this.Armory.bonuses[this.bonusBox[i].typeBonus];
            
            // On supprime l'objet
            this.bonusBox[i].dispose();
            this.bonusBox.splice(i,1)
        }
        
    }
    for (var i = 0; i < this.weaponBox.length; i++) {
        // Pour les armes
        if(BABYLON.Vector3.Distance(
            this.game._PlayerData.camera.playerBox.position,
            this.weaponBox[i].position)<6){
            var Weapons = this.game._PlayerData.camera.weapons;
            var paramsWeapon = this.Armory.weapons[this.weaponBox[i].typeWeapon];
            
            this.weaponBox[i].dispose();
            this.weaponBox.splice(i,1);
            
        }
    }
    for (var i = 0; i < this.ammosBox.length; i++) {
        // Pour les munitions
        if(BABYLON.Vector3.Distance(
            this.game._PlayerData.camera.playerBox.position,
            this.ammosBox[i].position)<6){
            
            var paramsAmmos = this.Armory.weapons[this.ammosBox[i].typeAmmo].setup.ammos;
            var Weapons = this.game._PlayerData.camera.weapons;

            this.ammosBox[i].dispose();
            this.ammosBox.splice(i,1)
        }
        
    }
},

Comme au-dessus, vous pouvez voir que le code se compose de trois parties similaires mais distinctes. Chacune gère pour l'instant son contenu de la même façon. Nous allons apporter des modifications relativement importantes qui vont rendre chaque boucle unique.

givePlayerBonus

Ajoutez une simple ligne dans la première boucle (dédiée au bonus de vie et d'armure) :

this.game._PlayerData.givePlayerBonus(paramsBonus.type,paramsBonus.value);

Vous l'avez compris, nous allons créer une fonction dans Player qui va gérer le changement d'état au niveau vie et armure pour le joueur.

// Donner un bonus au joueur
givePlayerBonus : function(what,howMany) {
    
    var typeBonus = what;
    var amountBonus = howMany;
    if(typeBonus === 'health'){
        if(this.camera.health + amountBonus>100){
            this.camera.health = 100;
        }else{
            this.camera.health += amountBonus;
        }
    }else if (typeBonus === 'armor'){
        if(this.camera.armor + amountBonus>100){
            this.camera.armor = 100;
        }else{
            this.camera.armor += amountBonus;
        }
    } 
    this.textHealth.innerText = this.camera.health;
    this.textArmor.innerText = this.camera.armor;
},
  • typeBonus nous donne des informations quant au type de bonus envoyé. Pour l'instant, nous gérons seulement deux cas : armor et health.

  • amountBonus nous donne la quantité de bonus envoyé.

Nous vérifions si le joueur n'a pas déjà le maximum en termes de vie et d'armure, puis nous lui ajoutons ce qu'il vient de récupérer. En dernier lieu, nous actualisons l'affichage de vie et d'armure avec les nouvelles valeurs.

Appel de newWeapon depuis Arena

Quand le joueur passe sur une arme, nous avons plusieurs choses à faire : 

  • Vérifier s'il n'a pas déjà l'arme

  • S'il l'a déjà, ne pas faire disparaître le bonus

  • S'il ne l'a pas déjà, lui donner

Voici comment composer l'intérieur de la boucle for et du if consacré à weaponBox dans _checkProps :

var Weapons = this.game._PlayerData.camera.weapons;
var paramsWeapon = this.Armory.weapons[this.weaponBox[i].typeWeapon];
var notPiked = true;
for (var y = 0; y < Weapons.inventory.length; y++) {
    if(Weapons.inventory[y].typeWeapon == this.weaponBox[i].typeWeapon){
        notPiked = false;
        break;
    }
}
if(notPiked){

    var actualInventoryWeapon = Weapons.inventory[Weapons.actualWeapon];
    
    var newWeapon = Weapons.newWeapon(paramsWeapon.name);
    Weapons.inventory.push(newWeapon);

    // On réinitialise la position de l'arme précédente animée
    actualInventoryWeapon.position = actualInventoryWeapon.basePosition.clone();
    actualInventoryWeapon.rotation = actualInventoryWeapon.baseRotation.clone();
    Weapons._animationDelta = 0;

    actualInventoryWeapon.isActive = false;

    Weapons.actualWeapon = Weapons.inventory.length -1;
    actualInventoryWeapon = Weapons.inventory[Weapons.actualWeapon];
    
    actualInventoryWeapon.isActive = true;

    Weapons.fireRate = Weapons.Armory.weapons[actualInventoryWeapon.typeWeapon].setup.cadency;
    Weapons._deltaFireRate = Weapons.fireRate;

    this.weaponBox[i].dispose();
    this.weaponBox.splice(i,1);
}

On part du postulat de base que l'arme n'a pas été prise. Ensuite, on fait un tour de boucle dans les armes actuellement stockées par le player. Si l'arme devant laquelle le joueur se trouve a le même type que l'une des armes présentes dans son inventaire, on définit notPicked à true.

Si par contre la boucle n'a rien trouvé, on ajoute l'arme à l'inventaire du joueur. On la crée avec notre fonction newWeapon présente dans Weapons. Après cela, on fait comme quand on change d'arme : on réinitialise toutes les variables inhérentes au fonctionnement et aux animations de l'arme.

Avec cela, vous avez des armes qui s'ajoutent proprement dans votre inventaire. :)

reloadWeapon

De la même façon  que pour les bonus, nous allons gérer les munitions dans un autre fichier : Weapons.js. Juste avant cela, appelez cette fonction dans la boucle for de ammosBox :

var paramsAmmos = this.Armory.weapons[this.ammosBox[i].typeAmmo].setup.ammos;
var Weapons = this.game._PlayerData.camera.weapons;

Weapons.reloadWeapon(this.ammosBox[i].typeAmmo, paramsAmmos.refuel);

this.ammosBox[i].dispose();
this.ammosBox.splice(i,1)

Maintenant, vous allez mettre Arena.js de côté pour quelques temps car nous allons devoir effectuer un certain nombre de modifications à Weapons.js : il nous faut gérer les munitions !

Ajouter le système de munitions dans Weapons.js

Tout d’abord, vous allez préparer les armes à recevoir des munitions en leur définissant des munitions dans newWeapon :

if(this.Armory.weapons[i].setup.ammos){
    newWeapon.ammos = this.Armory.weapons[i].setup.ammos.baseAmmos;
}

En ajoutant ces lignes, on vérifie si l'arme possède des munitions. Si c'est le cas, elles seront stockées dans l'objet. Sinon (ce cas s'applique pour les armes de corps-à-corps), on ne met pas la variable ammos.

Maintenant que les armes sont prêtes, on doit limiter le tir ! Si le joueur n'a plus de munitions, il faut l’empêcher de tirer. Nous allons vérifier cela à deux endroits : dans la boucle registerBeforeRender pour l'animation et dans launchFire pour le tir.

registerBeforeRender

Dans la boucle, nous allons rendre l'animation possible seulement si l'arme est chargée ou qu'elle n'a pas de munitions : 

Player.game.scene.registerBeforeRender(function() {
    if (!_this.canFire) {
    	// On vérifie si l'arme est chargée ou n'a pas de munitions
		if(_this.inventory[_this.actualWeapon].ammos == undefined || (
			_this.inventory[_this.actualWeapon].ammos && 
			_this.inventory[_this.actualWeapon].ammos>0)){
        	// On anime l'arme actuelle
        	_this.animateMovementWeapon(_this._animationDelta); 
        }
        // On augmente animationDelta
        _this._animationDelta += engine.getDeltaTime();
        _this._deltaFireRate -= engine.getDeltaTime();

        if (_this._deltaFireRate <= 0 && _this.Player.isAlive) {
            // Quand on a fini l'animation, on replace l'arme à sa position initiale
            _this.inventory[_this.actualWeapon].position = 
            _this.inventory[_this.actualWeapon].basePosition.clone();
            _this.inventory[_this.actualWeapon].rotation = 
            _this.inventory[_this.actualWeapon].baseRotation.clone();
            
            _this.canFire = true;
            _this._deltaFireRate = _this.fireRate;
            
            // Quand on peut tirer, on repasse animationDelta à 0
            _this._animationDelta = 0;
        }
    }
});

Avec cette condition, l'arme ne s’animera que s'il reste des munitions. ^^ 

launchFire

Nous allons devoir, là aussi, vérifier si l'arme est chargée. Pour cela, une nouvelle condition if suffira :

if (this.canFire) {
    var idWeapon = this.inventory[this.actualWeapon].typeWeapon;
    var weaponAmmos = this.inventory[this.actualWeapon].ammos;
    var renderWidth = this.Player.game.engine.getRenderWidth(true);
    var renderHeight = this.Player.game.engine.getRenderHeight(true);
    var direction = this.Player.game.scene.pick(renderWidth/2,renderHeight/2);
    
    // Si l'arme est une arme de distance
    if(this.Armory.weapons[idWeapon].type === 'ranged'){
        if(weaponAmmos>0){
            // ---------------------------------
            // CODE DEJA PRESENT DANS RANGED
            // ---------------------------------
            
            this.inventory[this.actualWeapon].ammos--;
        } 
    }
------------------------ RESTE DE LAUNCHFIRE -------------------------

On ne met le if que dans ranged. Nous ne vérifions donc pas pour les armes de corps-à-corps. À la fin de ranged, on indique aussi ammos-- : cela va servir à diminuer les munitions dès que le joueur aura tiré. Ainsi, le stock de nos munitions descend désormais.

Munitions : sac temporaire et gestion des munitions

Notre arme est presque prête à être rechargée par des munitions supplémentaires. Il nous reste une dernière chose à voir en termes de gameplay.

En effet, que se passe-t-il si un joueur amasse des munitions alors qu'il n'a pas encore d'arme ? Depuis un petit moment, dans les jeux tels que Quake ou Unreal Tournament, vous pouvez amasser des munitions pour des armes que vous n'avez pas. Les munitions seront ajoutées à l'arme quand vous la débloquerez. C'est ce que nous allons faire ici aussi !  ;) 

Pour cela, nous allons ajouter un sac temporaire de munitions qui se remplira tout au long de la vie du joueur. Ce sac sera créé dans l'objet Weapons, juste en dessous de inventory.

// Sac de munitions temporaire, tant que l'arme n'est pas possédée
this.tempAmmosBag = [];

Maintenant que vous avez ce sac de munitions, vous devez lui dire d'influer sur les munitions de base du joueur. Dans newWeapon, modifiez la ligne que nous avions ajoutée quelques minutes plus tôt, et qui s'occupe de définir le nombre de munitions :

if(this.Armory.weapons[i].setup.ammos){
    newWeapon.ammos = this.Armory.weapons[i].setup.ammos.baseAmmos;
    // S'il y a des munitions supplémentaires dans le sac à munitions
    if(this.tempAmmosBag[i]){
        newWeapon.ammos += this.tempAmmosBag[i];
        // Si les munitions dépassent le maximum, on les fait revenir à une valeur normale
        if(newWeapon.ammos > this.Armory.weapons[i].setup.ammos.maximum){
            newWeapon.ammos = this.Armory.weapons[i].setup.ammos.maximum;
        }
    }
}

Nous voilà avec un sac de munitions temporaire qui n'attend que d'être rempli ! Revenons à nos moutons désormais : il est plus que temps de la créer, cette fonction reloadWeapon. :) 

reloadWeapon

La fonction est relativement simple au niveau schématique : si on récupère des munitions, elle vérifie si l'arme compatible avec ces munitions existe. Si l'arme existe, elle va augmenter les munitions de l'arme directement. Sinon, elle va remplir le tempAmmoBag en attendant que l'arme soit créée.

reloadWeapon : function(type,numberAmmos) {
    var ammoHud = document.getElementById('ammosValue');
    var existingWeapon = false;
    // On part du principe que l'arme n'existe pas
    for (var i = 0; i < this.inventory.length; i++) {
        if(this.inventory[i].typeWeapon === type){
            // Si l'arme existe, on lui donne les munitions
            var existingWeapon = true;
            if((this.inventory[i].ammos + numberAmmos) > 
            this.Armory.weapons[i].setup.ammos.maximum){
                this.inventory[i].ammos = this.Armory.weapons[i].setup.ammos.maximum
            }else{
                this.inventory[i].ammos += numberAmmos;
            }
            break;
        }
    }
    // Si l'arme n'existe pas, on ajoute les munitions au sac de munitions
    if(!existingWeapon){
        
        if(!this.tempAmmosBag[type]){
            this.tempAmmosBag[type]=0;
        }
        if((this.tempAmmosBag[type] + numberAmmos) > 
        this.Armory.weapons[type].setup.ammos.maximum){
            this.tempAmmosBag[type] = this.Armory.weapons[type].setup.ammos.maximum;
        }else{
            this.tempAmmosBag[type] += numberAmmos;
        }
    }     
},

Grâce à ces lignes, les armes ont désormais des munitions et ne peuvent tirer que quand elles en possèdent. Nous avons créé tous les types de munitions ! Il vous reste à voir une dernière chose dans ce chapitre : la gestion du réseau.

Le serveur et les props

Les objets sont actuellement créés une seule fois et supprimés localement. Il nous faut cependant les supprimer sur toutes les machines et leur dire de se recréer après un certain laps de temps. C'est ce que vous allez faire maintenant !

Envoyer la suppression d'un objet

Si le joueur a récupéré un objet, il faut prévenir le serveur. Pour cela, voici une fonction simple qu'il faut ajouter dans toutes les boucles for de _checkProps dans Arena.js : pickableDestroyed. Voici les lignes que vous devez ajouter juste avant les dispose() et splice() respectifs.

// Pour bonusBox
this.pickableDestroyed(this.bonusBox[i].idServer,'bonus');

// Pour weaponBox
this.pickableDestroyed(this.weaponBox[i].idServer, 'weapon');

// Pour ammosBox
this.pickableDestroyed(this.ammosBox[i].idServer, 'ammos');

Définissez la fonction ainsi, dans prototype :

// Partie Server
pickableDestroyed : function(idServer,type) {
    destroyPropsToServer(idServer,type)
},

Ainsi, vous signifiez au serveur que ces objets ont été pris.

Recevoir l'ordre de supprimer un objet

À l'inverse, si le serveur reçoit l'ordre d'effacer un objet, il faut lui indiquer l'id de l'objet à supprimer, puis relancer la fonction adéquate. NetworkManager nous envoie déjà les données au bon moment dans la fonction deletePropFromServer :

deletePropFromServer : function(deletedProp){
    // idServer est l'id de l'arme
    var idServer = deletedProp[0];
    
    // type nous permet de déterminer ce qu'est l'objet
    var type = deletedProp[1];
    switch (type){
        case 'ammos' :
            for (var i = 0; i < this.ammosBox.length; i++) {
                if(this.ammosBox[i].idServer === idServer){
                    this.ammosBox[i].dispose();
                    this.ammosBox.splice(i,1);
                    break;
                }
            }
            
        break;
        case 'bonus' :
            for (var i = 0; i < this.bonusBox.length; i++) {
                if(this.bonusBox[i].idServer === idServer){
                    this.bonusBox[i].dispose();
                    this.bonusBox.splice(i,1);
                    break;
                }
            }
        break;
        case 'weapon' :
            for (var i = 0; i < this.bonusBox.length; i++) {
                if(this.weaponBox[i].idServer === idServer){
                    this.weaponBox[i].dispose();
                    this.weaponBox.splice(i,1);
                    break;
                }
            }
        break;
    }
},

Toutes les boucles for nous permettent de connaître l'objet exact à effacer. Quand nous l'avons trouvé, nous le supprimons simplement de la liste des objets. ^^

Recevoir l'ordre de re-créer l'objet

Pour éviter les tricheries, c'est le serveur qui gère la re-création des props. Il envoie donc a un instant précis un message à NetworkManager avec les instruction de re-création. Ces informations sont alors envoyées à recreatePropFromServer. Cette fonction a une forme extrêmement simple :

recreatePropFromServer : function(recreatedProp){
    var idServer = recreatedProp[0];
    var type = recreatedProp[1];
    switch (type){
        case 'ammos' :
            var newAmmoBox = this.newAmmo(new BABYLON.Vector3(
                this.ammosServer[idServer].x,
                this.ammosServer[idServer].y,
                this.ammosServer[idServer].z),
                this.ammosServer[idServer].t);
            
            newAmmoBox.idServer = idServer;
            this.ammosBox.push(newAmmoBox);
        break;
        case 'bonus' :
            var newBonusBox = this.newBonuses(new BABYLON.Vector3(
                this.bonusServer[idServer].x,
                this.bonusServer[idServer].y,
                this.bonusServer[idServer].z),
                this.bonusServer[idServer].t);
                
            newBonusBox.idServer = idServer;
            this.bonusBox.push(newBonusBox);
        break;
        case 'weapon' :
            var newWeaponBox = this.newWeaponSet(new BABYLON.Vector3(
                this.weaponServer[idServer].x,
                this.weaponServer[idServer].y,
                this.weaponServer[idServer].z),
                this.weaponServer[idServer].t);
                
            newWeaponBox.idServer = idServer;
            this.weaponBox.push(newWeaponBox);
        break;
    }
},

Comme pour deletePropFromServer, on détermine l'action à effectuer selon le type (munition, bonus, arme). Quand l'objet est créé, on l'envoie à la liste correspondante pour que l'objet puisse être traité par _checkInputs.

Il vous faut maintenant réactiver les deux derniers socket.on dans le fichier NetworkManager.

socket.on ('deleteProps', function (deleteProp) {
    game._ArenaData.deletePropFromServer(deleteProp)
});
socket.on ('recreateProps', function (createdProp) {
    game._ArenaData.recreatePropFromServer(createdProp)
});

Les objets sont maintenant créés et affichés ! Si vous testez avec un ami, vous pourrez constater la disparition dynamique des objets. Magique !

  

Nous avons officiellement passé le dernier chapitre un peu ardu ! Nous pouvons désormais nous amuser avec des fonctions plus secondaires et faire le jeu tout beau pour sa sortie ! Vous êtes prêt à ajouter un annonceur de multi-kill ? Eh bien rendez-vous au prochain chapitre ! :p ‌

Exemple de certificat de réussite
Exemple de certificat de réussite