Fil d'Ariane
Mis à jour le mardi 18 octobre 2016
  • 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 !

Développez une fonction de saut pour le joueur

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

Bien, maintenant que nous avons créé toutes les animations nécessaires, vous allez travailler à ajouter une partie importante du jeu : le saut !

Pour cela, nous allons développer nous-même un système de chutes. Cela vous donnera l'occasion de voir comment on peut faire fonctionner une inertie. C'est parti !

Développer le saut

Pour sauter, vous aurez besoin de quelques paramètres : 

  • La hauteur du saut

  • La hauteur du personnage

  • Le temps passé en saut

  • Si le joueur peut sauter

En plus de cela, bien évidemment, il va nous falloir capter la touche espace. C'est par cela que vous allez commencer : direction Player.js ! Ajoutez les lignes suivantes à la fin de l'objet Player. ^^

window.addEventListener("keypress", function(evt) {
    // Le keyCode 32 correspond à la bare espace
    if(evt.keyCode === 32){
        console.log('Jumped!')
    }
}, false);

Maintenant que l'event est créé, il vous faut ajouter toutes les variables dont nous venons de parler ! Vous pouvez les mettre directement dans Player, juste au-dessus de keypress.

// Si le joueur peut sauter ou non
_this.camera.canJump = true;

// La hauteur de saut
_this.jumpHeight = 10;

// La hauteur du personnage
_this.originHeight = _this.camera.playerBox.position.clone();
window.addEventListener("keypress", function(evt) {
    if(evt.keyCode === 32){
        
    }
}, false);

Il est important de faire en sorte que le joueur ne puisse sauter qu'une seule fois. C'est pour cela que nous allons gérer le saut de telle manière que cette valeur passe à false dès que la touche de saut est pressée. Ensuite, nous vérifions si le joueur touche le sol grâce à la valeur originHeight. S'il touche le sol, on refait passer canJump à true. Ça, c'était la théorie ! Mettons tout cela en pratique. :p

// Si le joueur peut sauter ou non
_this.camera.canJump = true;

// La hauteur de saut
_this.jumpHeight = 10;

// La hauteur du personnage
_this.originHeight = _this.camera.playerBox.position.clone();
window.addEventListener("keypress", function(evt) {
    if(evt.keyCode === 32){
        if(_this.camera.canJump===true){
                // On définit la hauteur de saut à la position actuelle du joueur
                // plus la variable jumpHeight
                _this.camera.jumpNeed = _this.camera.playerBox.position.y + _this.jumpHeight;
                _this.camera.canJump=false;
            }
    }
}, false);

À présent que tout cela est défini, allez dans _checkUniqueMove. Là-bas, nous avons déjà une boucle qui effectue les actions de déplacement à chaque frame. C'est donc là que vous allez ajouter votre code ! Tout en bas de la fonction, vous allez vérifier si le joueur doit sauter.

if(playerSelected.jumpNeed){
    // Lerp 
    percentMove = playerSelected.jumpNeed - playerSelected.playerBox.position.y;
    // Axe de mouvement
    up = new BABYLON.Vector3(0,percentMove/4 *  relativeSpeed,0);
    playerSelected.playerBox.moveWithCollisions(up);
    // On vérifie si le joueur a environ atteint la hauteur désirée
    if(playerSelected.playerBox.position.y + 1 > playerSelected.jumpNeed){
        // Si c'est le cas, on prépare airTime
        playerSelected.airTime = 0;
        playerSelected.jumpNeed = false;
    }
}else{
    // Si l'ascension est terminée, on redescend
}

Quand jumpNeed est égal à une valeur, on effectue un lerp vers la position choisie.

On multiplie cette valeur de lerp par la relativeSpeed (qui est, je le rappelle, un calcul pour adapter le déplacement selon les performances des machines). Maintenant que jumpNeed est égal à 0, on passe dans le else. L'objectif est de déterminer la distance qu'il reste à parcourir pour atteindre le sol et accélérer tant que le joueur n'est pas arrivé au sol.

Première chose à faire, déterminer cette distance :

