How do you trigger a collider to become enabled after the player collider isn't touching it anymore?

So I’m having my character spawn a bomb under his feet, after the bomb spawns it should have no collision, until the character steps off the bomb, rather than push him out of the way when it get’s instantiated. I tried to have two colliders (One to be a trigger, and another to be the actual collision) but I’m having a bit of trouble. Here is my code, the game crashes upon instantiating. I had an old build that would not crash, but when walking back onto the bomb and the “IsTouching” activated like it should, but did not collide as I thought it would. I want a way to check “IsTouching” on Start, then after a bool is triggered checking if the player is on or off the bomb, the “IsTouching” never get’s used again in the script.

void Start () { 
        rend = transform.GetComponent<SpriteRenderer>();
        collision = transform.GetComponent<BoxCollider2D>();
        newcollision = transform.GetComponent<BoxCollider2D>();
        player = GameObject.FindWithTag("Player");
        playercollision = player.GetComponent<CircleCollider2D>();

        while(playercollision.IsTouching(collision))  
        {
            underPlayer = true;
            newcollision.isTrigger = true;
        }
        while (underPlayer == true)
        {
            collision.isTrigger = true;
        }
        while (playercollision.IsTouching(collision)==false)
        {
            underPlayer = false;
            newcollision.isTrigger = false;
        }
        while (underPlayer == false)
        {
            newcollision.isTrigger = false;
        }
	}
	
	IEnumerator detonationTime(){
	yield return new WaitForSeconds(3);
        collision.isTrigger = true;
        newcollision.isTrigger = true;
        rend.enabled = false;
        isActive = false;
			

}

I used to have “if” statements, but when troubleshooting I tried changing it to “while”, but it didn’t change anything, any help or criticism would be greatly appreciated.

That’s really really bad code. You shouldn’t put while loops inside of Start. Instead you want them to check every frame so you should put pretty much all of your code inside of Update.

Your code is a bit all over the place so I don’t really want to fix it line by line. Instead, I’ll just explain to you how you can fix the collision problem.

First of all, your logic behind using a trigger and a collider is nice. However, what you didn’t know is that when you instantiate an object with a trigger that’s already touching/inside of the player, the trigger won’t know it’s there nor will the trigger know when it leaves. (It’s a secret Unity feature you will never know unless you tried to do what you just did.)

So instead of a trigger, you should just use a simple distance comparison. If the player is at least X distance away from the bomb, activate the bomb’s collider. Simple.

easiest way to do it is to spawn the object outside the spawner’s collision, set any needed variables and then place the spawned object where it needs to be. all in the same call. I recommend to have this done statically and inside the bombscript. this way the bomb script can have direct control over how its getting spawned. however this isn’t important for this to work

public class BombScript : MonoBehaviour
{
    // this boolean only allows the bomb to go boom when its armed
    private bool bombIsArmed = false; 
    // If the bomb leaves this collider it will arm
    private Collider armingTrigger;   



    //here I make the bombscript responsible for instantiating itself properly.
    // doing so simplifies the playerscript and possibly any other script that might want to 
    // spawn a bomb too
    public static GameObject BombPrefab; //prefab reference to the bomb that can spawn
    public static GameObject SpawnBomb(Collider armingCollider)
    {
        // lazy load the bomb prefab "Bomb" from the resources folder
        // for this to  work your bomb prefab must be in Assets/Resources and 
        // be named "Bomb"
        if(BombPrefab == null)
            BombPrefab = Resources.Load("Bomb");

        // first spawn the bomb OUTSIDE the collider! Preferbly someplace that is never seen
        Vector3 spawnlocation = armingCollider.transform.position + Vector3.down*10000;
        GameObject bomb = 
            GameObject.Instantiate(BombPrefab,spawnlocation,armingCollider.transform.rotation);
        
        //assign the bomb's arming trigger to the collider that was passed in
        bomb.GetComponent<BombScript>().armingTrigger = armingCollider;
        
        //then set it to the exact spot you wanted. the collisions will trigger correctly!
        bomb.transform.position = transform.position;
    }



    void Boom(Collider target)
    {
        //if bomb isn't armed then it can't boom
        if(!bombIsArmed)
        {
            return;
        }
        //place your boom logic here
        Debug.Log("Bomb go boom");

        GameObject.Destroy(gameObject);
    }



    void OnTriggerEnter(Collider other)
    {
        Boom(other);
    }



    void OnTriggerExit(Collider other)
    {
        // arm the bomb as soon as it leave's the armingTrigger
        if(other == armingTrigger)
        {
            bombIsArmed = true;
        }
    }
}

but don’t worry the bomb won’t explode when it’s pushed back into the player’s trigger. since our bomb is spawned while not armed, and will only arm once the bomb leaves the player’s trigger. Plus now that we have the BombSpcript controlling how its spawned, all that code is managed there which makes the playerscript simpler and allowing it to just directly manage actions and movement on the player itself.

public class PlayerScript: MonoBehaviour
{
    // variables that can be read from other scripts
    //  but can only be changed by this script, also
    //  they won't clutter the inspector by default
    public CircleCollider2D armingCollider {get;private set}

    void Awake()
    {
        armingCollider = GetComponent<CircleCollider2D>();
    }

    void Update()
    {
        if(Input.GetButtonUp("Fire"))
        {
            SpawnBomb();
        }
    }

    void SpawnBomb()
    {
        //I make the BombScript responsible for instanitating itself properly
        // it keeps this class simple, lets other classes reuse the 
        // code for spawning bombs, and the Bombscript class has more
        // control over itself
        BombScript.SpawnBomb(armingCollider);
    }

}

You definitely shouldn’t be using while loops in the Start method. That is the most likely reason for your game crashing, because if any of the loops’ statements evaluate to true, the game will be stuck in an infinite loop during the beginning of that frame. What you want to do instead is take the same type of code you are using in the loops and placing it into if statements in the Update() method. This will allow for the game to continue running while checking the conditions you set every frame.

As for the colliders not working properly, it probably has something to do with placing one collider on top of another. You should instead try to destroy the first collider in the script and then create the second in its place afterwards.

In 2021, I solved this problem by the following logic (this article helped):

  1. When Instantiating an object, enable isTrigger property of the BoxCollider2D

  2. Then “re-disable” it again when leaving the trigger area.

    // Your "bomb" prefab
    void Awake()
    {
        this.boxCollider = GetComponent<BoxCollider2D>();
        this.boxCollider.isTrigger = true;
    }
    
    // Just stop overlapping a collider 2D
    private void OnTriggerExit2D(Collider2D collision)
    {
        this.boxCollider.isTrigger = false;
    }