Home | Clases | Unity: Videojuego para 2 jugadores en 3D ortográfico | La cámara

La cámara


Creación del conjunto de la cámara

  • Crea un nuevo EmptyObject y renómbralo como CameraRig
  • Resetea su Position y ajusta Rotation a 40, 60, 0
  • Arrastra la Main Camera dentro de CameraRig
  • Ajusta la Position de la Main Camera a 0, 0 , 65 y asegúrate de que su Rotation es 0, 0, 0.

En este caso, la Main Camera estará definida con una Position Local respecto de la CameraRig.

NOTA: La diferencia entre Local y Global Position es fácilmente entendible si piensas en que vas conduciendo: los elementos a tu alrededor tienen una Position Local respecto a ti, pero una Position Global respecto al mundo (igual que tú y tu coche). Esto será importante para configurar la cámara de forma diferente en juegos en 1ª o 3ª persona.


Entendiendo el View Frustum y el Aspect

La palabra frustum se refiere a una figura sólida que parece como una pirámide con la parte superior cortada paralela a la base. Esta es la forma de la región que puede ser vista y renderizada por una cámara de perspectiva estándar.

Imaginemos el ejemplo siguiente, en el que una cámara está captando un lápiz en diferentes posiciones:




En el primer caso, el lápiz es perpendicular a las lentes de la cámara y está en centro del plano, con lo que se registra únicamente un punto.
En el segundo caso, sigue siendo perpendicular al plano pero desplazada hacia un lado, con lo que la cámara registra una línea cada vez más delgada.
En el tercer caso, solo se ve un punto porque el resto se sale del plano.

En definitiva, cualquier punto en una imagen de cámara en realidad corresponde a una linea en el espacio y solamente un punto a lo largo de esa linea es visible en la imagen

En Unity, el frustum view se refiere a la figura geométrica formada por los dos planos de recorte de la cámara (el más lejano y el más cercano) y las líneas imaginarias que los unen.

De este modo, en una cámara en perspectiva estándar, el frustum view será similar a una pirámide truncada (figura de la izquierda), en la cual los objetos más alejados se ven más pequeños (como en el mundo real), mientras que en el caso de una cámara ortográfica, en la que buscamos que los objetos más alejados tengan el mismo tamaño que los cercanos, el frustum view tendrá forma de paralelepípedo (figura de la derecha):



En el caso de una cámara ortográfica, podemos ajustar el zoom de la misma simplemente ajustando su tamaño o size.



Otro parámetro que vamos a necesitar será el aspecto o aspect de la cámara: Al igual que en el caso de una TV en HD (1080p o lo que es lo mismo 1920 x 1080px), el aspect es el resultado de dividir ancho entre alto (1,778 en este caso).

Nota: No confundir con aspect ratio, que se expresa como 16:9 (aunque el resultado sea el mismo).

Así, en una cámara en perspectiva, ajustaremos el zoom ajustando size x aspect:




Ajustando la cámara

El objetivo de nuestra cámara es doble: por un lado debe seguir a los tanques y por el otro debe ajustar el tamaño (zoom) para asegurarse que los tanques permanecen dentro de la pantalla.

Para el primer propósito (seguir a los tanques), arrastra el script Camera Control desde Scripts/Camera al objeto CameraRig. Ábrelo y fíjate en los comentarios para entenderlo.

Básicamente, para seguir a los tanques haremos uso de las funciones Move y FIndAveragePoisition.



Para hacer zoom de manera dinámica, tenderemos en cuenta el size en el eje Y, que corresponderá a la distancia en Y del tanque, y el size en el eje X, que corresponderá a la distancia en X del tanque dividido por el aspect:




Para el zoom, utilizamos las funciones Zoom, FindRequiredSize y SetStartPositionAndSize.


using UnityEngine;

