Script de Câmera Orbital – Unity3D

Precisei fazer um app que usa intensamente uma câmera orbital e teria que rodar tanto em tablets quanto em desktop.
Pesquisei um monte, mas os scripts que achei sempre faltava algo, então juntei um coisa aqui uma ali e fiz um script até que bem completo.
Falta ainda fazer a câmera seguir um ponto em movimento e colidir com paredes etc, mas como não iria utilizar isso não fiz agora.
Uma breve descrição do que o script faz, tudo isso controlado por variáveis expostas e funções públicas:

  • Funciona tanto para mobile quanto desktop
  • Troca o ponto algo com ou sem smooth
  • Possibilidade de usar o botão direito ou esquerdo do mouse para rotacionar
  • Possibilidade de usar as setas do teclado para rotacionar
  • Zoom com scroll do mouse ou control + seta , 2 dedos no mobile , com velocidade controlavel
  • Seleção de quais eixos serão usados
  • Rotação com ou sem smooth , com velocidade controlável
  • Trava de ângulo nos eixos , para limitar a rotação
  • Trava de zoom mínimo e zoom máximo

Ainda tem alguns scripts de exemplo para trocar a rotação ou o ponto central, com várias opções para controle.

Contact Point é para centralizar o ponto da câmera aonde clicar no objeto e Seconds to Action funciona no mobile apenas, dedo por x segundos sobre o objeto/botão para ativar a ação.

O código fonte está bem comentado para facilitar.

Abaixo um link com um exemplo rodando e também um projeto com o código fonte.

DOWNLOAD CÓDIGO FONTE

EXEMPLO ONLINE

Vou colocar o código aqui escondido também

using UnityEngine;
using System.Collections;
/// <Descricao>
/// componente 'TransfereTargetCamera'
/// Esse é um script que gira a camera entorno de um ponto
/// Funcionalidades
/// Seleção de eixos para rotacionar
/// Rotação com ou sem desaceleração
/// Trava de angulos para rotação
/// Troca de eixo com ou sem desaceleração
/// Zoom com ou sem desaceleração
/// Metodo para ver se está sendo rotacionada a camera
/// Metodos para alterar os paramentros da camera
/// Versão para web/standalone e mobile
/// 
/// Autor: Daniel Almeida - daniel@immersive.com.br / daniel@compilamasnaoroda.com.br
/// Data: 02/12/2011
/// Versão 1
/// </Descricao>
public class CameraOrbitalMouse : MonoBehaviour
{
    //----------------------------------------------------------Variáveis PÚBLICAS------------------------------------------
    public bool mobile = false;
    //Objeto alvo, em torno dele que a camera girará
    public Transform target;
    //se deve seguir o objeto alvo
    //private bool followsTarget = false;
    //se precisa clicar para rotacionar
    public bool mouseClicked = true;
    //se setas do teclado giram a camera
    public bool arrowMode = false;
    public float arrowVelocityX = 1;
    public float arrowVelocityY = 1;
    public float arrowZoomVelocity = 1;

    //seleciona se rotacionará no angulo x,y, ou em ambos
    public enum MouseButtons : int { LEFT, RIGHT };
    public MouseButtons mouseButton;
    //seleciona se rotacionará no angulo x,y, ou em ambos
    public enum Axis : int { X, Y, XY };
    public Axis eixo;
    //Se movimento é com suavização
    public bool smooth = false;
    //tempo para dar o smooth
    public float smoothTime = 0.3f;
    //valores iniciais de rotação
    public float rotationX = 0.0f;
    public float rotationY = 0.0f;
    //limita a rotação no eixo X
    public float rotationMinX = -360.0f;
    public float rotationMaxX = 360.0f;
    //limita a rotação no eixo Y
    public float rotationMinY = -20f;
    public float rotationMaxY = 80f;
    //velocidade que terá a rotação
    public float rotationSpeedX = 250.0f;
    public float rotationSpeedY = 120.0f;
    //se terá zoom
    public bool zoomActive = true;
    //zoom inicial, minimo , maximo , velocidade e desacelaração do zoom
    public float zoom = 10.0f;
    public float zoomMin = 5.0f;
    public float zoomMax = 20.0f;
    public float zoomSpeed = 10.0f;
    public float zoomDampening = 5.0f;
    //----------------------------------------------------------Variáveis PRIVADAS------------------------------------------
    // private bool travaZoom = true;
    private float currentzoom;
    private float desiredzoom;
    //guarda o valor da posicao final do target
    private Vector3 targetPosition = Vector3.zero;
    //guarda o valor de x e y enquanto está interpolando
    private float xSmooth = 0.0f;
    private float ySmooth = 0.0f;
    //variaveis referencia para velocidade
    private float xVelocity = 0.0f;
    private float yVelocity = 0.0f;
    //smooth do reposicionamento
    private bool targetSmooth = false;
    private Vector3 posSmooth = Vector3.zero;
    private Vector3 posVelocity = Vector3.zero;
    //guarda se a câmera está sendo rotacionada pelo usuário
    private bool movingSmooth = false;
    private bool movingMouse = false;
    private Vector3 positionOld;
    private float lastMouseX;
    private float lastMouseY;
    private bool rotationLock = false;
    private bool travaZoom = true;

