Jump to content
Sign in to follow this  
Antonio261

Problemas con la rotación de la cámara

Recommended Posts

Muy buenas. Tengo un problema con el que llevo unos días liado y no consigo resolver. Me pregunto si alguien podría ayudarme.

En esta StartCourutine, la cámara de mi personaje FPS centra la vista en un objetivo concreto y hace un zoom In. Tras pasar unos segundos, hace un zoom Out. Hasta aquí bien. El problema viene cuando al terminar de hacer este zoom out y volver a tener control sobre mi personaje, la cámara hace un giro muy brusco. He estado mirando por ahí y parece que esto se debe a que la cámara guarda la rotación anterior a cuando centra al objetivo. De manera que cuando vuelve, la cámara vuelve a la rotación original. Supongo que la solución está en guardar las coordenadas de esta rotación antes y establecerlas cuando termine el zoom out. Pero no sé cómo se hace. Si alguien pudiera ayudarme lo agradecería enormemente. Un saludo y gracias por leerme.

Aquí el script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityStandardAssets.Characters.FirstPerson;

public class centrarObjetivo : MonoBehaviour 
{
    public float segundos = 1f; 

    IEnumerator tiempoCentrarObjetivo ()
    {   
        GameObject.Find ("FPSController").GetComponent<CharacterController> ().enabled = false;    
        GameObject.Find ("FPSController").GetComponent<FirstPersonController> ().enabled = false;   
        Vector3 relativePos = new Vector3 (GameObject.Find ("objetivo").transform.position.x,     GameObject.Find ("objetivo").transform.position.y + 0f, GameObject.Find ("objetivo").transform.position.z) - GameObject.Find ("FirstPersonCharacter").transform.position;    
        Quaternion toRotation  = Quaternion.LookRotation (relativePos);    
        GameObject.Find ("FirstPersonCharacter").transform.rotation = Quaternion.Lerp (GameObject.Find ("FirstPersonCharacter").transform.rotation, toRotation, 2.5f * Time.deltaTime);    
        GameObject.Find ("FirstPersonCharacter").GetComponent<Camera> ().fieldOfView =     Mathf.Lerp (GameObject.Find ("FirstPersonCharacter").GetComponent<Camera> ().fieldOfView, 10f, Time.deltaTime * 0.2f); 
        yield return new WaitForSeconds (segundos * 4); 
        GameObject.Find ("FirstPersonCharacter").GetComponent<Camera> ().fieldOfView =    Mathf.Lerp (GameObject.Find ("FirstPersonCharacter").GetComponent<Camera> ().fieldOfView, 90f, Time.deltaTime * 3f); 
        yield return new WaitForSeconds (segundos * 2);   
        GameObject.Find ("FPSController").GetComponent<CharacterController> ().enabled = true;    
        GameObject.Find ("FPSController").GetComponent<FirstPersonController> ().enabled = true;
    }   

    void Update ()
    { 
        StartCoroutine ((tiempoCentrarObjetivo ()));
    }
}

 

Edited by Antonio261

Share this post


Link to post
Share on other sites

No puedes llamar a la corrutina en la función Update, esto te generará grandes problemas.

Primero empieza por solucionar eso, es decir, centrar la cámara al presionar una tecla concreta podría ser una solución.

void Update ()
{ 
  if (Input.GetKeyDown(KeyCode.F))
  	StartCoroutine ((tiempoCentrarObjetivo ()));
}

Evita usar GameObject.Find y GetComponent lo máximo posible, esto lo lograrás "cacheando" los valores en variables (guardando una referencia del objeto/instancia).

public class centrarObjetivo : MonoBehaviour 
{
    public float segundos = 1f; 

    private CharacterController m_characterController;
    private FirstPersonController m_firstPersonController;
    private Camera m_camera;
    private transform m_objetive;
    private Transform m_fisrtPersonCharacter;

    private void Start ()
    {
        m_characterController = GameObject.Find ("FPSController").GetComponent<CharacterController> ();
        m_firstPersonController = m_characterController.GetComponent<FirstPersonController> ();
        m_objetive = GameObject.Find ("objetivo").transform;
        m_fisrtPersonCharacter = GameObject.Find ("FirstPersonCharacter").transform;
        m_camera = m_fisrtPersonCharacter.GetComponent<Camera> ();
    }

