Search code examples
c#unity-game-engineunityscript

Unity - How to have two of the same GameObjects collide, destroy each other, and spawn a new GameObject at the target position?


So I want to have two balls collide, destroy themselves, and then have another ball spawn at their place (preferably with a specific velocity). When I try to attach the script to the ball, however, both instances of the ball are destroyed on contact, then immediately spawns two prefabs of the ball, since they both have the code. This causes both balls to spawn and destroy each other over and over. I have this script attached to the balls:

private Vector3 ballPosition;

void OnTriggerEnter2D (Collider2D other) {

    if (other.gameObject.tag == "Ball") {

        ballPosition = new Vector3 ((transform.position.x + other.transform.position.x) / 2, (transform.position.y + other.transform.position.y) / 2, 0.0f);
        StartCoroutine ("RespawnBall");
    }
}

IEnumerator RespawnBall () {

    Instantiate (gameObject, ballPosition, Quaternion.identity);
    Destroy (gameObject);
    yield return null;
}

How do I make this code destroy both balls, then spawn only one instance of the prefab?


Solution

  • You can also use a boolean on your script that is set so only the first ball having its OnTriggerEnter2D() method call will spawn a new ball :

    private Vector3 ballPosition;
    public bool spawnNewBall;
    
    void Start() {
        spawnNewBall = true;
    }
    
    void OnTriggerEnter2D (Collider2D other) {
    
        if (other.gameObject.tag == "Ball") {
    
            if (spawnNewBall) {
                other.GetComponent</*YourScriptName*/>().spawnNewBall = false;
            }
    
            ballPosition = new Vector3 ((transform.position.x + other.transform.position.x) / 2, (transform.position.y + other.transform.position.y) / 2, 0.0f);
            StartCoroutine ("RespawnBall");
        }
    }
    
    IEnumerator RespawnBall () {
        if (spawnNewBall) {
            Instantiate (gameObject, ballPosition, Quaternion.identity);
        }
        Destroy (gameObject);
        yield return null;
    }
    

    More simply, just do this:

    public class TwoToOne : MonoBehaviour {
    
        public bool doNothing;
    
        void OnCollisionEnter (Collision col)
            {
            if (doNothing) return;
    
            col.gameObject.GetComponent<TwoToOne>().doNothing = true;
            Destroy(col.gameObject);
    
            GameObject newCube = Instantiate(gameObject);
    
            Destroy(gameObject);
            }
    
        }
    

    That's a totally common script or pattern in Unity.

    So, conceptually you just "destroy the other one"; since one of the scripts has to run first, it works out fine. In different systems from Unity you can do one of these things:

    • A, "destroy" the other game object in some way. That would be DestroyImmediate(col.gameObject) in Unity.

    • B, "destroy" or disable the other script in some way. that would be col.gameObject.GetComponent<TwoToOne>().enabled = false in Unity

    • C, "flag" (set a boolean) on the other game object in some way - as shown here.

    As it happens, in Unity specifically you can't do A or B, so you just do C. B is the most elegant solution, but it doesn't work in Unity5, so for now do C!