    //----------------------deletar tudo 
    public float zoomNearLimit = 5;
    public float zoomFarLimit = 12;
    public float zoomScreenToWorldRatio = 3.0f;
    public float orbitScreenToWorldRatio = 1.0f;
    public float twistScreenToWorldRatio = 5.0f;

    // don't change these
    Vector3 orbitSpeed = Vector3.zero;
    //float twistSpeed = 0;
    float distWeight = 0;
    float zoomDistance;
    // float zoomSpeedMobile = 0;
    float lastf0f1Dist;


    //----------------------------------------------------------EXECUTADO AO INICIAR----------------------------------------
    void Start()
    {
        //verifica se o target foi setado
        if (target == null)
        {
            Debug.LogWarning("O Target da câmera não foi setado, mantendo posição (0,0,0) para o target", gameObject);
        }
        else
        {
            targetPosition = target.position;
        }
        //faz toda válidação dos inputs do zoom
        if (zoomMin < 0)
        {
            Debug.LogWarning("Zoom mínimo menor que zero, alterando para o valor padrão = 0", gameObject);
            zoomMin = 0;
        }
        if (zoomMax < 0 || zoomMax < zoomMin)
        {
            Debug.LogWarning("Zoom máximo não pode ser menor que zero ou menor que o zoom mínimo, alterando para o valor zoomMin + 10", gameObject);
            zoomMax = zoomMin + 10;
        }
        if (zoom < zoomMin || zoom > zoomMax)
        {
            Debug.LogWarning("Zoom fora no range mínimo e máximo, alterando para o valor máximo", gameObject);
            zoom = zoomMax;
        }

        if (zoomDampening < 0)
        {
            Debug.LogWarning("zoomDampening < 0 causa o mesmo efeito do que = 0 , setando o valor para 0", gameObject);
            zoomDampening = 0;
        }

        if (zoomSpeed < 0)
        {
            Debug.LogWarning("zoomSpeed < 0 causa o mesmo efeito do que = 0 , setando o valor para 0", gameObject);
            zoomSpeed = 0;
        }

        //seta o zoom desejado e o zoom corrente        
        desiredzoom = zoom;
        currentzoom = zoom;

        // faz o rigidbody não afetar rotação
        if (rigidbody)
        {
            rigidbody.freezeRotation = true;
        }
        //inicia já na posição setada
        xSmooth = rotationX;
        ySmooth = rotationY;
        //inicializa posicoes
        posSmooth = target.position;
        //inicializa nas posicões passadas
        updatePosition();
        //pega a posicao inicial da camera
        positionOld = transform.position;
        //pega a posicao inicial do mouse
        lastMouseX = Input.GetAxis("Mouse X");
        lastMouseY = Input.GetAxis("Mouse Y");

    }
    //----------------------------------------------------------EXECUTADO UMA VEZ POR FRAME------------------------------------------
    // chamado uma x por frame
    void Update()
    {
       /* if (followsTarget) {
            if (target == null)
            {
                Debug.LogWarning("O Target da câmera não foi setado, mantendo posição (0,0,0) para o target", gameObject);
            }
            else
            {
                targetPosition = target.position;
            }
        }*/
    }
    void LateUpdate()
    {
        //Debug.Log("orbit x " + orbitSpeed.x + "    orbit y " + orbitSpeed.y);
        if (!mobile)
        {
            //verifica qual axe foi escolhido
            if (!mouseClicked || (Input.GetMouseButton(0) && (mouseButton == MouseButtons.LEFT)) || (Input.GetMouseButton(1) && (mouseButton == MouseButtons.RIGHT)) || (arrowMode && !Input.GetKey("left ctrl") && !Input.GetKey("right ctrl") && (Input.GetKey("up") || Input.GetKey("down") || Input.GetKey("left") || Input.GetKey("right"))))
            {

                if (((eixo == Axis.X) || (eixo == Axis.XY)) && !rotationLock)
                {
                    if (Input.GetKey("up") || Input.GetKey("down") || Input.GetKey("left") || Input.GetKey("right"))
                    {
                        
                            rotationX += (Input.GetKey("right") ? 1 : (Input.GetKey("left") ? -1 : 0)) * arrowVelocityX * rotationSpeedX * Time.deltaTime;
                       
                    }

                    else
                    {
                        //faz as contas no eixo x
                        rotationX += Input.GetAxis("Mouse X") * rotationSpeedX * Time.deltaTime;
                    }
                }
                if (((eixo == Axis.Y) || (eixo == Axis.XY)) && !rotationLock)
                {
                    if (Input.GetKey("up") || Input.GetKey("down") || Input.GetKey("left") || Input.GetKey("right"))
                    {                       
                            rotationY += (Input.GetKey("down") ? 1 : (Input.GetKey("up") ? -1 : 0)) * arrowVelocityY * rotationSpeedY * Time.deltaTime;
                      
                    }
                    
                    else
                    {
                        //faz as contas no eixo y
                        rotationY -= Input.GetAxis("Mouse Y") * rotationSpeedY * Time.deltaTime;
                    }
                }

                //verifica se o mouse está sendo movido
                movingMouse = (lastMouseX != Input.GetAxis("Mouse X") || lastMouseY != Input.GetAxis("Mouse Y"));
            }
            else
            {
                movingMouse = false;
            }
           
        }
        else
        {
            if (!rotationLock)
            {
                Touch f0;
                if (Input.touchCount == 1)
                {

                    // finger data
                    f0 = Input.GetTouch(0);

                    // finger delta
                    Vector3 f0Delta = new Vector3(f0.deltaPosition.x, -f0.deltaPosition.y, 0);

                    // if finger moving
                    if (f0.phase == TouchPhase.Moved)
                    {


                        // compute orbit speed
                        orbitSpeed += (f0Delta + f0Delta * distWeight) * Time.deltaTime;

                        rotationX = orbitSpeed.x * rotationSpeedX * 0.2f;
                        rotationY = orbitSpeed.y * rotationSpeedY * 0.3f;
                        movingMouse = true;
                    }
                }
                else if (Input.touchCount == 2)
                {
                    f0 = Input.GetTouch(0);
                    if (f0.phase == TouchPhase.Moved)
                    {
                        Touch touch2 = Input.touches[1];
                        desiredzoom = Vector2.Distance(f0.position, touch2.position);
                        if (travaZoom)
                        {
                            travaZoom = false;
                        }
                        else
                        {
                            zoom += (currentzoom - desiredzoom) * Time.deltaTime;
                        }
                        zoom = Mathf.Clamp(zoom, zoomMin, zoomMax);

                        currentzoom = desiredzoom;
                    }
                }
                else
                {
                    movingMouse = false;
                }
            }
            if (Input.touchCount != 2)
            {
                travaZoom = true;
            }
        }
        if (smooth)
        {
            //trava a rotação smooth nos limites
            if (rotationMinX != -360 && rotationMaxX != 360)
            {
                rotationX = Mathf.Clamp(rotationX, rotationMinX, rotationMaxX);
            }
            if (rotationMinY != -360 && rotationMaxY != 360)
            {
                rotationY = Mathf.Clamp(rotationY, rotationMinY, rotationMaxY);
            }

            xSmooth = Mathf.SmoothDamp(xSmooth, rotationX, ref xVelocity, smoothTime);
            ySmooth = Mathf.SmoothDamp(ySmooth, rotationY, ref yVelocity, smoothTime);
        }
        //se smooth do zoom ativo...
        if (zoomActive && !mobile)
        {

            if (arrowMode && (Input.GetKey("left ctrl") || Input.GetKey("right ctrl")) && (Input.GetKey("up") || Input.GetKey("down")))
            {
              
                    desiredzoom -= (Input.GetKey("down") ? -1 : (Input.GetKey("up") ? 1 : 0)) * Time.deltaTime * arrowZoomVelocity * zoomSpeed * Mathf.Abs(desiredzoom);
               
            }        
            else
            {
                desiredzoom -= Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * zoomSpeed * Mathf.Abs(desiredzoom);
            }

            //clamp the zoom min/max
            desiredzoom = Mathf.Clamp(desiredzoom, zoomMin, zoomMax);
            // For smoothing of the zoom, lerp zoom
            currentzoom = Mathf.Lerp(currentzoom, desiredzoom, Time.deltaTime * zoomDampening);
            zoom = currentzoom;
        }

        if (targetSmooth)
        {

            posSmooth = Vector3.SmoothDamp(posSmooth, targetPosition, ref posVelocity, smoothTime);
        }

        //pega a ultima posicao do mouse
        lastMouseX = Input.GetAxis("Mouse X");
        lastMouseY = Input.GetAxis("Mouse Y");

        updatePosition();

    }