    IEnumerator tiempoCentrarObjetivo ()
    {   
        m_characterController.enabled = false;    
        m_firstPersonController.enabled = false;   
        Vector3 relativePos = m_objetive - m_fisrtPersonCharacter.position;    
        Quaternion toRotation  = Quaternion.LookRotation (relativePos);    
        m_fisrtPersonCharacter.rotation = Quaternion.Lerp (m_fisrtPersonCharacter.rotation, toRotation, 2.5f * Time.deltaTime);    
        m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, 10f, Time.deltaTime * 0.2f); 
        yield return new WaitForSeconds (segundos * 4); 
        m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, 90f, Time.deltaTime * 3f); 
        yield return new WaitForSeconds (segundos * 2);   
        m_characterController.enabled = true;    
        m_firstPersonController.enabled = true;
    }   

    void Update ()
    { 
        if (Input.GetKeyDown (KeyCode.F))
            StartCoroutine ((tiempoCentrarObjetivo ()));
    }
}

Veo un par de cosas que están mal dentro de TiempoCentrarObjetivo, pero quizás tengas que pensar un poco más para encontrar la solución, así aprenderás seguro 😎

Share this post


Link to post
Share on other sites
34 minutes ago, francoe1 said:

No puedes llamar a la corrutina en la función Update, esto te generará grandes problemas.

Primero empieza por solucionar eso, es decir, centrar la cámara al presionar una tecla concreta podría ser una solución.


void Update ()
{ 
  if (Input.GetKeyDown(KeyCode.F))
  	StartCoroutine ((tiempoCentrarObjetivo ()));
}

Evita usar GameObject.Find y GetComponent lo máximo posible, esto lo lograrás "cacheando" los valores en variables (guardando una referencia del objeto/instancia).


public class centrarObjetivo : MonoBehaviour 
{
    public float segundos = 1f; 

    private CharacterController m_characterController;
    private FirstPersonController m_firstPersonController;
    private Camera m_camera;
    private transform m_objetive;
    private Transform m_fisrtPersonCharacter;

    private void Start ()
    {
        m_characterController = GameObject.Find ("FPSController").GetComponent<CharacterController> ();
        m_firstPersonController = m_characterController.GetComponent<FirstPersonController> ();
        m_objetive = GameObject.Find ("objetivo").transform;
        m_fisrtPersonCharacter = GameObject.Find ("FirstPersonCharacter").transform;
        m_camera = m_fisrtPersonCharacter.GetComponent<Camera> ();
    }

    IEnumerator tiempoCentrarObjetivo ()
    {   
        m_characterController.enabled = false;    
        m_firstPersonController.enabled = false;   
        Vector3 relativePos = m_objetive - m_fisrtPersonCharacter.position;    
        Quaternion toRotation  = Quaternion.LookRotation (relativePos);    
        m_fisrtPersonCharacter.rotation = Quaternion.Lerp (m_fisrtPersonCharacter.rotation, toRotation, 2.5f * Time.deltaTime);    
        m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, 10f, Time.deltaTime * 0.2f); 
        yield return new WaitForSeconds (segundos * 4); 
        m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, 90f, Time.deltaTime * 3f); 
        yield return new WaitForSeconds (segundos * 2);   
        m_characterController.enabled = true;    
        m_firstPersonController.enabled = true;
    }   

    void Update ()
    { 
        if (Input.GetKeyDown (KeyCode.F))
            StartCoroutine ((tiempoCentrarObjetivo ()));
    }
}

Veo un par de cosas que están mal dentro de TiempoCentrarObjetivo, pero quizás tengas que pensar un poco más para encontrar la solución, así aprenderás seguro 😎

Gracias por responder. La corrutina en el script original la llamo a través de un par de condiciones que se han de cumplir antes. Es que quería simplificarlo todo lo posible para centrar el problema y por ello lo he puesto tal cual en el Update.

De acuerdo, evitaré usar GameObject.Find y GetComponent y usaré variables. 

Me quedo un poco igual...¿Alguna pista? 😅

Share this post


Link to post
Share on other sites

Ayudaria mucho ver que pasa, pero imagino tienes un salto de la camara entre el fin de la corrutina y la posicion "normal" de juego, si es esto, yo iria devolviendo la camara a sus rotaciones originales segun hace el zoom out. Te pongo un ejemplo donde el Euler seria la posicion original de los angulos de la cam antes de todo el proceso.

