Autor Tema: Detener sprite cuando colisiona Unity2d  (Leído 133 veces)

Middrel

  • New Jammer
  • *
  • Mensajes: 5
  • Molas: 0
Detener sprite cuando colisiona Unity2d
« en: 26 de Abril de 2017, 06:14:04 am »
Hola, buenas noches,

Estaba viendo algunos comentarios que hicieron en un post algo antiguo sobre colisiones, mencionaban que no usar la física de Unity, sino más bien trabajar con Raycast + Colisiones.

Como estoy iniciando en Unity, 2D sobre todo, estaba tratando de conseguir que un sprite que muevo (player) al llegar a un muro se detenga completamente, pero no lo he conseguido, quizá tenga que ver con lo que comentaban en ese tema: http://foro.malagajam.com/index.php?topic=121.msg1579#msg1579

Mi código es el siguiente:

Código: [Seleccionar]
public class PlayerController : MonoBehaviour {
 
    public float speed;
    private Vector3 target;
    private Vector3 target_rot;
 
    private bool sprite;
    public Rigidbody2D r2bd;
 
    public int turn = 0;
   
    void Start()
    {
        target = transform.position;
        r2bd = GetComponent<Rigidbody2D>();
 
    }
   
    void Update()
    {
        sprite = true;
 
        if (Input.GetMouseButtonDown(0))
        {
            if (turn == 0) {
                if (sprite)
                {
                    target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                    target.z = transform.position.z;
                    target_rot = Camera.main.ScreenToWorldPoint(Input.mousePosition);
                }
            }
            turn = 1;
        }
        transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
        var angle = Mathf.Atan2(target_rot.y - transform.position.y, target_rot.x - transform.position.x) * Mathf.Rad2Deg;
        transform.rotation = Quaternion.Euler(0, 0, angle + 90);     
    }
 
    void OnCollisionEnter2D(Collision2D coll)
    {
        if (coll.gameObject.tag == "wall")
        {
            r2bd.velocity = Vector2.zero;
            r2bd.angularVelocity = 0;
        }
 
        if (coll.gameObject.tag == "enemy")
        {
            r2bd.velocity = Vector2.zero;
            r2bd.angularVelocity = 0;
        }
    }
 
}

En este video pueden ver lo que sucede:



En resumen, mi player se mueve en un tablero que está dividido en dos partes, este sólo debe moverse de su lado, con un click del mouse, pero, cuando llegue o esté a punto de llegar al límite (ya sea a los costados o a la línea media del tablero) se detenga completamente. Entonces, quiero suponer que lo que estoy haciendo en:

Código: [Seleccionar]
    void OnCollisionEnter2D(Collision2D coll)
    {
        if (coll.gameObject.tag == "wall")
        {
            r2bd.velocity = Vector2.zero;
            r2bd.angularVelocity = 0;
        }
 
        if (coll.gameObject.tag == "enemy")
        {
            r2bd.velocity = Vector2.zero;
            r2bd.angularVelocity = 0;
        }
    }

no es del todo correcto, ¿es así?

De antemano, gracias por sus comentarios.

Saludos!!

santiandrade

  • Jammer
  • **
  • Mensajes: 89
  • Molas: 12
  • @SantiHisteria | histeriagamedev.com
    • Histeria Gamedev
Re:Detener sprite cuando colisiona Unity2d
« Respuesta #1 en: 26 de Abril de 2017, 10:22:54 am »
Hola Middrel, según veoi en tu código, usas la siguiente instrucción para realizar el movimiento de tu player:

transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);

Dicha instrucción hace uso de la variable target (informada con la posición dada por el "click" en pantalla).

Bien, pues en tu función de OnCollisionEnter2D(...), cuando detectas la colisión con la pared, lo único que estás haciendo es bajarle a 0 la velocidad de tu rigidbody, sin embargo en el siguiente frame dicha velocidad vuelve a ponerse como estaba debido a la instrucción Vector3.MoveTowards(...).

Entonces yo creo que, más que poner la velocidad a 0 ahí, lo que deberías hacer es establecer la variable "target" al valor de la posición actual de tu player en ese momento en que colisiona, para que no siga moviéndose cuando detecte la colisión. Algo así como:

target = transform.position;

en vez de:

r2bd.velocity = Vector2.zero;
r2bd.angularVelocity = 0;


