Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

Problema OnTriggerEnter y OnTriggerExit

Iniciado por ftejada, Marzo 22, 2018, 07:16:56 PM

Tema anterior - Siguiente tema
Hola a todos Tengo un problema que me tiene loco ya... Unity 2017.1.1f1
 
 
 
Tengo un script en el FpCharacter que tira unos rayos en la direccion del desplazamiento para que cuando detecte ciertos objetos cambie el SlopeLimits del CharacterController. Es decir, cuando detecta escaleras y algunas cosas lo pone en 90 para que pueda subirlos. Y al terminar vuelve a poner el SlopeLimits a 45.
 
Tengo una puerta que tiene un Trigger para que cuando detecte al Player entrar en ese trigger (Por medio de OntriggerEnter()) la puerta se abra y tire un sonido. Y cuando sale del Trigger mediante OntriggerExit() cierra la puerta.
 
 
 
El problema es el siguiente: Por alguna razón al entrar en el trigger y moverme dentro de dicho trigger (cerca de la puerta), el codigo detecta que el player sale y entra del trigger en ocasiones, sin que verdaderamente haya salido del perimetro que tiene el trigger. Pero lo más curioso es que cuando no lanzo los rayos del script que mencioné arriba nunca se genera el problema. Es como si los rayCast que tiro en dicho script, hiciesen que el trigger interpretase que el Player ha salido del trigger y al instante vuelto a entrar... con lo que la puerta en muchas ocasiones, se cierra y se abre instantaneamente con el player a lado, cuando deberia permanecer abierta en todo momento hasta que el player saliese del trigger
 
 
 
¿¿¿Alguien tiene alguna idea de porqué está pasandome este problema???? y como solucionarlo...
 
 
 
Gracias por adelantado. Un saludo.

Cita de: ftejada date=1521742616Tengo un script en el FpCharacter que tira unos rayos en la direccion del desplazamiento para que cuando detecte ciertos objetos cambie el SlopeLimits del CharacterController. Es decir, cuando detecta escaleras y algunas cosas lo pone en 90 para que pueda subirlos. Y al terminar vuelve a poner el SlopeLimits a 45.
   


Osea que estás usando un slopeLimit como si fuera un step offset? Esos parámetros son generalmente fijos y no sirve de mucho andar variandolos en runtime.
 
 
 
Cita de: ftejada date=1521742616¿¿¿Alguien tiene alguna idea de porqué está pasandome este problema???? y como solucionarlo...
   


Podrías subir el/los scripts.

Marzo 22, 2018, 08:32:01 PM #2 Ultima modificación: Marzo 22, 2018, 08:33:11 PM por ftejada
Cita de: lightbug date=1521744280Osea que estás usando un slopeLimit como si fuera un step offset? Esos parámetros son generalmente fijos y no sirve de mucho andar variandolos en runtime.
   
   
       
   
   
      Podrías subir el/los scripts.
   


No se muy bien si el Step Offset me serviría para subir escalones u obstaculos verticales, siempre que estos no sean muy altos. Realmente lo que quiero es poder subir escaleras en el escenario, pero estoy en un proyecto en el que se está utilizado el FirstPersonController antiguo de Unity en el que llevaba el script CharacterMotor y el FPSInputController. Y por algunos motivos es bastante complicado pasar al nuevo FirstPersonController de Unity, que he probado y que sube escaleras muy bien sin tener que tocar nada.
 
 
 
Aquí los tienes... El primero es el script para detectar obstaculos y cambiar el SlopeLimit y el segundo es el de la Puerta con el Trigger:
 

