[Bug] Collision event not always triggered

Cheo

Active member
Hello, when subscribing to a collision event not related to ground collisions, there are significant chances that it is not executed, especially if the character is not moving fast. I also think that not using root motion can slightly increase the chances of the collision detection to malfunction. Here is a video as always to give a clear example :


And here is my test script :

C#:
using Opsive.Shared.StateSystem;
using Opsive.UltimateCharacterController.Character;
using UnityEngine;

public class CharacterCollisionEvent : StateBehavior
{
    [SerializeField] protected bool m_CollisionEventEnabled = true;

    public bool CollisionEventEnabled { get { return m_CollisionEventEnabled; } set { m_CollisionEventEnabled = value; } }

    private CharacterLocomotion m_CharacterLocomotion;

    protected override void Awake()
    {
        base.Awake();
        m_CharacterLocomotion = GetComponentInParent<CharacterLocomotion>();

        m_CharacterLocomotion.OnNonGroundCollision += (RaycastHit hit) =>
        {
            CollisionEvent(hit);
        };
    }

    private void CollisionEvent(RaycastHit hit)
    {
        if (m_CollisionEventEnabled)
        {
            Debug.Log("CharacterCollisionEvent hit " + hit.collider.name);
        }
    }

    private void OnDestroy()
    {
        m_CharacterLocomotion.OnNonGroundCollision -= (RaycastHit hit) =>
        {
            CollisionEvent(hit);
        };
    }

}

Here are also the modifications I made to Character Locomotion - first add these properties :

C#:
private Action<RaycastHit> m_OnNonGroundCollision;
[Shared.Utility.NonSerialized] public Action<RaycastHit> OnNonGroundCollision { get { return m_OnNonGroundCollision; } set { m_OnNonGroundCollision = value; } }

And in Detect Collisions add this new event underneath the existing one :

C#:
                        // Others may be interested in the collision.
                        if (m_OnCollision != null) {
                            m_OnCollision(closestRaycastHit);
                        }

                        if (m_OnNonGroundCollision != null)
                        {
                            m_OnNonGroundCollision(closestRaycastHit);
                        }

Hope this can be reproduced and looked into, thanks.
 
After some more experimenting this afternoon, I came to the conclusion that the very low value of the const float c_ColliderSpacing (0.01f) or at least the CombinedCast line in DetectCollisions could be the source of the issue. Here is another video :


To summarize, I added a cast distance multiplier under the form of these 2 properties in Character Locomotion :

C#:
        [SerializeField] protected float m_CollisionCastDistanceMultiplier = 1f;
        public float CollisionCastDistanceMultiplier { get { return m_CollisionCastDistanceMultiplier; } set { m_CollisionCastDistanceMultiplier = value; } }

And changed the CombinedCast line to this :

Code:
var hitCount = CombinedCast(lastPosition, normalizedTargetMovement, Mathf.Max(movementMagnitude, c_ColliderSpacing) * m_CollisionCastDistanceMultiplier);

By setting this multiplier to at least 1.5f, the collision detection works much more reliably and rarely fails. However if c_ColliderSpacing was made a const float that has to be for a reason, so naturally I'm afraid that this may have unwanted consequences, but I haven't seen any so far. I hope this can serve as both a lead and a bandaid for the moment.
 
The collision event only fires if the object completely stops the character. If there is even a little bit amount of sliding then the collision event will not fire. This looks like what is happening here. I can see a reason for both designs, maybe having a callback that gets fired before the collision is resolved would be helpful?
 
Hello, here's a new video in the hope of clarifying a few things :


At the end of Detect Collisions there's a chunk of code starting with an if statement checking if slide is active, and commenting it out changes nothing, but I'm not sure whether that's what you had in mind ? I also want to point out the fact that if the Combined Cast returns 0 hit count, then logically speaking the events cannot be reached as they are underneath an if statement checking if hitCount is superior to 0, so from my point of view the Combined Cast line is the heart of the matter.
 
Can you please make that video private? There is a lot of code shown which is the core part of the controller and you should have a license to the controller to view it.

With that said, I will rethink how the collision event works. There was another post somewhat recently which had a similar confusion.
 
Ah of course I'm sorry about that, I just made the video private and will be careful about that in the future.
 
Back
Top