Variante de contrôles pour le jeu de bille

Le but de ce tuto est de mettre en place un système de contrôle de bille du même type que celui de Marble Blast, par exemple.

 

Ainsi, donner la possibilité au joueur de faire sauter la bille, mais aussi, et surtout, avoir la possibilité de faire tourner la caméra avec la souris.

 

L'idée est donc de pouvoir contrôler la bille au clavier avec ZQSD, la faire sauter avec SPACE et faire tourner la caméra à la souris.


1. Utilisation d'un Standard Asset de Unity

Nous allons en effet exploiter un setup de caméra déjà tout prêt que nous importerons depuis les Standard Assets de Unity.

Nous pourrions concevoir notre propre système, mais cela représente quand même un niveau assez conséquent de maîtrise de Unity. Et c'est justement là qu'il est judicieux d'utiliser des assets déjà tout prêt qu'il n'y a plus qu'à configurer !

C'est l'une des grandes puissances de Unity3D !

 

Commencez donc par importer le package Cameras :

Vous allez pouvoir trouver dans votre dossier "Project" 4 prefabs. Ils sont rangés ici : "Standard Assets/Cameras/Prefabs".

Pour notre système de contrôle, nous utiliserons le "FreeLookCameraRig".

2. Setup de la scène pour le prototype

Voici le setup de base que nous allons utiliser :

  1. Supprimez la MainCamera déjà présente dans la scène (le prefab que l'on va utiliser est déjà équipé d'une caméra).
  2. Insérer un cube et paramétrez-le pour en faire le sol.
  3. Créez un Empty, remettez-le bien à 0.
  4. A l'intérieur, placez-y une sphère "Player" ainsi que le prefab "FreeLookCameraRig".
  5. Positionnez le tout afin que cela soit exploitable pour des tests.
  6. Ajoutez un Rigidbody à la sphère Player et éventuellement une Constant Force.

Setup du FreeLookCameraRig

Le FreeLookCameraRig est donc l'élément qui va nous permettre de contrôler la caméra à la souris.

Testez une première fois en lançant le jeu. Vous remarquerez qu'il risque d'y avoir besoin de configurer certaines choses pour que cela fonctionne comme on le souhaite. En effet, par défaut, il ne se passe rien. On a beau déplacer la souris, il ne se passe rien.

 

Commençons donc les paramétrages :

Vous observerez que ce prefab est équipé, notamment, de 2 scripts (vous pourrez les ouvrir, par curiosité, mais ne les modifiez pas).

 

Il y a un paramètre important, ici : "Target". Cela signifie "Cible".

Le script a en effet besoin d'une cible à suivre. C'est le joueur, bien sûr !

Mais observez la propriété juste en-dessous : "Auto Target Player". Ce qui signifie "cibler automatiquement le Player" ; en l’occurrence, tout objet taggé "Player" (mais il n'en faut qu'un seul !).

Donc, si vous taggez votre sphère "Player" et que vous laissez la case "Auto Target Player" vide, le script trouvera automatiquement votre sphère et l'utilisera comme cible.

 

Censément, il vous faut assigner à "Target" votre sphère.

Mais le mieux est surtout de bien tagger votre sphère "Player".

Vous pouvez faire les deux, ce n'est pas gênant.

Mais sachez que le tag "Player" est aussi utilisé par le 2ème script (propriété "Dont Clip Tag" : "Player").

 

Testez de nouveau votre scène.

La caméra doit automatiquement "regarder" vers la bille.

 

Maintenant que notre caméra pointe bien vers la bille, il nous faut configurer la réaction aux mouvements de la souris. Il s'agit d'augmenter les valeurs des propriétés "Turn Speed" et "Turn Smoothing". Mettez-les à 10, c'est suffisant.

 

Testez à nouveau votre setup.

Et ça y est ! Notre caméra suit bien la souris !

 

Pour régler la distance de la caméra par rapport à la bille, augmentez la valeur de la propriété "Closest Distance" du script "Protect Camera From Wall Clip". Une valeur de 7 est pas mal.

Comportements de la bille

Maintenant que notre caméra fonctionne bien, il va falloir programmer les contrôles de la bille.

 

Nous allons partir de ce que l'on a fait sur notre jeu de bille précédent.

 

Donc, créez un nouveau script C# et nommez-le, par exemple, PlayerController.

Placez-le sur la sphère Player.

Puis inscrivez les lignes suivantes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using UnityEngine;

public class PlayerController : MonoBehaviour
{
        //Référence au rigidbody de la bille
        public Rigidbody playerRigidbody;

        //Vitesse à assigner via l'inspecteur
        public float        speed;