public class CameraControl : MonoBehaviour
{
public float m_DampTime = 0.2f; //Tiempo de espera para mover la cámara
public float m_ScreenEdgeBuffer = 4f; //Pequeño padding para que los tanques no se pegen a los bordes
public float m_MinSize = 6.5f; //Tamaño mínimo de zoom
/*[HideInInspector]*/ public Transform[] m_Targets; //Array de tanques, no se mostrarán en el inspector cuando haya Game Manager


private Camera m_Camera; //la cámara
private float m_ZoomSpeed; //velocidad de zoom
private Vector3 m_MoveVelocity; //velocidad de movimiento
private Vector3 m_DesiredPosition; //posición a la que quiero llegar


private void Awake()
{
//Al arrrancar cogemos la cámara
m_Camera = GetComponentInChildren<Camera>();
}


private void FixedUpdate()
{
Move(); //Mueve la cámara
Zoom(); //ajusta el tamaño de la cámara
}


private void Move()
{
//Busco la posicón intermedia entre los dos tanques
FindAveragePosition();

//Muevo la cámara de forma suave
transform.position = Vector3.SmoothDamp(transform.position, m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
}


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

//Recorre la cantidad de tanques activos, captura su posición y asigna a m_DesiredPosition el punto medio entre ellos (en el eje Y)
for (int i = 0; i < m_Targets.Length; i++)
{
//Si no está activo me lo salto
if (!m_Targets[i].gameObject.activeSelf)
continue;

//incremento el valor a la media y el número de elementos
averagePos += m_Targets[i].position;
numTargets++;
}

//Si hay elementos, hago la media
if (numTargets > 0)
averagePos /= numTargets;

//mantengo el valor de y
averagePos.y = transform.position.y;

//La posición deseada es la media
m_DesiredPosition = averagePos;
}


private void Zoom()
{
//Buscamos la posición requerida de zoom (size) y la asignamos a la cámara
float requiredSize = FindRequiredSize();
//Ajusto el tamaño de la cámara de forma suave
m_Camera.orthographicSize = Mathf.SmoothDamp(m_Camera.orthographicSize, requiredSize, ref m_ZoomSpeed, m_DampTime);
}


private float FindRequiredSize()
{
//Teniendo en cuenta la posición deseada
Vector3 desiredLocalPos = transform.InverseTransformPoint(m_DesiredPosition);

float size = 0f;

//recorremos los tanques activos y cojemos la posición más alta (el que estaría más lejos del centro)
for (int i = 0; i < m_Targets.Length; i++)
{
//Si no está activo me lo salto
if (!m_Targets[i].gameObject.activeSelf)
continue;

//posición del tanque en el espacio de la cámara
Vector3 targetLocalPos = transform.InverseTransformPoint(m_Targets[i].position);

//diferencia entre la deseada y la actual
Vector3 desiredPosToTarget = targetLocalPos - desiredLocalPos;

//escojo el máximo entre el tamaño de cámara actual y la distancia del tanque (arriba o abajo)
size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.y));

//escojo el máximo entre el tamaño de cámara actual y la distancia del tanque (izqueirda o derecha)
size = Mathf.Max (size, Mathf.Abs (desiredPosToTarget.x) / m_Camera.aspect);
}

//Aplicamos el padding
size += m_ScreenEdgeBuffer;

//Comprobamos que al menos tenemos el zoom mínimo
size = Mathf.Max(size, m_MinSize);

return size;
}

//La usaremos en el GameManager para resetear la posición y el zoom en cada escena
public void SetStartPositionAndSize()
{
//Buscamos la posición deseada
FindAveragePosition();

//ajustamos la posición de la cámara (sin damping porque va a ser al entrar)
transform.position = m_DesiredPosition;

//buscamos y ajustamos el tamaño de la cámara
m_Camera.orthographicSize = FindRequiredSize();
}
}


Para finalizar, selecciona el CameraRig y arrastra el Tank a la variable pública Targets del script Camera Control. Pulsa Play y comprueba que todo funciona.

No olvides guardar la escena.


Fecha de publicación: 29/07/2018
Asignaturas: realización de proyectos multimedia interactivosdesarrollo de entornos interactivos multidispositivo
Temas: Unity 2d ortográfico
Utilizamos cookies propias y de terceros para mejorar su experiencia en la navegación. Al seguir navegando entendemos que acepta su uso.
Si lo desea, consulte nuestras políticas de privacidad y cookies
ENTENDIDO
[X] Cerrar

Contacta conmigo


[X] Cerrar

Acceso alumnos