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▲
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.