Jump to content
TRaFuGa

ANSWERED Mover Cámara entre pantallas (1 Solución)

Recommended Posts

Hola, he estado buscando por el foro e internet pero no he visto nada parecido a lo que quiero hacer.

Tengo un mapa de 4x5 pantallas (dentro de una misma scene) con un tamaño establecido y fijo para cada pantalla (todas el mismo), el caso es que quiero hacer un sistema de cambio de pantalla (al pasar a la izquierda, derecha, arriba o abajo) y que la cámara se mueva y se ajuste a dicha pantalla (el efecto no es de mover, sino de cambiar, porque se le asignan las nuevas coordenadas a la cámara).

El problema que tengo es en el proceso de cambio de pantalla (traspaso de pantalla del jugador). Tengo un trigger (con un edge collider, vertical u horizontal) y he probado dos formas de hacer el movimiento (que esto lo hace bien, pero el problema lo tengo al controlar cuando se hace...):

-Pongo un trigger en cada zona de salida, con el edge collider pegado casi al final del tile, para asegurarme de que cuando traspasa dicho collider haga el cambio de pantalla que le he establecido por parámetros (por ejemplo, hacia la derecha) y controlando la dirección del personaje, de esta forma si pasa al contrario (ej: hacia la izquierda) no hace nada.

-Pongo un solo trigger en el medio de los 2 tiles que dividen las pantallas, y dependiendo de la dirección del personaje muevo la cámara a dicha dirección. (Esta es la opción que tengo ahora, me parece más limpia, al tener menos triggers en el mapa)

¿El problema? Si voy ajustando el personaje despacito (y a veces no hace falta que vaya muy despacio), dicho cambio de cámara no se hace, o se hace doble... vamos, que funciona bien cuando quiere...

En la captura se ve la zona de cambio (en este caso es de izquierda-derecha) y el trigger en verde en el medio

 captura.png