if(playerSelected.jumpNeed){
    // Lerp 
    percentMove = playerSelected.jumpNeed - playerSelected.playerBox.position.y;
    // Axe de mouvement
    up = new BABYLON.Vector3(0,percentMove/4 *  relativeSpeed,0);
    playerSelected.playerBox.moveWithCollisions(up);
    // On vérifie si le joueur a atteint la hauteur désirée
    if(playerSelected.playerBox.position.y + 1 > playerSelected.jumpNeed){
        // Si c'est le cas, on prépare airTime
        playerSelected.airTime = 0;
        playerSelected.jumpNeed = false;
    }
}else{
    // On trace un rayon depuis le joueur
    var rayPlayer = new BABYLON.Ray(playerSelected.playerBox.position,new BABYLON.Vector3(0,-1,0));

    // On regarde quel est le premier objet qu'on touche
    // On exclut tous les meshes qui appartiennent au joueur
    var distPlayer = this.game.scene.pickWithRay(rayPlayer, function (item) {
        if (item.name == "hitBoxPlayer" || item.id == "headMainPlayer" || item.id == "bodyGhost" || item.isPlayer)
            return false;
        else
            return true;
    });
}

Vous disposez maintenant de la distance entre le joueur est le sol. Nous devons faire en sorte de déplacer le joueur vers le bas à chaque frame, en augmentant airTime tant qu'il n'a pas touché le sol. airTime décidera de la vitesse de chute (plus on tombe longtemps, plus on tombe vite).

if(playerSelected.jumpNeed){
    // Lerp 
    percentMove = playerSelected.jumpNeed - playerSelected.playerBox.position.y;
    // Axe de mouvement
    up = new BABYLON.Vector3(0,percentMove/4 *  relativeSpeed,0);
    playerSelected.playerBox.moveWithCollisions(up);
    // On vérifie si le joueur a atteint la hauteur désirée
    if(playerSelected.playerBox.position.y + 1 > playerSelected.jumpNeed){
        // Si c'est le cas, on prépare airTime
        playerSelected.airTime = 0;
        playerSelected.jumpNeed = false;
    }
}else{
    // On trace un rayon depuis le joueur
    var rayPlayer = new BABYLON.Ray(playerSelected.playerBox.position,new BABYLON.Vector3(0,-1,0));

    // On regarde quel est le premier objet qu'on touche
    // On exclut tous les meshes qui appartiennent au joueur
    var distPlayer = this.game.scene.pickWithRay(rayPlayer, function (item) {
        if (item.name == "hitBoxPlayer" || item.id == "headMainPlayer" || item.id == "bodyGhost"  || item.isPlayer)
            return false;
        else
            return true;
    });
    // targetHeight est égal à la hauteur du personnage
    var targetHeight = this.originHeight.y;
    // Si la distance avec le sol est inférieure ou égale à la hauteur du joueur -> On a touché le sol
    if(distPlayer.distance <= targetHeight){
        // Si c'est le joueur principal et qu'il ne peut plus sauter
        if(playerSelected.isMain && !playerSelected.canJump){
            playerSelected.canJump = true;
        }
        // On remet airTime à 0
        playerSelected.airTime = 0;
    }else{
        // Sinon, on augmente airTime
        playerSelected.airTime++;
        // Et on déplace le joueur vers le bas, avec une valeur multipliée par airTime
        playerSelected.playerBox.moveWithCollisions(new BABYLON.Vector3(0,(-playerSelected.airTime/30) * relativeSpeed ,0));
    }
}

Et voilà ! Le saut est en place ! Nous avons un certain nombres de lignes ici et nous aurions pu le faire plus simplement, mais l'intérêt était de vous montrer comment faire "à la main" ce genre de choses. ;)

Et maintenant qu'on a tout ça, comment on fait pour montrer aux autres joueurs qu'on a sauté ?

Eh bien maintenant que nous avons la fonction sendNewData pour transférer les données à tous les joueurs, il nous suffit d'envoyer par ce biais que le jumpNeed d'un joueur a changé ! On s'en occupe tout de suite.

Voir le saut des autres joueurs

Pour voir le saut des autres joueurs, rien de plus simple ! Il nous suffit d'envoyer l'endroit où le joueur est censé arriver avec le saut dans l'event que nous avons créé plus tôt.