    void updatePosition()
    {

        Quaternion rotation;
        Vector3 position;

        if (smooth)
        {
            //acerta os angulos para nao passarem de -360 ou 360
            //xSmooth = ClampAngle(xSmooth, rotationMinX, rotationMaxX);
            //ySmooth = ClampAngle(ySmooth, rotationMinY, rotationMaxY);
            //garante que o angulo esta no intervalor setado
            //pega a rotacao
            rotation = Quaternion.Euler(ySmooth, xSmooth, 0);
        }
        else
        {
            //acerta os angulos para nao passarem de -360 ou 360
            rotationX = ClampAngle(rotationX, rotationMinX, rotationMaxX);
            rotationY = ClampAngle(rotationY, rotationMinY, rotationMaxY);
            //garante que o angulo esta no intervalor setado
            //pega a rotacao
            rotation = Quaternion.Euler(rotationY, rotationX, 0);
        }
        //faz a conta da posicao
        if (targetSmooth)
        {
            position = rotation * new Vector3(0.0f, 0.0f, -zoom) + posSmooth;
        }
        else
        {
            position = rotation * new Vector3(0.0f, 0.0f, -zoom) + targetPosition;
        }

        //seta nos valores
        transform.rotation = rotation;
        transform.position = position;

        //se está sendo movida a camera
        movingSmooth = positionOld != transform.position;       

        positionOld = transform.position;
    }