m_camera.transform.rotation = Quaternion.Slerp(m_camera.transform.rotation, Quaternion.Euler( 0,-90,0), 0,1f * Time.deltaTime);}

 

Share this post


Link to post
Share on other sites
3 hours ago, rublo said:

Ayudaria mucho ver que pasa, pero imagino tienes un salto de la camara entre el fin de la corrutina y la posicion "normal" de juego, si es esto, yo iria devolviendo la camara a sus rotaciones originales segun hace el zoom out. Te pongo un ejemplo donde el Euler seria la posicion original de los angulos de la cam antes de todo el proceso.


m_camera.transform.rotation = Quaternion.Slerp(m_camera.transform.rotation, Quaternion.Euler( 0,-90,0), 0,1f * Time.deltaTime);}

 

Gracias por contestar. Intento recolocar la cámara en su rotación original pero me sigue dando el salto. He probado lo que me has dicho y nada.

He hecho un video para ilustrar el problema. Justo después del zoom out, la cámara bruscamente rota en la dirección que estaba inicialmente. Eso es lo que quisiera arreglar. Saludos.

Share this post


Link to post
Share on other sites

Seguro lo implementaste bien? te pongo un ejemplo, la primera linea solo guarda la orientacion de la cam, con la segunda tendrias que jugar con el valor 5 para que le de tiempo a aproximarse a sus angulos originales en el tiempo que hace el zoom out. No te aseguro mucho que este bien ya que no lo puedo probar y yo soy algo new aun en unity, pero creo este es el camino para reducir el salto.

IEnumerator tiempoCentrarObjetivo ()
        {   
            m_characterController.enabled = false;    
            m_firstPersonController.enabled = false;   
            Vector3 relativePos = m_objetive - m_fisrtPersonCharacter.position;    
            Quaternion toRotation  = Quaternion.LookRotation (relativePos);    
        
            Quaternion posicionOriginal = m_camera.transform.rotation;

            m_fisrtPersonCharacter.rotation = Quaternion.Lerp (m_fisrtPersonCharacter.rotation, toRotation, 2.5f * Time.deltaTime);    
            m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, 10f, Time.deltaTime * 0.2f); 
            yield return new WaitForSeconds (segundos * 4); 

            m_camera.transform.rotation = Quaternion.Slerp(m_camera.transform.rotation, posicionOriginal, 5 * Time.deltaTime);

            m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, 90f, Time.deltaTime * 3f); 
            yield return new WaitForSeconds (segundos * 2);   
            m_characterController.enabled = true;    
            m_firstPersonController.enabled = true;
        }   

 

Share this post


Link to post
Share on other sites

Yo creo que se está usando mal la corrutina, la única forma de que ese código funcione es llamarlo múltiples veces, esto es por que Lerp() se está llamando una única vez dentro de la corrutina.

Te mando un ejemplo de corrutina de como debería ser para que funcionara con 1 sola llama.

 

	IEnumerator tiempoCentrarObjetivol ()
    {   
        //Guardar rotación Original
        Quaternion originalRotation = m_fisrtPersonCharacter.rotation;
        //Guardar fieldOfView Original
        float originalFieldofView = m_camera.fieldOfView;

        //Desactivar interactividad del jugador
        m_characterController.enabled = false;    
        m_firstPersonController.enabled = false;   

        //Obtener el vector de dirección.
        Vector3 relativePos = m_objetive - m_fisrtPersonCharacter.position;    
        Quaternion toRotation  = Quaternion.LookRotation (relativePos);  
        float fieldOfViewTarget = 10;

        //ZOOM-IN
        {
            //Permanecer en este bucle si la rotación aun no esta completa o el campo de visión aun no llego a su target.
            while (Quaternion.Angle (m_fisrtPersonCharacter.rotation, toRotation) > 1 ||
                m_camera.fieldOfView > fieldOfViewTarget)
            {
                m_fisrtPersonCharacter.rotation = Quaternion.Lerp (m_fisrtPersonCharacter.rotation, toRotation, 2.5f * Time.deltaTime);    
                m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, fieldOfViewTarget, Time.deltaTime * 0.2f); 
                yield return null;
            }

            //Asignar los valores de forma directa para evitar que se empiecen a crear margenes en lo valores.
            m_fisrtPersonCharacter.rotation = toRotation;
            m_camera.fieldOfView = fieldOfViewTarget;  
        }

        //Tiempo para el Zoom-out
        yield return new WaitForSeconds (segundos * 4); 

        //ZOOM-OUT
        {
            //Permanecer en este bucle si la rotación aun no esta completa o el campo de visión aun no llego a su target.
            while (Quaternion.Angle (m_fisrtPersonCharacter.rotation, originalRotation) > 1 ||
                originalFieldofView > m_camera.fieldOfView)
            {
                m_fisrtPersonCharacter.rotation = Quaternion.Lerp (m_fisrtPersonCharacter.rotation, originalRotation, 2.5f * Time.deltaTime);    
                m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, fieldOfViewTarget, Time.deltaTime * 0.2f); 
                yield return null;
            }  

            //Asignar los valores de forma directa para evitar que se empiecen a crear margenes en lo valores.
            m_fisrtPersonCharacter.rotation = originalRotation;
            m_camera.fieldOfView = originalFieldofView;
        }

        //Activar interactividad del usuario
        m_characterController.enabled = true;    
        m_firstPersonController.enabled = true;
    }   



 

Share this post


Link to post
Share on other sites
15 hours ago, francoe1 said:

Yo creo que se está usando mal la corrutina, la única forma de que ese código funcione es llamarlo múltiples veces, esto es por que Lerp() se está llamando una única vez dentro de la corrutina.

Te mando un ejemplo de corrutina de como debería ser para que funcionara con 1 sola llama.

 


	IEnumerator tiempoCentrarObjetivol ()
    {   
        //Guardar rotación Original
        Quaternion originalRotation = m_fisrtPersonCharacter.rotation;
        //Guardar fieldOfView Original
        float originalFieldofView = m_camera.fieldOfView;

        //Desactivar interactividad del jugador
        m_characterController.enabled = false;    
        m_firstPersonController.enabled = false;   

        //Obtener el vector de dirección.
        Vector3 relativePos = m_objetive - m_fisrtPersonCharacter.position;    
        Quaternion toRotation  = Quaternion.LookRotation (relativePos);  
        float fieldOfViewTarget = 10;

        //ZOOM-IN
        {
            //Permanecer en este bucle si la rotación aun no esta completa o el campo de visión aun no llego a su target.
            while (Quaternion.Angle (m_fisrtPersonCharacter.rotation, toRotation) > 1 ||
                m_camera.fieldOfView > fieldOfViewTarget)
            {
                m_fisrtPersonCharacter.rotation = Quaternion.Lerp (m_fisrtPersonCharacter.rotation, toRotation, 2.5f * Time.deltaTime);    
                m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, fieldOfViewTarget, Time.deltaTime * 0.2f); 
                yield return null;
            }

            //Asignar los valores de forma directa para evitar que se empiecen a crear margenes en lo valores.
            m_fisrtPersonCharacter.rotation = toRotation;
            m_camera.fieldOfView = fieldOfViewTarget;  
        }

        //Tiempo para el Zoom-out
        yield return new WaitForSeconds (segundos * 4); 

        //ZOOM-OUT
        {
            //Permanecer en este bucle si la rotación aun no esta completa o el campo de visión aun no llego a su target.
            while (Quaternion.Angle (m_fisrtPersonCharacter.rotation, originalRotation) > 1 ||
                originalFieldofView > m_camera.fieldOfView)
            {
                m_fisrtPersonCharacter.rotation = Quaternion.Lerp (m_fisrtPersonCharacter.rotation, originalRotation, 2.5f * Time.deltaTime);    
                m_camera.fieldOfView = Mathf.Lerp (m_camera.fieldOfView, fieldOfViewTarget, Time.deltaTime * 0.2f); 
                yield return null;
            }  

            //Asignar los valores de forma directa para evitar que se empiecen a crear margenes en lo valores.
            m_fisrtPersonCharacter.rotation = originalRotation;
            m_camera.fieldOfView = originalFieldofView;
        }

        //Activar interactividad del usuario
        m_characterController.enabled = true;    
        m_firstPersonController.enabled = true;
    }   

Gracias por la aportación. Esto se parece más a lo que estaba buscando. Me da algún tironsillo durante el zoom out pero es cuestión de que analice todo y lo ajuste como es debido. Muchas gracias por la ayuda 🙂

 

 

Share this post


Link to post
Share on other sites
Sign in to follow this  

×
×
  • Create New...