        // Update is called once per frame
        void Update ()
        {
                //SI la touche "flèche du haut" est maintenue appuyée
                if ( Input.GetKey ( KeyCode.UpArrow ) )
                {
                        //Ajout de force vers l'avant au rigidbody
                        playerRigidbody.AddForce ( Vector3.forward * speed );
                }

                if ( Input.GetKey ( KeyCode.DownArrow ) )
                {
                        playerRigidbody.AddForce ( Vector3.back * speed );
                }

                if ( Input.GetKey ( KeyCode.LeftArrow ) )
                {
                        playerRigidbody.AddForce ( Vector3.left * speed );
                }

                if ( Input.GetKey ( KeyCode.RightArrow ) )
                {
                        playerRigidbody.AddForce ( Vector3.right * speed );
                }
        }
}

Il ne reste plus qu'à assigner le Rigidbody du player via l'inspecteur et entrer une valeur pour la vitesse (Speed).

Testons ce script !

 

Conclusions : plusieurs problèmes.

- Nous avons ici assigner les flèches du clavier alors que l'on souhaite utiliser ZQSD.

- Il manque par ailleurs le saut sur la barre d'espace.

- La caméra ne suit pas bien la bille, elle se déplace trop lentement.

- Dernier point, et pas des moindres : si la caméra est tournée d'un côté ou de l'autre et que l'on déplace la bille au clavier, celle-ci ne suit pas la direction de la caméra, rendant les contrôles impossibles à jouer...

 

Nous allons essayer de corriger ces problèmes un par un.

3. Corrections des problèmes

Les contrôles de base au clavier

Commençons par le plus facile. Voici le script corrigé pour les contrôles de base.

Utilisation des touches ZQSD et Barre d'espace pour le saut. Remarquez au passage la création d'une variable destinée à accueillir la valeur de puissance du saut.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using UnityEngine;

public class PlayerController : MonoBehaviour
{
        //Référence au rigidbody de la bille
        public Rigidbody    playerRigidbody;

        //Vitesse à assigner via l'inspecteur
        public float        speed;        //Essayez 10
        //Puissance du saut (à assigner via l'inspecteur ausssi)
        public float        jump;   //Essayez 500



        // Update is called once per frame
        void Update ()
        {
                //SI la touche "flèche du haut" est maintenue appuyée
                if ( Input.GetKey ( KeyCode.Z ) )
                {
                        //Ajout de force vers l'avant au rigidbody
                        playerRigidbody.AddForce ( Vector3.forward * speed );
                }

                if ( Input.GetKey ( KeyCode.S ) )
                {
                        playerRigidbody.AddForce ( Vector3.back * speed );
                }

                if ( Input.GetKey ( KeyCode.Q ) )
                {
                        playerRigidbody.AddForce ( Vector3.left * speed );
                }

                if ( Input.GetKey ( KeyCode.D ) )
                {
                        playerRigidbody.AddForce ( Vector3.right * speed );
                }

                //Utilisation de l'évènement "KeyDown" pour le saut, sinon,
                //tant que la barre d'espace est pressée, la bille vole ^^
                //Alors que là, la puissance du Jump n'est ajouté qu'une seule fois.
                if ( Input.GetKeyDown ( KeyCode.Space ) )
                {
                        playerRigidbody.AddForce ( Vector3.up * jump );
                }
        }
}

Petit plus : ajout d'un composant Constant Force avec une valeur de -20 sur la propriété Y afin d'avoir une bille "plus lourde". Ce qui rend le saut plus réaliste.

Déplacement de la caméra trop lent

Pour ce qui est de la vitesse de déplacement de la caméra, il faut retourner sur le gameobject "FreeLookCameraRig" et changer la valeur de la propriété "Move Speed".

 

10 fonctionne plutôt bien.

Aligner la direction de la bille selon la direction de la caméra

Alors, c'est ici qu'on va commencer à s'amuser un peu ^^

En effet, il va nous falloir opérer à quelques calculs...

 

Tout d'abord, il nous faut bien comprendre le problème.

 

Lorsque nous écrivons ceci :

1
2
3
4
5
6
//SI la touche "flèche du haut" est maintenue appuyée
if ( Input.GetKey ( KeyCode.UpArrow ) )
{
        //Ajout de force vers l'avant au rigidbody
        playerRigidbody.AddForce ( Vector3.forward * speed );
}

...nous n'ajoutons en fait pas vraiment de la force VERS L'AVANT, mais vers l'axe Z du monde 3D.

 

Ainsi, peu importe où regarde la caméra, à partir du moment où le joueur appuis sur la touche de déplacement, la bille est poussée vers Z.

 

Pour que notre nouveau système fonctionne, il va falloir travailler là-dessus.

L'idée va être d'utiliser les informations de rotation du "FreeLookCameraRig".

 

Observons déjà ce qu'il se passe, concrètement, lorsque nous bougeons la caméra :

- Séléctionnez le "FreeLookCameraRig" dans la hiérarchie

- Lancez le jeu

- Observez les valeurs du Transform pendant que vous bougez la caméra à la souris

Voyez comment varient les valeurs de l'axe de rotation Y.

 