window.addEventListener("keypress", function(evt) {
    if(evt.keyCode === 32){
        if(_this.camera.canJump===true){
            _this.camera.jumpNeed = _this.camera.playerBox.position.y + _this.jumpHeight;
            _this.camera.canJump=false;
            var data={
                jumpNeed : _this.camera.jumpNeed
            };
            _this.sendNewData(data)
        }
    }
}, false);

Nous n'avons même pas besoin de vérifier si les ghosts peuvent sauter : chaque joueur le fait de son côté !

En plus de cela, il vous faut tout de même ajouter une dernière ligne : targetHeight est actuellement défini avec originHeight.y. Si c'est un ghost, cette valeur doit changer. Le reste de la boucle ne change pas. ^^

if(playerSelected.jumpNeed){
    // Lerp 
    percentMove = playerSelected.jumpNeed - playerSelected.playerBox.position.y;
    // Axe de mouvement
    up = new BABYLON.Vector3(0,percentMove/4 *  relativeSpeed,0);
    playerSelected.playerBox.moveWithCollisions(up);
    // On vérifie si le joueur a atteint la hauteur désirée
    if(playerSelected.playerBox.position.y + 1 > playerSelected.jumpNeed){
        // Si c'est le cas, on prépare airTime
        playerSelected.airTime = 0;
        playerSelected.jumpNeed = false;
    }
}else{
    // On trace un rayon depuis le joueur
    var rayPlayer = new BABYLON.Ray(playerSelected.playerBox.position,new BABYLON.Vector3(0,-1,0));

    // On regarde quel est le premier objet qu'on touche
    // On exclut tous les meshes qui appartiennent au joueur
    var distPlayer = this.game.scene.pickWithRay(rayPlayer, function (item) {
        if (item.name == "hitBoxPlayer" || item.id == "headMainPlayer" || item.id == "bodyGhost"  ||  item.isPlayer)
            return false;
        else
            return true;
    });
    // isMain permet de vérifier si c'est le joueur
    if(playerSelected.isMain){
        var targetHeight = this.originHeight.y;
    }else{
        // si c'est un ghost, on fixe la hauteur à 3 
        var targetHeight = 3;
    }
    if(distPlayer.distance <= targetHeight){
        if(playerSelected.isMain && !playerSelected.canJump){
            playerSelected.canJump = true;
        }
        playerSelected.airTime = 0;
    }else{
        playerSelected.airTime++;
        playerSelected.playerBox.moveWithCollisions(new BABYLON.Vector3(0,(-playerSelected.airTime/30) * relativeSpeed ,0));
    }
}

Enfin, il nous faut ajouter le paramètre saut reçu par updateLocalGhost : data.jumpNeed.

updateLocalGhost : function(data){
    ghostPlayers = this.ghostPlayers;
    
    for (var i = 0; i < ghostPlayers.length; i++) {
        if(ghostPlayers[i].idRoom === data.id){
            var boxModified = ghostPlayers[i].playerBox;
            // On applique un correctif sur Y, qui semble être au mauvais endroit
            if(data.position){
                boxModified.position = new BABYLON.Vector3(data.position.x,data.position.y-2.76,data.position.z);
            }
            if(data.axisMovement){
                ghostPlayers[i].axisMovement = data.axisMovement;
            }
            if(data.rotation){
                ghostPlayers[i].head.rotation.y = data.rotation.y;
            }
            if(data.jumpNeed){
                ghostPlayers[i].jumpNeed = data.jumpNeed;
            }
            if(data.axisMovement){
                ghostPlayers[i].axisMovement = data.axisMovement;
            }
        }
        
    }
}

C'est fait ! Les joueurs peuvent se voir entre eux sauter dans tous les sens dans le jeu ! On pourrait maintenant aller plus loin ! Étant donné que ce qui fait sauter les joueurs est originHeight, il serait très simple d'ajouter des plateformes de saut !

‌  

… Cependant, pour l'instant, nous n'allons pas nous occuper de ça mais continuer avec un chapitre un peu plus imposant : la génération des bonus en jeu ! Allez, à tout de suite ! :)

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