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 !

Animez les armes

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

Bienvenue dans la quatrième et dernière partie de ce cours ! 

Vous avez désormais un FPS jouable et entièrement paramétrable. Mais diantre, il nous manque encore un peu de gameplay et quelques éléments de jeu !

On commence tout de suite par nous occuper de l'effet visuel des armes qui tirent. Montrer au joueur qu'il a tiré est essentiel pour les feedbacks de jeu. Cela ne devrait pas énormément modifier la structure et ce chapitre devrait donc être relativement léger. Une bonne mise en bouche ! ^^ 

Retour dans Weapons.js

Notre vieil ami Weapons.js gère déjà beaucoup de choses, et il a une fonctionnalité sous le capot très utile : une boucle qui calcule le délai à respecter entre chaque tir. Cette fonction, c'est registerBeforeRender ! Mais avant ça, nous allons devoir ajouter quelques variables à droite et à gauche. ;) 

Armory.js

Dans Armory.js, nous allons commencer par ajouter à toutes nos armes une variable importante : timeAnimation. Cette variable déterminera le temps que va mettre chaque animation.

Par exemple, l'arme Crook va ressembler à ceci :

{
    'name':'Crook',
    'model' : {
        // 'meshUrl': '',
        'meshName': 'Crook'
    },
    'type':'closeCombat',
    'timeAnimation' : 400,
    'setup':{
        // Distance de frappe de l'arme de CaC
        'range': 4,
        'damage' : 20,
        'cadency' : 500,
        'colorMesh' : new BABYLON.Color3((59/255), (195/255), (203/255))
    }
},

Dès que vous avez affecté une valeur à toutes les armes, retournez dans Weapons.js !

Objet Weapons

Dans l'objet Weapons, nous allons paramétrer une valeur instanciée a zéro et qui augmente à chaque frame pendant laquelle le joueur ne peut pas tirer (dans notre fameux registerBeforeRender). Nous allons appeler cette variable _animationDelta.

// Définition du temps passé à chaque rechargement
this._animationDelta = 0; 

Player.game.scene.registerBeforeRender(function() {
    if (!_this.canFire) {
        // 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;
        }
    }
});

Vous voyez ici les deux valeurs que nous venons de créer : basePosition et baseRotation. Il va falloir les initialiser dans newWeapon(). Elles permettront de connaître la position initiale de l'arme en main !

newWeapon.basePosition = newWeapon.position;
newWeapon.baseRotation = newWeapon.rotation;

Ces deux variables vont maintenant nous servir à affecter le changement d'arme pour réinitialiser la position de celle-ci ainsi que _animationDelta.

if(this.actualWeapon != nextPossibleWeapon){
    // On dit à l'arme de se repositionner à son emplacement initial
    this.inventory[this.actualWeapon].position = 
    this.inventory[this.actualWeapon].basePosition.clone();
    
    this.inventory[this.actualWeapon].rotation = 
    this.inventory[this.actualWeapon].baseRotation.clone();
    
    // On reset _animationDelta
    this._animationDelta = 0;

    this.inventory[this.actualWeapon].isActive = false;
    this.inventory[this.actualWeapon]
    this.actualWeapon = nextPossibleWeapon;
    this.inventory[this.actualWeapon].isActive = true;

    this.fireRate = this.Armory.weapons[this.inventory[this.actualWeapon].typeWeapon].setup.cadency;
    this._deltaFireRate = this.fireRate;

  -------------------------------------------------------------------------

Maintenant que tout cela est défini, vous allez pouvoir créer la fonction pour animer les armes ! :) 

La fonction animateMovementWeapon

Nous allons créer cette fonction à la suite, avec comme paramètre le temps écoulé depuis le début du "rechargement" de l'arme.

animateMovementWeapon : function(step){
    if(!this.Player.isAlive){
        return;
    }
},

En premier lieu, on effectue une sortie de cette fonction si le joueur n'est plus en vie. En effet, si la fonction venait à s'activer alors que le joueur et ses armes n'existent plus, cela pourrait poser des problèmes !

Une fois cette précaution prise, nous allons récupérer le nombre fourni par le delta et nous en servir pour le transformer en un chiffre qui va varier de 0 à 1, puis de 1 à 0, et ainsi de suite. Si vous reprenez votre manuel de mathématiques, vous allez voir qu'une courbe comme celle-là existe… et c'est la courbe sinusoïdale !

À nous de transformer step pour qu'il varie de 0 à 1.

animateMovementWeapon : function(step){
    if(!this.Player.isAlive){
        return;
    }
    let typeWeapon = this.inventory[this.actualWeapon].typeWeapon;
    
    // On divise step par la valeur de timeAnimation de l'arme
    // On multiplie cette valeur par 180 
    let result = (step / this.Armory.weapons[typeWeapon].timeAnimation) * 180;

    // Si la valeur dépasse 180, c'est que step est supérieur à timeAnimation
    // Dans ce cas, on fait en sorte que result ne dépasse jamais 180
    if(result>180){
        result = 180;
    }
},

Vous voilà avec une valeur qui varie de 0 à 180. Il ne nous reste plus qu'à faire en sorte que cette valeur soit en radians et qu'on la donne à un sinus !