Ce sont ces valeurs qui disent "vers où regarde" la caméra.

Ce sont donc avec ces valeurs qu'il va falloir travailler.

 

1ère chose : Notre script doit "connaître" ces informations.

Pour cela, créons une variable et voyons si on arrive à accéder aux bonnes infos.

1
2
//Référence au composant Transform du FreeLookCameraRig
public Transform transformToFollow;

Dans Unity, ne pas oublier de glisser le gameobject "FreeLookCameraRig" dans la variable.

 

Puis dans l'update, affichons les informations locales de rotation (locales, car celles de l'objet lui-même) :

1
Debug.Log ( transformToFollow.localRotation );

Alors, ici c'est un peu compliqué : le type de donnée renvoyé par la propriété "localRotation" est en fait un Quaternion, une unité composée de 4 informations et TRES difficile à manipuler. En effet, Unity utilise des Quaternions pour tous les calculs de rotation.

 

Nous, nous avons l'habitude de manipuler des Vecteur3. Heureusement il est possible de convertir un Quarternion en Vecteur3.

 

Mais pour notre Debug, afin de mieux lire les informations retournées par le Quaternion, nous allons opérer comme ceci :

1
Debug.Log ( transformToFollow.localRotation.eulerAngles );

Voilà, avec ceci, nous allons pouvoir nous rendre compte des informations contenues dans la propriété "localRotation".

 

En testant notre jeu, on peut se rendre compte que les informations retournées par le "localRotation" converties en angles Euler (ceux que l'on lit dans l'interface Unity sous forme de vecteur 3), sont bien les bonnes informations.

 

Notre script Player connait donc l'état et la valeur de rotation du FreeLookCameraRig.

Nous allons donc pouvoir travailler avec cette propriété.

 

L'idée : Alors, ce sont des maths, purs et durs...

On connait la rotation que l'on veut suivre ET on sait faire avancer notre bille vers l'avant grâce à Vector3.forward.

Il faut savoir que Vector3.forward est égale à Vector3 (0, 0, 1).

 

Le but est de calculer une "POUSSEE" sous forme de vecteur3 dans la bonne direction.

 

Pour établir le rapport entre la rotation de la caméra et la poussée de base de la bille, il va falloir les multiplier.

Ainsi, pour aller dans la bonne direction, il nous faut multiplier le vecteur de direction par la rotation de la caméra.

 

Il ne nous restera plus qu'à multiplier par la vitesse, et notre poussée devrait aller dans la bonne direction par rapport à la caméra et adopter un degré de vitesse selon les valeurs entrées dans l'inspecteur.

 

Essayons ceci pour aller vers l'avant. Su cela fonctionne, il n'y aura plus qu'à faire de même avec les autres directions.

1
2
3
4
5
6
//SI la touche "Z" est maintenue appuyée
if ( Input.GetKey ( KeyCode.Z ) )
{
        //Ajout de force vers l'avant du rigidbody par rapport à la rotation  de la caméra
        playerRigidbody.AddForce ( transformToFollow.localRotation * Vector3.forward * speed );
}

Normalement, cela fonctionne bien ! ;)

Reste plus qu'à adapter le reste du script de contrôle comme ceci :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using UnityEngine;

public class PlayerController : MonoBehaviour
{
        //Référence au composant Transform du FreeLookCameraRig
        public Transform transformToFollow;

        //Référence au rigidbody de la bille
        public Rigidbody    playerRigidbody;

        //Vitesse à assigner via l'inspecteur
        public float        speed;        //Essayez 10
        //Puissance du saut (à assigner via l'inspecteur ausssi)
        public float        jump;   //Essayez 500



        // Update is called once per frame
        void Update ()
        {
                //SI la touche "Z" est maintenue appuyée
                if ( Input.GetKey ( KeyCode.Z ) )
                {
                        //Ajout de force vers l'avant du rigidbody par rapport à la rotation  de la caméra
                        playerRigidbody.AddForce ( transformToFollow.localRotation * Vector3.forward * speed );
                }

                if ( Input.GetKey ( KeyCode.S ) )
                {
                        playerRigidbody.AddForce ( transformToFollow.localRotation * Vector3.back * speed );
                }

                if ( Input.GetKey ( KeyCode.Q ) )
                {
                        playerRigidbody.AddForce ( transformToFollow.localRotation * Vector3.left * speed );
                }

                if ( Input.GetKey ( KeyCode.D ) )
                {
                        playerRigidbody.AddForce ( transformToFollow.localRotation * Vector3.right * speed );
                }

                //Utilisation de l'évènement "KeyDown" pour le saut, sinon,
                //tant que la barre d'espace est pressée, la bille vole ^^
                //Alors que là, la puissance du Jump n'est ajouté qu'une seule fois.
                if ( Input.GetKeyDown ( KeyCode.Space ) )
                {
                        playerRigidbody.AddForce ( Vector3.up * jump );
                }
        }
}