Duda unity OnColliderEnter

krzz

Buenas gente llevo ya varias horas liado para ver exactamente como funciona lo siguiente: OnColliderEnter ,

explico:

Quiero que mi personaje al tocar un sprite que es "agua" pues se hagan ciertas cosas, como es la animacion de la muerte y mostrar el game over, el tema es que quiero saber como hacer que detecte que ha tocado el agua y poder ejecutar las instrucciones que yo crea pertinentes.

Un saludo y a ver si lo sacamos entre todos :D

Gracias de antemano!

totespare

Aquí tienes un buen tutorial:

https://unity3d.com/es/learn/tutorials/topics/physics/detecting-collisions-oncollisionenter

Esta es la documentación: https://docs.unity3d.com/ScriptReference/Collider2D.OnCollisionEnter2D.html

PD: es OnCollisionEnter2D (ya que dices que es un sprite) y recibe como parámetro un Collision2D. Esa collisión tiene atributos que puedes utilizar para identificar si es el agua o si es lo que quieras que sea. En caso de ser agua (identificándolo por ejemplo por el tag), pues ejecuta lo que necesites.

2 1 respuesta
krzz

#2 al final lo he solucionado con el ontriggerenter que es parecido , el problema es que en el agua si me hace la animacion de morir pero con otros objetos no..

2 respuestas
B

#3 No has probado a recibir el collider y asignar los objetos a un tag que sea "Death" y si entra en contacto con este tipo de elementos, ejecutes el efecto que quieras?

Te evitas de esta manera tener que asignar un colliderenter or trigger por cada objeto en particular.

Edit: Ya veo que totespare ya ha comentado lo del 'tag'.

1 respuesta
krzz

#4 Si lo que tengo creo que es algo parecido, tengo un script que se llama DestroyPersonaje en el que supuestamente si se lo asigno a los objetos ese script todo lo que toque ese script que tenga el TAG "Player" lo destruye pero me pasa eso, es decir a ver si puedo adjuntar aqui los videos

1 respuesta
Yandr0s

#5 Has mirado que los otros objetos tambien tengan el collider, y lo tengas marcado como trigger?

Es que hay muy poca informacion para saber lo que te pasa xD

1 respuesta
B

Mira de poner el codigo con la etiquera [.code][./code] para una mejor visualización en el foro.

Lo mejor de programar es intentar que una cosa sirva para muchas otras y si se necesitan modificaciones, crear herencia y crear en las clases hijas las modificaciones que sean exclusivas.

krzz

#6 si , de hecho los pongo igual que el que si funciona..

using UnityEngine;
using System.Collections;

public class DestroyPlayer : MonoBehaviour {

private bool muertoOn = false;
public Transform personaje;
private Animator animacion;
Rigidbody2D rb2D2;


void Awake()
{
    animacion = personaje.GetComponent<Animator>();
}
// Use this for initialization
void Start () {
    rb2D2 = personaje.GetComponent<Rigidbody2D>();
}

// Update is called once per frame
void FixedUpdate()
{
    if (personaje != null)
    {
        animacion.SetBool("playerMuerto", muertoOn);
        rb2D2.velocity = new Vector2(0, rb2D2.velocity.y);
    }
}

void OnTriggerEnter2D(Collider2D col)
{
    if(col.gameObject.tag == "Player")
    {
        Debug.Log("Funciona");
        Destroy(col.gameObject, 0.70f);
        
        muertoOn = true;
  
}

}
}

Ahora adjunto videos

krzz

[media] https://drive.google.com/file/d/0B0IR80dqgj8zcW1BejJDUERvY2s/view [/media]

[media]https://drive.google.com/open?id=0B0IR80dqgj8zSC1oejFMdWZaNEE[/media]

1 respuesta
B

Según veo va "bien" pues al entrar en el agua es destruido y al tocar el cactus igual.

1 respuesta
Yandr0s

#9 le has asignado el transform del personaje al cactus?

#10 pero con el cactus no salta la animacion de muerto

1 respuesta
B

Tienes el personaje como kinematic?

Pones que se ejecute el destroy antes del cambio de la variable muertoOn. No te da problemas diciendo de que el objeto no existe al crear la animación de muerte si ya lo has destruido?

#11 lo que he visto es que hay un delay entre cuando entra al agua y cuando toca el cactus, que sigue moviendose incluso cuando ha tocado ya el cactus.

1 respuesta
krzz