    float ClampAngle(float angle, float min, float max)
    {
        //acerta os angulos para nao passarem de -360 ou 360
        if (angle < -360)
            angle += 360;
        if (angle > 360)
            angle -= 360;
        //garante que o angulo esta no intervalor setado
        return Mathf.Clamp(angle, min, max);
    }
    //----------------------------------------------------------METODO setTarget------------------------------------------
    //Esse método serve para se passar um novo target para a câmera
    //deve ser informado se terá transição de uma posição para outra ou se o corte será seco
    //Parametros : novaPosicao(Vector3, transform ou gameObject)
    //             smoothly (bool)
    public void setTarget(Vector3 novaPosicao, bool smoothly = false)
    {
        targetPosition = novaPosicao;
        targetSmooth = smoothly;
        //se não for para ter suavidade sincroniza o ponto inicial e final, isso previne que se clicar em um objeto que tem o smooth
        //ele partirá do ponto corrente.
        if (!targetSmooth)
        {
            posSmooth = targetPosition;
        }
    }
    //sobrecarga para o metodo setTarget
    public void setTarget(Transform novaPosicao, bool smoothly = false)
    {
        setTarget(novaPosicao.position, smoothly);
    }
    //sobrecarga para o metodo setTarget
    public void setTarget(GameObject novaPosicao, bool smoothly = false)
    {
        setTarget(novaPosicao.transform.position, smoothly);
    }
    //----------------------------------------------------------METODO isMoving------------------------------------------
    //metodo usado para saber se a camera está girando
    //parametro affectedSmooth = true pega se a camera está em movimento (usuário ou smooth movendo)
    //parametro affectedSmooth = false pega se a camera está em movimento (apenas o usuário a movendo)
    public bool isMoving(bool affectedSmooth = false)
    {
        if (affectedSmooth)
        {
            return movingSmooth;
        }
        else
        {
            return movingMouse;
        }

    }
    //----------------------------------------------------------METODO setRotation------------------------------------------
    public void setRotation(float newRotationX, float newRotationY, bool smoothly)
    {
        //pega o valor no range de -360 a 360
        float rotationXNormalizado = rotationX % 360;
        float rotationYNormalizado = rotationY % 360;
        //apara as arestas
        rotationX = ClampAngle(newRotationX, rotationMinX, rotationMaxX);
        rotationY = ClampAngle(newRotationY, rotationMinY, rotationMaxY);
        //pega o valor no range de -360 a 360
        xSmooth = xSmooth % 360;
        ySmooth = ySmooth % 360;

        //clipa a rotação para pegar o caminho mais perto do ponto de destino
        if (rotationX - rotationXNormalizado > 180)
        {
            rotationX -= 360;
        }
        else if (rotationX - rotationXNormalizado < -180)
        {
            rotationX += 360;
        }
        //clipa a rotação para pegar o caminho mais perto do ponto de destino
        if (rotationY - rotationYNormalizado > 180)
        {
            rotationY -= 360;
        }
        else if (rotationY - rotationYNormalizado < -180)
        {
            rotationY += 360;
        }
        //se mudança a seco, iguala a variavel de smooth
        if (!smoothly)
        {
            xSmooth = rotationX;
            ySmooth = rotationY;
        }
    }

