- Home /
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.
Answer by allenallenallen · Feb 08, 2016 at 09:41 PM
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.
Answer by JoshuaMcKenzie · Feb 09, 2016 at 01:37 AM
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);
}
}
Answer by cbjunior · Feb 09, 2016 at 05:10 PM
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.
Answer by Cathair · Apr 11 at 03:49 PM
In 2021, I solved this problem by the following logic (this article helped):
When Instantiating an object, enable
isTrigger
property of theBoxCollider2D
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; }
Your answer
Follow this Question
Related Questions
Changing localScale on Collision2D 2 Answers
Ignore Collision for 2d Collider 2 Answers
If...else statement with errors 1 Answer
Boolean issues 0 Answers
How Do I check if a Bool was True a few moments ago 2 Answers