De todos modos, haciendo referencia a lo que comentabas al principio de tu post sobre hacer uso de raycasts en vez de las físicas de Unity, en este caso, para lo que estás haciendo sí que sería mucho más eficiente trabajar con raycasts en vez de con rigidbodies. Bastaría con ir lanzando un raycast (de corta distancia) en la dirección a la que se dirige tu player y cuando detecte una pared (o lo que quieras que detecte), se pare.

Espero que te sea de ayuda!

Saludos!

Middrel

  • New Jammer
  • *
  • Mensajes: 5
  • Molas: 0
Re:Detener sprite cuando colisiona Unity2d
« Respuesta #2 en: 26 de Abril de 2017, 04:40:56 pm »
Hola santiandrade, muchas gracias por responder...

Tengo a mi player con un componente RigidBody2D, ¿debería quitarle el componente o se lo dejo?

Y por otro lado, entonces lo que me comentas es que debo buscar en la documentación de raycast como detener mi player, ¿correcto? No propiamente por el método que estaba usando.

Saludos!!

santiandrade

  • Jammer
  • **
  • Mensajes: 89
  • Molas: 12
  • @SantiHisteria | histeriagamedev.com
    • Histeria Gamedev
Re:Detener sprite cuando colisiona Unity2d
« Respuesta #3 en: 26 de Abril de 2017, 06:02:41 pm »
Has probado lo que te dije de quitar:

r2bd.velocity = Vector2.zero;
r2bd.angularVelocity = 0;


y sustituirlo por esto?

target = transform.position;

Middrel

  • New Jammer
  • *
  • Mensajes: 5
  • Molas: 0
Re:Detener sprite cuando colisiona Unity2d
« Respuesta #4 en: 26 de Abril de 2017, 06:57:41 pm »
Hola santiandrade, aún no, estoy en la oficina :P

Cuando llegue a casa retomo esto, sólo trataba de leer un poco más del tema (si mi jefe me deja...)

Saludos!!

Middrel

  • New Jammer
  • *
  • Mensajes: 5
  • Molas: 0
Re:Detener sprite cuando colisiona Unity2d
« Respuesta #5 en: 27 de Abril de 2017, 02:47:20 am »
santiandrade funcionó muy bien, cada que el sprite o player toca la pared o el punto rojo en el video se detiene completamente.

Prácticamente era lo que buscaba, y me agrado mucho tu explicación, fue más precisa y completa que la que he obtenido hasta ahora. Por ello te agradezco :)

Mi única duda hasta aquí es: transform.position obtiene la posición actual del sprite, ¿correcto? sí es así, ¿por qué con esta misma instrucción se detiene?

¡Saludos y gracias por tus comentarios!

santiandrade

  • Jammer
  • **
  • Mensajes: 89
  • Molas: 12
  • @SantiHisteria | histeriagamedev.com
    • Histeria Gamedev
Re:Detener sprite cuando colisiona Unity2d
« Respuesta #6 en: 27 de Abril de 2017, 09:57:16 am »
Me alegro de que te haya funcionado!

Básicamente, el problema que estabas teniendo era el siguiente:

En la función Update(), la cual se ejecuta una vez por cada frame, está la siguiente instrucción:
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);

Dicha instrucción va actualizando la posición de tu objeto en función de la variable "target", la cual la tienes inicializada en la función Start() del siguiente modo:
target = transform.position;

Hasta aquí todo correcto. El problema viene en lo que estabas haciendo cuando detectabas la colisión, cuando hacías esto:
r2bd.velocity = Vector2.zero;
r2bd.angularVelocity = 0;


Efectivamente, dichas instrucciones hacen que tu objeto se detenga... pero lo hace tan solo en ese frame. Recuerda que luego tienes la función Update() la cual está siguiendo su ejecución frame tras frame y que vuelve a lanzar la instrucción:
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);

Y como la variable target no la habías actualizado (tan solo la inicializaste UNA vez en Start()), la instrucción hace que el objeto se siga moviendo hacia el target que seteaste al principio.

Espero haberme explicado bien!

Saludos!

Middrel

  • New Jammer
  • *
  • Mensajes: 5
  • Molas: 0
Re:Detener sprite cuando colisiona Unity2d
« Respuesta #7 en: 28 de Abril de 2017, 05:58:25 am »
¡Muchas gracias por la explicación santiandrade!

Estudiaré más el tema y continuaré trabajando con lo siguiente, hay cosas o detalles que no se explican en la documentación de Unity, al menos no ha detalle como el "no usar esto por..." o "para efectos de usar mejor..." claro, sería complicado documentar todo pero es útil en muchas ocasiones.

¡Nuevamente, gracias por todo, seguimos en contacto!