void FixedUpdate()
    {
        if (GetComponent<CharacterMotor>())
            motor.mFixedUpdate();     //Actualizamos el FixedUpdate del ThirdPersonUser del Standard Asset de Unity   
        else
            fpc.mFixedUpdate();
        UpdateDetectedObstacles();
    }
 
   
    void UpdateDetectedObstacles()
    {
        #region"PARA DETECTAR ESCALONES U OBSTACULOS VERTICALES"
        if (GetComponent<CharacterMotor>())
            displacementDirection = motor.inputMoveDirection;//motor.m_MoveDir;
        else
            displacementDirection = fpc.m_MoveDir;
        displacementDirection.Normalize();
        displacementDirection.y = 0;
        //Si detecta un obstaculo delante
        if (CheckForwrdObstacles())
        {            
            time = 0;
            newSlopeLimit = 90;            
        }
        else
        {
            time += Time.fixedDeltaTime;
            if(time >= delayRestoreSlope)
            {                
                newSlopeLimit = 45;                
            }
                         
        }
        if(newSlopeLimit != oldSlopeLimit)
            UpdateSlopeLimits(newSlopeLimit);
        oldSlopeLimit = newSlopeLimit;
        #endregion
    }
   
    bool CheckForwrdObstacles()                            
    {
        RaycastHit hitObstacles;        
        Vector3 offsPosZero = transform.localRotation * offsetPositionZero;
        float longOffset = offsetPositionZero.z * -1;
       
        for (int i = 0; i < numeroRayosCheckedObstaculos; i++)
        {
            float h = i == 0 ? alturaPrimerRayoObst : (i * heightBetweenRays);
                                                         
            if (Physics.Raycast(correctPositionZero.position + offsPosZero + (Vector3.up * h), displacementDirection, out hitObstacles, longCheckObstacles + longOffset, layerCollision, QueryTriggerInteraction.Ignore))
            {                
                //Comprobamos que el obstaculo no es más alto que la maxima altura que podemos subir
                if (!Physics.Raycast(correctPositionZero.position + offsPosZero + (Vector3.up * maxHeightLiftFoot), displacementDirection, longCheckObstacles + longOffset, layerCollision, QueryTriggerInteraction.Ignore))
                {
                    float angle = Vector3.Angle(hitObstacles.normal, Vector3.up);
                    if (angle > InclinacionObstaculo)     //Si la inclinacion de la superficie por la que pisa el character es superior a 80º
                        return true;
                }
            }
        }
        return false;
    }
   
    void UpdateSlopeLimits(float newSlope)
    {
        characterController.slopeLimit = newSlope;
    }
}

 
Y las funciones OnTriggers() del script de la puerta:
 

  public class DoorScript : MonoBehaviour
{
    public float AngleY = 90.0f;
private float targetValue = 0.0f;
    private float currentValue = 0.0f;
    private float easing = 0.05f;
    bool stay = false;
 
    public GameObject Target;
    public AudioClip sonidoOn;


// Update is called once per frame
void Update ()
    {
        currentValue = currentValue + (targetValue - currentValue) * easing;
        Target.transform.rotation = Quaternion.identity; // set rotation to zero
        Target.transform.Rotate(0, currentValue, 0); // apply full Rotation      
    }
 
    void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {          
            targetValue = AngleY;
            currentValue = 0;
      GetComponent< AudioSource > ().PlayOneShot(sonidoOn);            
        }
    }
 
    void OnTriggerExit(Collider other)
    {
        if (other.gameObject.tag == "Player")
        {            
            currentValue = AngleY;
            targetValue = 0.0f;            
        }
    }
}

 
Creo que estas son las partes más relevantes. De todos modos subo los script

no conocias eso de queryTriggerInteraction.... no se muy bien que hace....
 
 
 
pero creo que deverias meter el objeto Trigger en la "layer" "ignoreRaycast" (que es la 2)
 
y usar:
 

