Unity3D: Uma cena, várias câmeras
Uma das coisas bacanas nos jogos, principalmente os de corrida, é ter mais de uma opção de câmera com visões diferentes e até mesmo enxergando novos objetos, texturas, cores.
Existem vários tipos de ciclo de câmera, mas o que vou atacar aqui é um básico que já é caminho para resolver jogos de corrida e reposicionamento genérico da câmera.
TLDR: Ei tem certeza que não prefere ler? Se você só quer o script clica aqui
Passo 1: Criando a cena
Crie um projeto no Unity ou uma nova cena se quiser usar um projeto existente.
Dentro da cena tenha:
- Câmera
- Caso seja uma cena vazia adicione um objeto para ponto de referência, ex: box.
- Game objects vazios para representar novas posições de câmera, quantos forem necessários. Dêem nomes decentes para não se perder, ex: posição fora, posição dentro, posição sob ombro.
Dica: Eu costumo usar nomenclatura toda em inglês, isso ajuda na prática da lingua e na hora de buscar ajuda em fóruns.
Passo 2: O SCRIPT
Existem duas formas dessa idéia funcionar, uma delas é o script ficar na câmera que será alterada, a outra é o script aceitar a câmera como propriedade. Eu segui com o script fazendo parte da câmera, assim podemos pensar em coisas como split-screen com jogadores mudando suas câmeras individualmente mais facilmente.
Crie um script, eu dei o nome no meu de VNCameraSwitch, e adicione-o a sua câmera.
Começando: posição inicial
Vamos precisar ter acesso aos game objects de posições, mas não precisamos do GameObject em si mas sim do seu Transform.
Além dele teremos a posição atual e vamos guardar também a tecla usada para trocar entre as câmeras. Escolhi o número 2 no teclado númerico perto dos F's, porque? Porque 2 lembra base dois 😎.
public class VNCameraSwitch : MonoBehaviour {
public Transform[] positions;
public int currentPosition = 0;
public KeyCode switchKey = KeyCode.Alpha2;
Dica: Deixar as variáveis públicas faz com que elas fiquem disponíveis na UI do Unity para serem modificadas no objeto da cena.
Assim que o script rodar precisamos colocar a câmera na posição inicial caso exista alguma posição a ser utilizada. Vamos alterar diretamente o position e rotation do transform da câmera com a posição atual (currentPosition).
private void SetCameraInitialPosition() {
if (positions.Length > 0) {
updateCameraPosition ();
}
}void updateCameraPosition() {
transform.rotation = positions[currentPosition].rotation;
transform.position = positions[currentPosition].position;
}void Start()
{
SetCameraInitialPosition ();
}
Com isso se adicionarmos os game objects na lista de posições e rodarmos a cena o script já vai posicionar a câmera no primeiro local.
Sequência: fazendo um ciclo com as posições
Agora vamos usar o Update do script para mudar entre as posições, é um ciclo então andamos nas posições começando da atual e indo até a última posição na lista de 1 em 1.
Dica: Uma alternativa seria atribuir uma câmera para uma determinada tecla e ao invés de ciclo trocar de acordo com a tecla.
void Update()
{
if (Input.GetKeyUp (switchKey) && if (isEqualsToCameraPosition (positions[currentPosition])) {
currentPosition++;
currentPosition = currentPosition % positions.Length;
updateCameraPosition ();
}
}
Eita pera ai que diabos é isso: currentPosition = currentPosition % positions.Length;?
O operador modulo (mod), representado pelo sinal %, pega o resto da divisão de dois números. Como as listas vão de 0 até Length-1, então quando um número chegar em Length e for divido por ele mesmo a posição reseta para 0.
Outra coisa que não fizemos ainda foi esse método isEqualsToCameraPosition. O que ele faz? Ele verifica se o transform é igual a posição que deveria ser a atual, fazemos isso pois assim só trocamos de posição quando realmente a câmera está onde deveria, vai ser ainda mais útil logo menos.
bool isEqualsToCameraPosition(Transform currentPosition) {
return transform.position == currentPosition.position &&
transform.rotation == currentPosition.rotation;
}
Se rodar agora você conseguirá ver a câmera mudar entre as posições a cada toque na tecla.
O bônus: animando entre câmeras
Tudo muito bonito mas muito seco. É possível animar a câmera indo de um ponto a outro, para isso vamos precisar alterar um pouquinho a posição antiga em direção a desejada posição atual. Esse pouquinho vamos chamar de speed e essa variável será modificada em função do tempo do update, isso evita problemas entre velocidades diferentes entre computadores pontentes e menos potentes.
public float speed = 20f;
public animate = true;
Adicionemos um novo método que vai usar a velocidade e jogar a posição atual da câmera um pouco mais próxima da posição desejada.
void IncrementPosition () {
// O Time.deltaTime é o intervalo entre
float delta = speed * Time.deltaTime;
Transform endPosition = positions [currentPosition];
// Podemos usar o Lerp ou MoveTowards o resultado é o mesmo, andar o vetor atual um pouco mais próximo de seu vetor destino
Vector3 nextPosition = Vector3.MoveTowards (transform.position, endPosition.position, delta);
Quaternion nextRotation = Quaternion.RotateTowards(transform.rotation, endPosition.rotation, delta);
// Atualizamos a posição da câmera
transform.position = nextPosition;
transform.rotation = nextRotation;
}
O IncrementPosition deve ser usado no Update logo após o if do Input. Aproveite e cancele o updateCameraPosition se estiver usando o modo animado.
void Update() {
if (Input.GetKeyUp (switchKey) && isEqualsToCameraPosition (positions[currentPosition])) {
currentPosition++;
currentPosition = currentPosition % positions.Length;
if (!useAnimation) {
updateCameraPosition ();
}
}
if (useAnimation && !isEqualsToCameraPosition (positions [currentPosition])) {
IncrementPosition ();
}
}
Porque não consigo mudar de câmera no meio da animação? Lembra que o isEqualsToCameraPositio ia ser útil? Propositalmente só permitimos a mudança quando a câmera está na posição exata de onde deveria, e isso acontece apenas no fim da animação.
A partir de hoje suas câmeras vâo ficar muito mais interessantes. E aí fez diferente? Adicionou algo? Conte-nos sua experiência com câmeras no Unity nos comentários.