    public void setZoom(float _zoom)
    {
        desiredzoom = Mathf.Clamp(_zoom, zoomMin, zoomMax);
    }

    //----------------------------------------------------------METODO setRotationAndLock------------------------------------------
    //faz o mesmo que setrotation mas manda travar a rotação 
    public void setRotationAndLock(float newRotationX, float newRotationY, bool smoothly, bool rotationLock)
    {
        setRotation(newRotationX, newRotationY, smoothly);
        doLockRotation(rotationLock);
    }
    //----------------------------------------------------------METODO doLockRotation------------------------------------------
    //faz o mouse não rotacionar mais a camera
    public void doLockRotation(bool rotationLock)
    {
        this.rotationLock = rotationLock;
    }

    //----------------------------------------------------------METODO doLockZoom------------------------------------------
    //faz o mouse não dar mais zoom na camera
    public void doLockZoom(bool zoomLock)
    {
        zoomActive = !zoomLock;
    }
}

using UnityEngine;
using System.Collections;

/// <Descricao>
/// componente 'TransfereTargetCamera'
/// Este script deve ser usado em conjunto com o script CameraOrbitalMouse.cs,
/// Ele envia uma nova posição para o target e diz se deve ser com transição ou se já troca
/// de lugar na hora.
/// </Descricao>
[AddComponentMenu("Scripts/TransfereTargetCamera")]
public class TransfereTargetCamera : MonoBehaviour
{
    //camera que será afetada
    public Camera cameraTarget;
    public bool smooth = false;
    public enum MouseButtons : int { LEFT, RIGHT };
    public MouseButtons mouseButton;
    public Transform useObjectPosition;
    public Vector3 targetPosition = Vector3.zero;
    public bool contactPoint;
    public float secondsToAction = 2;
    private float contadorTempo = 0;
    private bool contando = false;

    void Start()
    {

    }

    void update()
    {

    }

    void OnMouseOver()
    {
        if ((Input.GetMouseButton(0) && (mouseButton == MouseButtons.LEFT)) || (Input.GetMouseButton(1) && (mouseButton == MouseButtons.RIGHT)))
        {
            if (cameraTarget && !contactPoint && !cameraTarget.GetComponent<CameraOrbitalMouse>().mobile)
            {
                // Debug.DrawLine(collider.con)
                cameraTarget.GetComponent<CameraOrbitalMouse>().setTarget(useObjectPosition != null ? useObjectPosition.position : targetPosition, smooth);
            }
        }
    }

