Home > Software design >  Multiple collisions happening at the same time
Multiple collisions happening at the same time

Time:11-11

I'm making a Balloon Fight style game and I'm having trouble with object collision. Each character has two balloons on top of his head and each balloon has an on trigger Box Collider. I want to make it so only one balloon can be hit at a time so you can't destroy both balloons at the same time. In order to do this I added a boolean called isAttacking to prevent it from destroying more than one balloon at the same time.

Hello, I'm making a Balloon Fight style game and I'm having trouble with object collision. Each character has two balloons on top of his head and each balloon has an on trigger Box Collider. I want to make it so only one balloon can be hit at a time so you can't destroy both balloons at the same time. In order to do this I added a boolean called isAttacking to prevent it from destroying more than one balloon at the same time.

 public bool isAttacking = false;

 private void OnTriggerEnter(Collider collision)
 {
     if (collision.GetComponent<Collider>().gameObject.layer == 7 && collision.GetComponent<Collider>().gameObject.tag != this.gameObject.tag)
     {
         if (!isAttacking)
         {
             Destroy(collision.GetComponent<Collider>().transform.parent.gameObject);
             transform.parent.gameObject.GetComponent<Jump>().jump = true;
             isAttacking = true;
         }
     }
 }

 void LateUpdate()
 {
     if (isAttacking)
     {
         isAttacking = false;
     }
 }

While it does prevent two collisions from registering I still found this solution to be insufficient, since the balloon that is destroyed is not necessarily the one closest to the character destroying it. How could I improve the collision code in order for it to only register the collision happening closer to the character?

CodePudding user response:

First, check if your OnTriggerEnter is executing for both balloons. It probably is?

Then in the moment OnTriggerEnter executes, compare the position of collision with the position of your balloons and see which one is the closest, then destroy the closest balloon and maybe set a variable isInvulnerable as true, so that if it is true, no balloon can be destroyed inside OnTriggerEnter.

CodePudding user response:

Within one frame afaik there is no reliable order of OnTriggerEnter calls (it is somewhat based on the instanceID of objects but that won't really help you).

What you could do instead would be comparing distances, somewhat like e.g.

private readonly HashSet<GameObject> hittingObjects = new();

[SerializeField] private Jump jump;

private void Awake()
{
    if(!jump) jump = GetComponentInParent<Jump>(true);
}

private void OnTriggerEnter(Collider collision)
{
    if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
    {
        hittingObjects.Add(collision.transform.parent.gameObject);
    }
}

private void LateUpdate()
{
    if (hittingObjects.Count > 0)
    {
        var closestHit = hittingObjects.OrderBy(hit => (transform.posiion - hit.transform.position).sqrMagnitude).First();
        Destroy(closestHit);
        jump.jump = true;

        hittingObjects.Clear();
    }
}

Note: This still doesn't prevent this object from colliding with the other balloon in the very next physics update. If you wanted to track this as well you could make it slightly more complex and only allow collisions if you are newly entering the trigger => You have to exit the object again before you can hit it again.

Somewhat like maybe

private readonly HashSet<GameObject> hastoExitFirstObjects = new();
private readonly HashSet<GameObject> newHittingObjects = new();

[SerializeField] private Jump jump;

private void Awake()
{
    if(!jump) jump = GetComponentInParent<Jump>(true);
}

private void OnTriggerEnter(Collider collision)
{
    if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
    { 
        var hit = collision.transform.parent.gameObject;
        if(!hastoExitFirstObjects.Contains(hit))
        {
            newHittingObjects.Add();
        } 
    }
}

private void OnTriggerExit(Collider collision)
{
    if (collision.layer == 7 && !collision.CompareTag(gameObject.tag))
    {
        var hit = collision.transform.parent.gameObject;
        hastoExitFirstObjects.Remove(hit);
    }
}

private void LateUpdate()
{
    if (newHittingObjects.Count > 0)
    {
        var closestHit = newHittingObjects.OrderBy(hit => (transform.posiion - hit.transform.position).sqrMagnitude).First();
        newHittingObjects.Remove(closestHit);
        Destroy(closestHit);
        jump.jump = true;

        foreach(var hit in newHittingObjects)
        {
            hastoExitFirstObjects.Add(hit);
        }

        newHittingObjects.Clear();
    }
}
  • Related