#12 ese es el tema, en el agua funciona bien , pero en el cactus no se destruye, el delay lo tiene para que se ejecute la animacion tiene un delay de 0.7 pero en el cactus no hace la animacion de morir

B

Entonces hay algo en el gameobject del cactus que es diferente al del agua. Mira bien que todos los objetos estén correctamente asignados o no falte o sobre algun script que pueda afectar a la ejecucion de la animación.

De todos modos, ¿este script es el que pones en el jugador o en cada objeto que pueda causar la muerte?

1 respuesta
krzz

#14 en cada objeto que pueda causar la muerte

FernandoA

#3 Tu problema es bastante obvio y es que tienes el código mal estructurado.

  1. Cuando quieres guardar el estado de algo, (en este caso muertoOn guarda el estado del personaje) lo habitual es guardarlo en el script del propio objeto (en este caso personaje), y no como haces aquí que lo guardas en el obstáculo (ojo, en todos y cada uno de los obstáculos).
  2. Cuando quieres cambiar un estado del Animator, lo habitual es modificarlo cuando se da una situación puntual que así lo requiera. En este caso habría que modificar el valor "playerMuerto" del animator, SOLO en el momento que mueres, y no continuamente en el FixedUpdate.

Estas dos cosas juntas son las que provocan el problema. Cuando un obstáculo te mata, ese obstáculo pone su muertoOn a true y en el FixedUpdate te modifica el valor del animator, el problema es que el resto de obstáculos que tengas en el juego seguirán teniendo su variable muertoOn a false y en sus FixedUpdates estarán modificando el valor del animator y poniéndolo a false. Con lo cual el "playerMuerto" del animator está continuamente cambiando de true a false y nunca hace la transición a la animación de muerte que quieres que haga.

Solución:

  1. Olvídate de la variable muertoOn.
  2. Elimina el FixedUpdate de la ecuación.
  3. Pon lo que había en el FixedUpdate dentro del OnTriggerEnter2D
using UnityEngine;
using System.Collections;

public class DestroyPlayer : MonoBehaviour {

public Transform personaje;
private Animator animacion;
Rigidbody2D rb2D2;

void Awake() {
    animacion = personaje.GetComponent<Animator>();
}

void Start () {
    rb2D2 = personaje.GetComponent<Rigidbody2D>();
}

void OnTriggerEnter2D(Collider2D col) {
     if(col.gameObject.tag == "Player") {
          animacion.SetBool("playerMuerto", true);
          rb2D2.velocity = new Vector2(0, rb2D2.velocity.y);
          Destroy(col.gameObject, 0.70f);
     }
}
}

Con ésto debería solucionarse.

1 1 respuesta
krzz

pero con eso siempre se ejecuta la animacion pasados 0.7 segundos... :S#16

1 respuesta
B

#16

    void OnTriggerEnter2D(Collider2D col) {
         if(col.gameObject.tag == "VeryDead") {
              animacion.SetBool("playerMuerto", true);
              rb2D2.velocity = new Vector2(0, rb2D2.velocity.y);
              Destroy(this.gameObject, 0.70f);
         }
    }

He modificado un poco esta parte. Si atachas este script al personaje, nunca entraría en el if porque es el objeto el que posee el collider2d que capta el player al entrar. Aparte, en el Destroy, he incluido this.gameObject para destruir el objeto que tiene este script, cuyo propietario es el personaje, si se dejase col.gameObject acabaría rompiendo el cactus o el agua.

1 respuesta
krzz

#18 pero entoncess este script pasaria a estar en el personaje y no los objetos? , por que si no sigue igual .. es decir , se ejecuta la animacion del personaje todo el rato :S

1 respuesta
B

#19 Es que realmente debe estar en el objeto al que le afecta la acción y la lanza.

A ver si el problema va a estar en la animation que no cortas esta acción para lanzar la de muerte y luego con el 0.7f se destruye el objeto?

1 respuesta
krzz

#20 pero luego no entiendo como con el agua funciona bien >S

2 respuestas
Yandr0s

#21 El animator tiene transicion de "corriendo" a muerto?

Lo mismo el del agua funciona porque esta haciendo la animacion del "dash"

Podrias poner tambien el script que tengas en el personaje?

Es que pueden ser muchisimas cosas y algunas se obvian xD

1 respuesta
B

#22 Yo vi muchas de ellas y entrelazadas pero sin ver los nombres así que puedo pensar que la tiene

Algo puedo apreciar de Running y de Dash