Y este es el código del script asociado:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerOutCam : MonoBehaviour
{
    public enum direc
    {
       UP, DOWN, LEFT, RIGHT 
    }

    public Camera Cam;
    public GameObject Player;
    public float CamHeigh=368f;
    public float CamWidth = 208f;

    //public direc Direccion = direc.UP;

    private int percent = 100;
    private Vector3 direction;
    private void Awake()
    {
        if (Player == null)
        {
            Player = GameObject.FindWithTag("Player");
        }

        if (Cam == null)
        {
            Cam = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
        }
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {

    }
    private void OnTriggerEnter2D(Collider2D collision)
    {


    }
 
    private void OnTriggerExit2D(Collider2D collision)
    {
        direction = Player.transform.position - transform.position;
        //Debug.Log(direction.y);

        if (collision.gameObject.tag=="Player")
        {
            //bug.Log("Player.x: " + Player.transform.position.x);
            //Debug.Log("Triger.x " + this.gameObject.name + ":"  + transform.position.x);

            float horizontalInput = Input.GetAxisRaw("Horizontal");
            float vertical = Input.GetAxisRaw("Vertical");
            Debug.Log("Direction: " + direction.x + " H: " + horizontalInput);
            if  (direction.x < 0f && horizontalInput < 0f) //IZQUIERDA
            {
                Cam.transform.position = new Vector3(Cam.transform.position.x - (CamHeigh / percent), Cam.transform.position.y, Cam.transform.position.z);
            }

            if (direction.x > 0f && horizontalInput > 0f) //DERECHA
            {
                Cam.transform.position = new Vector3(Cam.transform.position.x + (CamHeigh / percent), Cam.transform.position.y, Cam.transform.position.z);
            }

            if (direction.y < 0f && vertical < 0f)//ABAJO
            {
                Cam.transform.position = new Vector3(Cam.transform.position.x, Cam.transform.position.y - (CamWidth / percent), Cam.transform.position.z);
            }

            if (direction.y > 0f && vertical >0f)//ARRIBA
            {
                Cam.transform.position = new Vector3(Cam.transform.position.x, Cam.transform.position.y + (CamWidth / percent), Cam.transform.position.z);
            }

            //Recuperamos todos los SpawnPoint de la escena
            GameObject[] spawn = GameObject.FindGameObjectsWithTag("SpawnPoint");

            //Comprobamos que haya al menos 1 en la escena
            if (spawn != null)
            {
                //Por cada SpawnPoint de la escena hacemos las siguientes comprobaciones
                foreach (GameObject goSpawn in spawn)
                {
                    //Creamos un punto que va desde la cámara hasta la posición del SpawnPoint
                    Vector3 screenPoint = Cam.WorldToViewportPoint(goSpawn.transform.position);
                    //Controlamos que el punto esté dentro de la visión de la cámara que será un rectángulo
                    //que va desde 0-1 en su eje X y de 0-1 en su eje Y
                    if (screenPoint.x>0 && screenPoint.x <1 && screenPoint.y>0 && screenPoint.y<1)
                    {
                        //En el caso de que este punto esté dentro de la visión
                        //Se lo asignamos al Player como punto de Spawn
                        Player.GetComponent<PlayerController>().SpawnPoint = goSpawn;
                        //Retornamos y dejamos de buscar.
                        return;
                    }
                }
            }
        }
    }

}

El movimiento de la cámara funciona bien, lo que no me funciona correctamente es el ajuste de cuando se hace acorde al trigger que tengo, tampoco se si es la mejor manera de hacer algo de esto...

A mayores, gestiono el punto de respawn del jugador, esto me funciona correctamente, aunque como siempre, lo mismo no es la mejor forma de hacerlo.

Edited by TRaFuGa
Encontrada solución

Share this post


Link to post
Share on other sites

Podrías optar por crear un Rectángulo (imaginario) para el "Player" y otro para "Final" luego en cada rectángulo final pondrías un componente que haga una comprobación AABB con el rect del Player, de este modo evitas utilizar físicas y omitís muchos problemas que esto conlleva.   

Share this post


Link to post
Share on other sites

Te refieres a hacerle un cuadrado (un collider?) para el personaje y otro para la entrada/salida de la pantalla? y comprobar si está dentro y se ha salido por uno de los lados??

 

Share this post


Link to post
Share on other sites

Nop, me refiero a que no es necesario usar colisiones, simplemente definiendo la posición y tamaño de dos rectángulos podes hacer una comprobación AABB para saber si están colisionando.

Share this post


Link to post
Share on other sites

también puedes usar un Distance y según la distancia que hay entre el personaje y el centro de la cámara empezar a trabajar   

Share this post


Link to post
Share on other sites
14 hours ago, nomoregames said:

también puedes usar un Distance y según la distancia que hay entre el personaje y el centro de la cámara empezar a trabajar   

Pues me parece buena idea, sabiendo el tamaño de la pantalla se puede hacer perfectamente, y así se controla si se ha salido por alguna de los 4 lados. Voy a intentarlo y os cuento.

EDIT: Con una primera versión del movimiento, he conseguido que funcione mucho mejor que antes aunque tengo que seguir con las pruebas.

Lo que hice fue sacar los límites de la cámara y según la X/Y del jugador, ya puedo controlar si se ha pasado por alguno de los lados y mover la cámara acorde a por dónde se ha salido, luego recupera nuevos límites. Aún tengo que pulirlo, sobre todo para buscar una solución a no tener que estar controlando las posiciones x e y del jugador en cada update 🙂

Edited by TRaFuGa

Share this post


Link to post
Share on other sites

Voy a dejar el código del script por si a alguno le viene bien. Conseguí un trozo de internet que he usado:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerInCam : MonoBehaviour
{
    public Camera Cam; //Cámara que vamos a usar para hacer el movimiento 
    public float CamHeigh=368f; //Tamaño de la cámara
    public float CamWidth = 208f;
 
    enum Direction {Left, Right, Up, Down}; //Enum para controlar a que dirección mover
 
    public bool mov = false; //Bool para controlar si estamos haciendo el movimiento de la cámara para no hacerlo doble
    private int percent = 100;//Porcentaje para ajustar el movimiento de la cámara
    private Limits val; //Valores de los límites de la pantalla
    private Transform _GameObject; //GameObject del personaje
    // Start is called before the first frame update
    void Start()
    {
        GetLimits(); //Recojemos la primera vez los límites de la pantalla
        _GameObject = GetComponent<Transform>();//Asignamos el transform del gameobject del player
 
        if (Cam == null) //En el caso de no haber asignado cámara, buscamos la maincamera
        {
            Cam = GameObject.FindWithTag("MainCamera").GetComponent<Camera>();
        }
    }
 
    // Update is called once per frame
    void Update()
    {
 
        checkOutCam();//Método que comprueba si el player se ha salido de los límites de la cámara
        //if (!mov)
         //  Debug.Log("Player:" + _GameObject.position.x + ":" + _GameObject.position.y );
 
    }
    void checkOutCam(){
        //Comprobamos si se ha salido desde algun lado de los límites y la cámara no se está moviendo
        
 
        //En el caso de que entre en algunos de los controles
        //Marcamos a true el movimiento y movemos la cámara en la dirección que deseamos
        if (_GameObject.position.< val.Left  && !mov)
        {
            //Debug.Log("LEFT");
            mov = true;
            MoveCam(Direction.Left);
        }
 
        if (_GameObject.position.> val.Right  && !mov)
        {
            //Debug.Log("RIGHT");
            mov = true;
            MoveCam(Direction.Right);
        }
 
        if (_GameObject.position.< val.Bottom)
        {
            //Debug.Log("DOWN: " + _GameObject.position.y);
            mov = true;
            MoveCam(Direction.Down);
        }
 
        if (_GameObject.position.> val.Top)
        {
           //Debug.Log("UP: " + _GameObject.position.y);
            mov = true;
            MoveCam(Direction.Up);
        }
 
    }



     private Limits GetLimits()
    {
        val=new Limits();//Generamos unos nuevos límites
        Vector3 lowerLeft = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0)); //Recogemos el punto AbajoIzquierda
        Vector3 upperRight = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0)); //Recogemos el punto ArribaDerecha
        //Con estos dos puntos, ya tenemos marcados los límites de la pantalla, recogiendo dichos límites en la variable
        val.Left = lowerLeft.x;
        val.Right = upperRight.x;
        val.Top = upperRight.y;
        val.Bottom = lowerLeft.y;
        //Debug.Log("Limits: " + val.Left +"|||" + val.Right + "|||" + val.Top + "|||" + val.Bottom);
        return val;
    }
 
    private void MoveCam(Direction dir){
        //Movemos la cámara hacia la posición indicada
        switch (dir)
        {
            case Direction.Left:
                Cam.transform.position = new Vector3(Cam.transform.position.- (CamHeigh / percent), Cam.transform.position.y, Cam.transform.position.z);
                break;
            case Direction.Right:
                Cam.transform.position = new Vector3(Cam.transform.position.+ (CamHeigh / percent), Cam.transform.position.y, Cam.transform.position.z);
                break;
            case Direction.Down:
                Cam.transform.position = new Vector3(Cam.transform.position.x, Cam.transform.position.- (CamWidth / percent), Cam.transform.position.z);
                break;
            case Direction.Up:
                Cam.transform.position = new Vector3(Cam.transform.position.x, Cam.transform.position.+ (CamWidth / percent), Cam.transform.position.z);
                break;
        }
             GetLimits();//Volvemos a recoger los límites de la pantalla, ya que habrán cambiado con respecto al WorldSpace
             GetSpawnPoint();//Recogemos el punto de Spawn que hay en la pantalla
             mov = false;//Volvemos a poner a false el booleano para que si volvemos a cambiar de pantalla, se puedan hacer las comprobaciones
    }
 
    void GetSpawnPoint(){
 
            //Recuperamos todos los SpawnPoint de la escena
            GameObject[] spawn = GameObject.FindGameObjectsWithTag("SpawnPoint");
 
            //Comprobamos que haya al menos 1 en la escena
            if (spawn != null)
            {
                //Por cada SpawnPoint de la escena hacemos las siguientes comprobaciones
                foreach (GameObject goSpawn in spawn)
                {
                    //Creamos un punto que va desde la cámara hasta la posición del SpawnPoint
                    Vector3 screenPoint = Cam.WorldToViewportPoint(goSpawn.transform.position);
                    //Controlamos que el punto esté dentro de la visión de la cámara que será un rectángulo
                    //que va desde 0-1 en su eje X y de 0-1 en su eje Y
                    if (screenPoint.x>0 && screenPoint.<1 && screenPoint.y>0 && screenPoint.y<1)
                    {
                        //En el caso de que este punto esté dentro de la visión
                        //Se lo asignamos al Player como punto de Spawn
                        this.GetComponent<PlayerController>().SpawnPoint = goSpawn;
                        //Retornamos y dejamos de buscar.
                        return;
                    }
                }
            }
    }
 
    public class Limits
    {
     public float Left { get; set; }
     public float Right { get; set; }
     public float Top { get; set; }
     public float Bottom { get; set; }
    }
 
}

Seguramente no sea la mejor opción el controlar en cada Update las coordenadas del Player para ver si se ha salido de los límites, pero no encontré ningún método que se ejecutara cuando el Player queda fuera de la visión de la cámara.

Share this post


Link to post
Share on other sites

×
×
  • Create New...