animateMovementWeapon : function(step){
    if(!this.Player.isAlive){
        return;
    }
    let typeWeapon = this.inventory[this.actualWeapon].typeWeapon;
    // On divise step par la valeur de timeAnimation de l'arme
    // On multiplie cette valeur par 180 
    let result = (step / this.Armory.weapons[typeWeapon].timeAnimation) * 180;

    // Si la valeur dépasse 180, c'est que step est supérieur à timeAnimation
    // Dans ce cas, on fais en sorte que result ne dépasse jamais 180
    if(result>180){
        result = 180;
    }
    // La valeur 100 sert à arrondir
    let degSin = Math.round(Math.sin(degToRad(result))*100)/100;
},

Et vous voilà avec une valeur qui va de 0 à 1, puis à 0 !

Avec cela, nous allons définir des valeurs à atteindre pour les meshes d'arme. Il vous suffira de multiplier ce paramètre avec notre valeur degSin, qui fera que l'arme monte et descend. ^^ 

animateMovementWeapon : function(step){
    if(!this.Player.isAlive){
        return;
    }
    let typeWeapon = this.inventory[this.actualWeapon].typeWeapon;
    
    // On divise step par la valeur de timeAnimation de l'arme
    // On multiplie cette valeur par 180 
    let result = (step / this.Armory.weapons[typeWeapon].timeAnimation) * 180;

    // Si la valeur dépasse 180, c'est que step est supérieur à timeAnimation
    // Dans ce cas, on fait en sorte que result ne dépasse jamais 180
    if(result>180){
        result = 180;
    }
    // La valeur 100 sert à arrondir
    let degSin = Math.round(Math.sin(degToRad(result))*100)/100;
    
    // On détermine les paramètres de mouvement pour chaque type d'arme
    switch(typeWeapon){
        case 0:
            var positionNeeded = new BABYLON.Vector3(0,-0.5,0);
            var rotationNeeded = new BABYLON.Vector3(-0.5,0,0);
            break;
        case 1:
            var positionNeeded = new BABYLON.Vector3(0.05,0.05,0);
            var rotationNeeded = new BABYLON.Vector3(0.1,0.1,0);
            break;
        case 2:
            var positionNeeded = new BABYLON.Vector3(0,0.4,0);
            var rotationNeeded = new BABYLON.Vector3(1.3,0,0);
            break;
        case 3:
            var positionNeeded = new BABYLON.Vector3(0,0,-1);
            var rotationNeeded = new BABYLON.Vector3(0,0,0);
            break;
    }
},

À présent, il faut indiquer au système de bouger selon le paramètre degSin !

animateMovementWeapon : function(step){
    if(!this.Player.isAlive){
        return;
    }
    let typeWeapon = this.inventory[this.actualWeapon].typeWeapon;
    
    // On divise step par la valeur de timeAnimation de l'arme
    // On multiplie cette valeur par 180 
    let result = (step / this.Armory.weapons[typeWeapon].timeAnimation) * 180;

    // Si la valeur dépasse 180, c'est que step est supérieur à timeAnimation
    // Dans ce cas, on fait en sorte que result ne dépasse jamais 180
    if(result>180){
        result = 180;
    }
    // La valeur 100 sert à arrondir
    let degSin = Math.round(Math.sin(degToRad(result))*100)/100;
    
    // On détermine les paramètres de mouvement pour chaque type d'arme
    switch(typeWeapon){
        case 0:
            var positionNeeded = new BABYLON.Vector3(0,-0.5,0);
            var rotationNeeded = new BABYLON.Vector3(-0.5,0,0);
            break;
        case 1:
            var positionNeeded = new BABYLON.Vector3(0.05,0.05,0);
            var rotationNeeded = new BABYLON.Vector3(0.1,0.1,0);
            break;
        case 2:
            var positionNeeded = new BABYLON.Vector3(0,0.4,0);
            var rotationNeeded = new BABYLON.Vector3(1.3,0,0);
            break;
        case 3:
            var positionNeeded = new BABYLON.Vector3(0,0,-1);
            var rotationNeeded = new BABYLON.Vector3(0,0,0);
            break;
    }
    // On récupère la position et rotation de base
    var baseRotation = this.inventory[this.actualWeapon].baseRotation.clone();
    var basePosition = this.inventory[this.actualWeapon].basePosition.clone();

    // On affecte les valeurs qui nous intéresse par étape
    this.inventory[this.actualWeapon].rotation = baseRotation.clone() ;
    this.inventory[this.actualWeapon].rotation.x -= (rotationNeeded.x*degSin);

    this.inventory[this.actualWeapon].position = basePosition.clone() ;
    this.inventory[this.actualWeapon].position.y += (positionNeeded.y*degSin);
    this.inventory[this.actualWeapon].position.z += (positionNeeded.z*degSin);
},

Et voilà ! Toutes nos armes bougent différemment à chaque fois que le joueur tire ! Vous pouvez changer les paramètres à votre guise ou tenter une approche différente pour le déplacement.

  

Maintenant, il est temps d'ajouter quelque chose qui manquait cruellement au jeu jusque-là : le saut! En route ! :)‌‌

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