Câmeras para jogos 3D
Uma parte fundamental da criação de jogos em 3D é o uso de câmeras para mostrar o ambiente e os personagens da forma mais adequada ao gameplay desejado. O controle de câmeras pode ter diversos níveis de complexidade e nem sempre uma câmera mais complexa necessariamente é mais eficiente para um jogo. A seguir, vamos ver como implementar e as principais características de alguns tipos de câmeras para jogos 3D. O exemplo abaixo está disponível para download aqui.
Movimento relativo à câmera
Antes de falar de câmeras em si, um primeiro passo seria o de tornar o movimento do personagem ou avatar relativo à câmera, ou seja, apertar para frente move o jogador para a frente em relação à câmera. Para isso, vamos utilizar o código abaixo.
void Update () {
_input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
_input = Vector3.ClampMagnitude(_input, 1f);
Vector3 camForward = Camera.main.transform.forward;
_velTemp = Input.GetAxis("Vertical") * camForward + Input.GetAxis("Horizontal") * Camera.main.transform.right;
_velTemp.y = 0f;
_velTemp = _velTemp.normalized * _input.magnitude;
_anim.SetFloat("speed", _velTemp.magnitude);
}
void FixedUpdate()
{
if (_input.sqrMagnitude <= 0f)
{
return;
}
var vel = _velTemp * velocidade;
//var velAlvo = new Vector3(vel.x, _rb.velocity.y, vel.z);
transform.forward = Vector3.Slerp(transform.forward, _velTemp.normalized, Time.fixedDeltaTime * suavizar);
var finalVel = transform.forward * velocidade * _input.magnitude;
finalVel.y = _rb.velocity.y;
_rb.velocity = finalVel;
}
Ponto fixo, ângulo fixo
Essa seria uma câmera totalmente estática, posicionada de forma a sempre mostrar as mesmas coisas. É a mais simples de configurar e é bastante previsível.
Ponto fixo, ângulo variável
Essa câmera rotaciona para acompanhar um alvo, mas mantendo uma certa posição. Permite bastante controle por parte dos designers, mas mantém o centro da atenção no avatar.
void LateUpdate()
{
transform.LookAt(alvo);
}
Distância fixa, ângulo fixo
Nesse tipo de câmera, a distância e o ângulo entre a câmera e o avatar são sempre iguais, ou então tentam ser na medida do possível (pode-se usar suavização para evitar movimentos bruscos). É bastante simples de configurar, mas pode ser bastante interessante dependendo do tipo de movimento e espaço que o jogo apresenta.
void Start()
{
offset = transform.position - alvo.position;
}
void FixedUpdate()
{
Vector3 posicaoDesejada = alvo.position + offset;
posicaoDesejada = Vector3.Lerp(transform.position, posicaoDesejada, Time.fixedDeltaTime * suavizar);
transform.position = posicaoDesejada;
if(rotacionar)
{
transform.LookAt(alvo);
}
}
Distância fixa, ângulo variável
Essa é uma câmera bastante dinâmica, que segue o personagem, além de permitir uma pequena variação de enquadramento através de um offset. É bastante utilizada, mas, por sua complexidade, também apresenta uma série de problemas com colisões, suavização e uso contextual (curvas, controle do usuário, etc).
void Start()
{
offset = alvo.transform.position - transform.position;
}
void LateUpdate()
{
float anguloAtual = transform.eulerAngles.y;
float anguloDesejado = alvo.transform.eulerAngles.y;
float angle = Mathf.LerpAngle(anguloAtual, anguloDesejado, Time.smoothDeltaTime * suavizar);
Quaternion rotacao = Quaternion.Euler(0, angle, 0);
transform.position = alvo.transform.position - (rotacao * offset);
transform.LookAt(alvo.transform.position + offsetVisao);
}
Referências
O vídeo de John Nesky, programador de câmeras de Journey, é uma ótima referência para discutir a diversidade de problemas que câmeras em jogos 3D podem criar, assim como suas possibilidades expressivas.