    void Update()
    {
        if (cameraTarget.GetComponent<CameraOrbitalMouse>().mobile)//acoes para mobile
        {
            Touch f0;

            if (Input.touchCount >= 1)
            {

                // finger data
                f0 = Input.GetTouch(0);


                // if finger moving
                if (f0.phase == TouchPhase.Began)
                {
                    contadorTempo = 0;
                    contando = true;
                }
                else if (f0.phase == TouchPhase.Ended || f0.phase == TouchPhase.Canceled || f0.phase == TouchPhase.Moved)
                {
                    contando = false;
                }
            }


            if (contando)
            {
                contadorTempo += Time.deltaTime;

                if (contadorTempo >= secondsToAction)
                {
                    Ray ray = Camera.main.ScreenPointToRay(new Vector3(f0.position.x, f0.position.y, 0)); // Construct a ray from the current mouse coordinates

                    RaycastHit hit;

                    if (Physics.Raycast(ray, out hit))
                    {
                        cameraTarget.GetComponent<CameraOrbitalMouse>().setTarget(hit.point, smooth);
                        Debug.Log("atiraaa", gameObject);
                    }

                    cameraTarget.GetComponent<CameraOrbitalMouse>().setTarget(hit.point, smooth);
                    contando = false;
                    contadorTempo = 0;
                }
            }
        }
        else//acoes para standalone / web
        {

            if (((Input.GetMouseButton(0) && (mouseButton == MouseButtons.LEFT)) || (Input.GetMouseButton(1) && (mouseButton == MouseButtons.RIGHT))) && contactPoint)
            {

                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); // Construct a ray from the current mouse coordinates

                RaycastHit hit;

                if (Physics.Raycast(ray, out hit))
                {
                    if (hit.collider.gameObject == gameObject)
                    {
                        cameraTarget.GetComponent<CameraOrbitalMouse>().setTarget(hit.point, smooth);
                    }
                }
            }
        }
    }
}

using UnityEngine;
using System.Collections;

/// <Descricao>
/// componente 'SetaNovaRotacao'
/// </Descricao>
[AddComponentMenu("Scripts/SetaNovaRotacao")]
public class SetaNovaRotacao : MonoBehaviour
{

    //camera que será afetada
    public Camera cameraTarget;
    public float rotationX = 0;
    public float rotationY = 0;
    public bool smooth = false;
    
    void Start()
    {

    }

    void OnMouseDown()
    {
        if (cameraTarget)
        {
            cameraTarget.GetComponent<CameraOrbitalMouse>().setRotation(rotationX, rotationY, smooth );
            
        }
    }   
}

using UnityEngine;
using System.Collections;

/// <Descricao>
/// componente 'SetaNovaRotacao'
/// </Descricao>
[AddComponentMenu("Scripts/SetaNovaRotacao")]
public class SetaNovaRotacaoTrava : MonoBehaviour
{

    //camera que será afetada
    public Camera cameraTarget;
    public float rotationX = 0;
    public float rotationY = 0;
    public bool smooth = false;
    public bool rotationLock = false;
    void Start()
    {

    }

    void OnMouseDown()
    {
        if (cameraTarget)
        {
            cameraTarget.GetComponent<CameraOrbitalMouse>().setRotationAndLock(rotationX, rotationY, smooth , rotationLock);
            
        }
    }
}

Share

10 Comments

  • yuri |

    Boa tarde!
    Esta de parabens com os posts … faço designer de games na FMU e a materia mais puxada é unity. Acabei pegando uns uns scripts aqui, outros ali e juntando com os meus … esta servindo de muita ajuda. O melhor de tudo é que os scripts são em C#.
    Mais uma vez, parabens e obrigado por compartilha.

  • Daniel |

    Fala Yuri , fico feliz que está ajudando , estou voltando a postar coisas no blog , fiquei um tempo fora mas agora vou continuar.
    até mais
    Daniel

  • Fernando |

    Parabéns pelas dicas! Sua didática é ótima!!
    Só tenho dois problemas (he hee). Quando clico em “play” no Unity, a câmera fica muito perto, e se controlo no foco (perspectiva) distorce (grande angular). Como afastar a câm no script?
    E outra… preciso girar na diagonal tbm (tilt). poderia, por gentileza, mostrar como?

  • Daniel |

    Fala Fernando beleza?
    Cara para acertar o zoom basta colocar o valor desejado na variável zoom, que deve estar entre Zoom Min e Zoom Max.
    Quanto ao Tilt não está implementado nessa câmera, ela só rotaciona no eixo X e Y.
    até mais
    Danil

  • Marcelo Diniz |

    Amigo, baixe o sei código, mas os objetos vinheram sem as referencias dos scripts. Será que fiz alguma coisa errada? como faço para abrir o seu código aqui em meu PC ?

  • Daniel |

    É um projeto normal, basta mandar abrir o projeto no seu unity.

  • Rhenan |

    Muito bom cara! parabens!

    Só gostaria de fazer uma coisa e não estou conseguindo, queria fazer com que cada vez que eu pressionasse uma seta, a camera fizesse uma rotação de 90º para o sentido da seta, mas só uma vez

So, what do you think ?