Unity - Tanks

Contrôle de la caméra

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Voici le troisième épisode de la formation donnée au cours du Unite 2015 à Boston durant laquelle vous allez apprendre à faire un jeu dans lequel deux tanks s'affrontent.
Vous pouvez retrouver les autres épisodes de cette série dans le sommaire dédié.

II. Vidéo


Unity - Tanks ! - Contrôle de la caméra


III. Résumé

Dans cette troisième vidéo, vous allez voir comment déplacer la caméra suivant les mouvements des tanks. Dans ce contexte, la caméra doit toujours avoir les deux tanks dans son champ de vision. Pour cela, elle doit dynamiquement zoomer et dézoomer afin de ne pas perdre de vue les tanks.

III-A. Caméra

III-A-1. Implémentation dans la scène

Par défaut, la scène est composée d'une caméra principale (« Main Camera »). Dans ce jeu, la caméra seule ne suffit pas. Il est nécessaire de rajouter un nouveau GameObject (initialement vide) appelé « CameraRig ». Sa position est (0, 0, 0) et sa rotation est (40, 60, 0).
La caméra principale doit être enfant du nouvel GameObject. Celle-ci doit avoir la position (0, 0, -65) et la rotation (0, 0, 0).

Le comportement de la caméra (déplacement et zoom) est géré à travers un script « CameraControl » que l'on attache à l'objet « CameraRig ».

III-A-2. Script

 
Sélectionnez
using UnityEngine;

public class CameraControl : MonoBehaviour
{
    public float m_DampTime = 0.2f;                 // Temps approximatif pris par la caméra pour se focaliser.
    public float m_ScreenEdgeBuffer = 4f;           // Espace entre la cible en haut/bas de l'écran et la bordure de celui-ci.
    public float m_MinSize = 6.5f;                  // La taille minimale que la caméra puisse avoir.
    [HideInInspector] public Transform[] m_Targets; // Toutes les cibles que la caméra doit suivre.


    private Camera m_Camera;                        // Utilisé pour référencer la caméra.
    private float m_ZoomSpeed;                      // Vitesse de référence pour l'amortissement de la taille.
    private Vector3 m_MoveVelocity;                 // Vélocité de référence pour l'amortissement de la position.
    private Vector3 m_DesiredPosition;              // La position vers laquelle la caméra se dirige.


    private void Awake ()
    {
        m_Camera = GetComponentInChildren<Camera> ();
    }


    private void FixedUpdate ()
    {
        // Déplace la caméra à la position voulue.
        Move ();

        // Change la taille de la caméra.
        Zoom ();
    }


    private void Move ()
    {
        // Trouve la position moyenne des cibles.
        FindAveragePosition ();

        // Se déplace doucement vers cette position.
        transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
    }


    private void FindAveragePosition ()
    {
        Vector3 averagePos = new Vector3 ();
        int numTargets = 0;

        // Parcourt toutes les cibles et somme leur position.
        for (int i = 0; i < m_Targets.Length; i++)
        {
            // Si la cible n'est pas active, passe à la suivante.
            if (!m_Targets[i].gameObject.activeSelf)
                continue;

            // Ajoute à la moyenne et incrémente le nombre de cibles prises en compte.
            averagePos += m_Targets[i].position;
            numTargets++;
        }

        // S'il y a des cibles, divise la somme par leur nombre pour trouver la moyenne.
        if (numTargets > 0)
            averagePos /= numTargets;

        // Garde la même valeur pour Y.
        averagePos.y = transform.position.y;

        // La position voulue est la position moyenne.
        m_DesiredPosition = averagePos;
    }


    private void Zoom ()
    {
        // Trouve la taille requise suivant la position et atteint doucement cette taille.
        float requiredSize = FindRequiredSize();
        m_Camera.orthographicSize = Mathf.SmoothDamp (m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
    }


    private float FindRequiredSize ()
    {
        // Trouve la position vers laquelle le CameraRig se déplace dans son espace local.
        Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);

        // Commence le calcul avec une taille à 0.
        float size = 0f;

        // Parcourt toutes les cibles...
        for (int i = 0; i < m_Targets.Length; i++)
        {
            // ... et si l'une d'entre elles n'est pas active, passe à la suivante.
            if (!m_Targets[i].gameObject.activeSelf)
                continue;

            // Sinon, trouve la position de la cible dans l'espace local de la caméra.
            Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position);

            // Trouve la position de la cible à partir de la position voulue de l'espace local de la caméra.
            Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos;

            // Choisit la plus grande taille parmi toutes et la distance du tank en haut ou en bas de la caméra.
            size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.y));

            // Choisit la plus grande taille parmi toutes suivant la position à gauche ou droite du tank.
            size = Mathf.Max(size, Mathf.Abs(desiredPosToTarget.x) / m_Camera.aspect);
        }

        // Ajoute le tampon de bordure à la taille.
        size += m_ScreenEdgeBuffer;

        // S'assure que la taille de la caméra n'est pas inférieure à la taille minimale.
        size = Mathf.Max (size, m_MinSize);

        return size;
    }


    public void SetStartPositionAndSize ()
    {
        // Trouve la position voulue.
        FindAveragePosition ();

        // Définit la position de la caméra à la position voulue, sans amortissement.
        transform.position = m_DesiredPosition;

        // Trouve et définit la taille de la caméra.
        m_Camera.orthographicSize = FindRequiredSize ();
    }
}

III-A-3. Visibilité des variables dans l'inspecteur

Pour tester le script, la variable publique m_Targets est visible dans l'inspecteur. Ainsi, on peut rajouter les cibles de la caméra manuellement. Dans le jeu final, cette variable sera remplie par d'autres scripts. Afin de ne pas entraîner de problème en l'affectant à travers l'éditeur, il est possible de cacher la variable de l'inspecteur (même si celle-ci est publique) en précédant sa déclaration de [HideInInspector].

III-A-4. Suivi de la position

La position de l'objet CameraRig (et donc de la caméra) doit toujours correspondre au centre de l'ensemble des tanks. Pour cela, il suffit de prendre la position de chacun et de diviser la somme par leur nombre (autrement dit, de faire la moyenne de leur position).

III-A-5. Zoom

Afin de pouvoir faire les calculs, il est nécessaire de travailler dans l'espace de coordonnées de la caméra. Pour cela, il y a la fonction InverseTransformPoint() permettant de récupérer les coordonnées locales à partir des coordonnées dans l'espace monde.

Ensuite, il faut récupérer la distance la plus grande entre le point central de la caméra et les tanks (en espace local). Cela fonctionne immédiatement pour la hauteur de la caméra, car la taille correspond à la distance. En largeur, l'aspect (16/9) doit être pris en compte afin d'obtenir la vraie distance en X.

IV. Ressources

Vous pouvez télécharger le diaporama de la présentation.

Vous pouvez télécharger les ressources pour ce projet sur l'Asset Store de Unity.

V. Commenter

Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2016 Unity Technologies. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.