- Home /
Deal with timing conflict of 2 OnTriggerEnter2D Scripts
So I've been struggling with a problem for a while, and I think I've identified it though I could be completely off so please let me know if I'm not actually on the right track.
The scene is as the following. I'm working in 2D with 2D physics. It's a basic space shooter as of right now. I have an object spawner spawning ships from the top and the player at the bottom that shoots upwards. The spawner spawns prefab enemies and the player shoots prefab bullets. So (from my understanding) the objects themselves should behave the same when they collide. My problem is that this is not happening.
The desired outcome is for the bullet to hit the enemy and destroy itself, then when the enemy get's hit for them to lose life (and eventually die). The problem is that only one of these things is happening, and it isn't consistant. For instance, either my bullet will not be destroyed on contact and pass through damaging all enemies in a line, or the front ship will block the bullet (and not take damage at all, because the bullet got destroyed before the damage took place?).
So I'm pretty sure the problem lies in the fact that I'm relying on 2 separate scripts that both use OnTriggerEnter2D and whichever runs first overrules the other? I'm looking for a solution to the problem and also for an answer on how this works, because I'm sure it's a pain to make sure you can't have multiple OnTriggerEnter2D scripts in large games.
Here is code for the two scripts I believe are causing the conflict: GibOnTrigger.cs
public class GibOnTrigger : MonoBehaviour
{
public GameObject gib = null;
public GameObject objectToDestroy = null;
// Use this for initialization
void Start ()
{
if(objectToDestroy == null)
{
objectToDestroy = gameObject;
}
}
// Update is called once per frame
void OnTriggerEnter2D()
{
if (gib != null)
{
Instantiate(gib, transform.position, gib.transform.rotation);
}
if (transform.parent != null)
{
transform.parent.SendMessage("Dead", transform.position, SendMessageOptions.DontRequireReceiver);
}
Destroy(objectToDestroy);
}
}
EnemyHealth.cs
public class EnemyHealth : MonoBehaviour
{
public float initialHealth = 10.0f;
public GameObject hitEffect;
public GameObject deathEffect;
public string loadLevelOnDeath = "";
private float currentHealth;
// Use this for initialization
void Start ()
{
currentHealth = initialHealth;
}
public void TakeDamage(float damageAmount, Vector3 damagePosition)
{
currentHealth -= damageAmount;
Instantiate(hitEffect, damagePosition, Quaternion.identity);
if(currentHealth <= 0)
{
if(transform.parent != null)
{
transform.parent.SendMessage("Dead",transform.position, SendMessageOptions.DontRequireReceiver);
}
Instantiate(deathEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
if(!System.String.IsNullOrEmpty(loadLevelOnDeath))
{
Application.LoadLevel(loadLevelOnDeath);
}
}
}
void OnTriggerEnter2D(Collider2D col)
{
Debug.Log("Taking Damage");
TakeDamage(1.0f, col.transform.position);
}
}
Answer by pako · Jan 17, 2015 at 09:47 AM
I'm not clear why in GibOnTrigger.cs you Instantiate a gib inside OnTriggerEnter2D, but that's beyond the point. I'll give you the necessary code for a bullet to inflict damage and then destroy itself. You can customize it as necessary.
First of all your code seems an overkill (PUN intended ;) ). You don't need a lot of the code for the bullet, and OnTriggerEnter2D is not necessary in EnemyHealth, so just delete it (or comment it out until your testing is complete). Here's the code for the bullet. Customize it as necessary:
public class Bullet : MonoBehaviour {
void OnTriggerEnter2D(Collider2D other)
{
//Tag enemies with "Enemy", so they can be identified by bullets
if (other.tag == "Enemy")
{
//Get a reference to the
other.GetComponent<EnemyHealth>().TakeDamage(1.0f, transform.position);
//destroys the bullet
Destroy(gameObject);
}
}
}
To be honest, the 'why' is because I got it to kind of work that way and I had looked up/followed tutorials to get that far. I added this code in place of my existing system and it worked. Just to clarify for the sake of learning: $$anonymous$$y original assumption was most likely correct? 2 calls to OnTriggerEnter2D for the same action were causing the conflict?
OnTrigger events are called in a random order between objects. So, although you know that for a single GameObject OnTriggerEnter will for example, be executed after Start() and before any OnCollision event, you don't know in which order the OnTrigger events (or even Start() etc.) will be executed between GameObjects. This is why you got the particular behavior, and some OnTrigger events were executed first for the bullets, and other times for the EnemyHealth.
BTW, although you can have some partial control over the execution order of scripts, there are exceptions, but this is beyond the scope of this question.
Your answer
![](https://koobas.hobune.stream/wayback/20220613180651im_/https://answers.unity.com/themes/thub/images/avi.jpg)