#21 Como comenta Yandr0s puede que falle en la ejecución de las animaciones que se haya pasado un trigger por poner para hacer el efecto muerte o incluso que entre en conflicto con otro evento.

1 respuesta
krzz

#23 Aquí tienes el codigo y las animaciones :

using UnityEngine;
using System.Collections;
 
public class PlayerController : MonoBehaviour {
 
 
// Variables públicas
 
public float speedMove = 4.00f;
public float jumpForce = 600f;
 
private bool enSuelo = true;
public Transform comprobadorSuelo;
private float comprobadorRadio = 0.07f;
public LayerMask mascaraSuelo;
 
private Animator animator;
 
private bool corriendo = false;
private bool slideOn = false;
 
 
 
Rigidbody2D rb2D;
 
 
 
void Awake(){
    animator = GetComponent<Animator>();
 
}
 
// Use this for initialization
void Start () {
    rb2D = GetComponent<Rigidbody2D>();
   
}
 
void FixedUpdate()
{
    if (corriendo){
        rb2D.velocity = new Vector2(speedMove, rb2D.velocity.y);
    }
    animator.SetFloat("velX", rb2D.velocity.x);
    enSuelo = Physics2D.OverlapCircle(comprobadorSuelo.position, comprobadorRadio, mascaraSuelo);
    animator.SetBool("isGrounded", enSuelo);
    animator.SetBool("slideActivado", slideOn);
   
}
 
 
void PonerOnSlide()
{
    slideOn = false;
}
 
 
 
 
// Update is called once per frame
void Update () {
 
 
 
 
 
    if (Input.GetMouseButtonDown(0) && !slideOn)
    {
        if (corriendo)
        {
            if (enSuelo)
            {
                rb2D.AddForce(new Vector2(0f, jumpForce));
 
            }
        }
        else
        {
            corriendo = true;
        }
 
    }
 
    if (Input.GetKeyDown("space"))
    {
        if (corriendo)
        {
            if (enSuelo)
            {
                if (!slideOn)
                {
                    slideOn = true;
 
                }
 
            }
            Invoke("PonerOnSlide", 1f);
        }
        else
        {
            corriendo = true;
           
        }
    }
 
 
   
 
}
}
B

Ahora faltaria ver los triggers en las animaciones.

De todos modos veo que tienes el estado IDLE, pero luego una vez pulsas espacio o Fire1 no hay manera de pasar a este de nunguna manera. No se si lo piensas dejar así o es una funcionalidad que vas a añadir en un futuro. Si no, no te hace falta que de running y de Jump vayan a ella.

1 respuesta
krzz

#25 Ya , pero puede que sea por eso? Esque llevo todo el día y no se ya de que puede ser...

Yo creo que me va a tocar hacerlo de nuevo por que no veo el fallo...

FernandoA

#17 No comprendo a que te refieres, ¿que animación se ejecuta cada 0.7 segundos? Con el código que he puesto debería cambiar la variable del animator, parar el movimiento horizontal del personaje y destruir al personaje a los 0.7 segundos, nada más que eso. Y eso sólo cuando el personaje entra dentro del trigger del obstáculo, en ningún otro caso.

¿Tienes el playerMuerto del animator inicializado a false en el propio animator? Porque con los cambios que puse en mi script ya no se actualiza constantemente y, por lo tanto, hay que tenerlo inicializado a false o ya comenzará con la animación de muerte.
¿La animación de muerte la tienes en loop? Si es así quítaselo porque no necesitas loop en esa animación.

También deberías añadir al código del personaje

//Si el personaje no está muerto
if ( !animator.GetBool("playerMuerto") )

Y meter dentro todo el código del input, para evitar que el jugador pueda hacer acciones con el personaje cuando se ha muerto.

1 respuesta
krzz

#27 Vale, gracias a tu solución lo conseguí arreglar, el problema como bien dices estaba en el animator y no me habia dado cuenta, perdon por el retraso ;) :D

1 respuesta
B

No pidas perdon porque por cosas como estas son las que uno aprende. Vas viendo errores comunes y vas mejorando la estructura y ejecuciones.

Yo me he hecho adicto a los state y para todo hago una clase. De esta manera lo tengo ordenado y si quiero cambiar algo tiro de esa clase en particular.

Suerte y animo

FernandoA

#28 ¿Lo has solucionado al final? Me alegra. Y no te preocupes por no darte cuenta de un error, es algo típico que nos pasa a todos los programadores.