LayerMask lmask = ~(1<<2);
//esto ignorara la capa 2
if (Physics.Raycast(....., lmask) {
}

 
 
 
otra posible solucion seria usar el "stay" (onTriggerStay) y un "bool" para saber si esta dentro de la "zona" o no.... y abrir o cerrar la puerta..

Marzo 23, 2018, 11:49:56 AM #4 Ultima modificación: Marzo 23, 2018, 11:51:37 AM por ftejada
Cita de: Igor date=1521753143no conocias eso de queryTriggerInteraction.... no se muy bien que hace....
   
   
       
   
   
      pero creo que deverias meter el objeto Trigger en la "layer" "ignoreRaycast" (que es la 2)
   
   
      y usar:
   
   

LayerMask lmask = ~(1<<2);
//esto ignorara la capa 2
if (Physics.Raycast(....., lmask) {
}

   
       
   
   
      otra posible solucion seria usar el "stay" (onTriggerStay) y un "bool" para saber si esta dentro de la "zona" o no.... y abrir o cerrar la puerta..
   


Gracias por la respuesta y a lightbug por la anterior.
 
La Puerta ya estaba metida en el Layer ignoreRayCast. Aparte no creo que ese fuese el problema ya que la Puerta es la que tiene el script que hace el OnTriggerEnter() y OnTriggerExit() y hasta donde yo se los OnTriggerEnter, Stay y Exit no tienen en cuenta layers (Salvo quizas la Matriz general de Fisicas). Por lo que cuando el Player u otro objeto entra o sale del Trigger se lanza el OnTrigger Correspondiente (entrar, salir, etc).
 
Y el caso es que funciona perfecto, mientras el primer script que puse arriba, (el de detectar obstaculos), no tire los rayCast. Si comento las lineas de codigo que tiran los RayCast todo funciona perfectamente... y el Trigger de la puerta interpreta correctamente cuando entra y cuando sale de él el player... pero si el player, mediante su script de detectar obstaculos, tira los RayCast el trigger de la puerta detecta que el player sale y entra del trigger en muchas ocasiones cuando en realidad el player no ha salido en ningun momento de ese trigger... No se si se me entiende.
 
Otro dato curioso es que el script de detectar obstaculos lo utilizo en en el personaje en tercera persona, y aunque tabien tira esos RayCast, el trigger de la puerta no da problemas con este character en 3a persona. La unica diferencia entre estos dos Characteres (1a persona y 3a persona de los standard assets es el CharacterController) ya que el de tercera persona no lleva el CharacterController de Unity, solo un capsuleCollider normal. ¿Alguna idea?
 
 
 
¿Alguien puede arrojar algo de luz a lo que está pasando??
 
El queryTriggerInteraction  sirve para que los RayCast ignoren los triggers si lo pones en Ignore
 
Un saludo y gracias a ambos por contestar.

Cita de: ftejada date=1521802196hasta donde yo se los OnTriggerEnter, Stay y Exit no tienen en cuenta layers (Salvo quizas la Matriz general de Fisicas).
   


Wo woo wooo wooo esperate ahí!!!  como que no tienen en cuenta las layers? El contacto depende de si está permitido (ver tabla de colisiones del manual) y si está habilitado en la matriz de colisiones del proyecto, es decir que las layers Sí importan. Si tenés dudas probá, pero tenés que setearlo bien, es más, yo tengo una capa dedicada a triggers y si no le doy el tilde en la matriz no las detecta. No se si iba por acá tu planteo.
 
Cita de: ftejada date=1521802196pero si el player, mediante su script de detectar obstaculos, tira los RayCast el trigger de la puerta detecta que el player sale y entra del trigger en muchas ocasiones cuando en realidad el player no ha salido en ningun momento de ese trigger... No se si se me entiende.
   


Hay algo que no me queda claro, que ya mencionaste en el anterior post, ¿por qué hablas de que detecta que entra o sale cuando tirás un ray? osea el trigger se activa cuando el collider entra en contacto (en un Enter).. no se, quizás a esta altura me perdí un poco.
 
 
 
Cita de: ftejada date=1521802196Otro dato curioso es que el script de detectar obstaculos lo utilizo en en el personaje en tercera persona, y aunque tabien tira esos RayCast, el trigger de la puerta no da problemas con este character en 3a persona. La unica diferencia entre estos dos Characteres (1a persona y 3a persona de los standard assets es el CharacterController) ya que el de tercera persona no lleva el CharacterController de Unity, solo un capsuleCollider normal. ¿Alguna idea?
   


mmm probaste de ponerle un rigidbody kinemático a la version que no tiene Rb (primera persona)? Pa ver que pasa.

Marzo 24, 2018, 02:25:39 AM #6 Ultima modificación: Marzo 24, 2018, 03:49:47 AM por ftejada
Cita de: lightbug date=1521839492Wo woo wooo wooo esperate ahí!!!  como que no tienen en cuenta las layers? El contacto depende de si está permitido (ver tabla de colisiones del manual) y si está habilitado en la matriz de colisiones del proyecto, es decir que las layers Sí importan. Si tenés dudas probá, pero tenés que setearlo bien, es más, yo tengo una capa dedicada a triggers y si no le doy el tilde en la matriz no las detecta. No se si iba por acá tu planteo.
   


Gracias por responder..  A eso me referia con lo de que no tienen encuenta las layers...  a que salvo por la Matriz de fisicas un OnTriggerEnter, etc, etc detectan todos los colliders que entran, salen, etc de ese trigger siempre que estén activadas en la matriz de colision de fisicas como decias tu. Quizas no lo expresé bien.
 
 
 
Cita de: lightbug date=1521839492Hay algo que no me queda claro, que ya mencionaste en el anterior post, ¿por qué hablas de que detecta que entra o sale cuando tirás un ray? osea el trigger se activa cuando el collider entra en contacto (en un Enter).. no se, quizás a esta altura me perdí un poco.
   


Me refiero a que aunque el player está dentro del collider que hace de trigger para detectar si el player entra o sale, y asi que la puerta se abra o se cierre, el OnTriggerExit() se ejecuta como si el player saliese del perimetro del collider "trigger". Y acto seguido de que se lance el OntriggerExit(), el OnTriggerEnter() se ejecuta interpretando que el player ha entrado en el collider "Trigger" de la puerta. Todo cuando el player no sale del perimetro de dicho trigger... No se si ahora lo he explicado mejor.
 
 
 
Cita de: lightbug date=1521839492mmm probaste de ponerle un rigidbody kinemático a la version que no tiene Rb (primera persona)? Pa ver que pasa.
   


Si. Es una de las muchisimas cosas que he probado.... y la verdad es que ya me he quedado sin ideas
 
Otra dato a tener en cuenta es que justo donde se genera el problema, la malla del escenario tiene un pequeño escalón, por el cual uno de los raycast  que se tiran para detectar si hay un obstaculo(como este escalon), choca y es cuando se produce el problema. Es decir cuando se tira el Raycast no se genera el problema, lo hace cuando el raycast choca con algo como ese pequeño escalon.
 
Saludos

Etiquetas: