Unity - 如何让两个相同的GameObject碰撞,相互摧毁,并在目标位置产生一个新的GameObject?

时间:2016-11-30 04:50:01

标签: c# unity3d unityscript

所以我想让两个球碰撞,自我毁灭,然后在他们的位置产生另一个球(最好是以特定的速度)。然而,当我试图将脚本附加到球上时,球的两个实例在接触时都被破坏,然后立即产生两个球的预制件,因为它们都有代码。这导致两个球一次又一次地产卵和摧毁。我把这个剧本附在球上了:

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;
}

如何使此代码销毁这两个球,然后只生成预制件的一个实例?

3 个答案:

答案 0 :(得分:1)

你也可以在你设置的脚本上使用布尔值,这样只有第一个有OnTriggerEnter2D()方法调用的球会产生一个新球:

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;
}

更简单地说,就这样做:

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);
        }

    }

这是Unity中完全常见的脚本或模式。

所以,从概念上讲,你只是&#34;摧毁另一个&#34 ;;因为其中一个脚本必须首先运行,所以它运行正常。在Unity的不同系统中,您可以执行以下操作之一:

  • A,&#34; destroy&#34;另一种游戏对象在某种程度上。这将是Unity中的DestroyImmediate(col.gameObject)

  • B,&#34;销毁&#34;或以某种方式禁用其他脚本。这将是Unity中的col.gameObject.GetComponent<TwoToOne>().enabled = false

  • C,&#34; flag&#34; (以某种方式设置一个布尔值)在另一个游戏对象上 - 如图所示。

碰巧,在Unity中,你不能做A或B,所以你只做C.B是最优雅的解决方案,但它在Unity5中不起作用,所以现在做C !

答案 1 :(得分:0)

您可以使用delegates OR来解决这个问题,因为@JoeBlow建议使用来自事件管理器的UnityEvents

在以下示例中,我选择使用委托。

有2个脚本。一个位于球体上(您已经拥有),第二个是静态类,可以从应用程序中的任何其他脚本引用而无需实例化。

<强> EventManager.cs

using UnityEngine;
using System.Collections;

public static class EventManager{

    // Create our delegate with expected params.
    // NOTE params must match SphereScript.PostCollision declaration
    public delegate void CollideEvent(string message);

    // Create the delegate instance. This is the one we will invoke.
    public static event CollideEvent PostCollision;

    // Called whenever an object has collided with another
    public static void Collision(GameObject obj1, GameObject obj2, Vector3 collisionPoint){
        if (obj1.GetComponent<sphereScript>().isAlive && obj2.GetComponent<sphereScript>().isAlive) {

            //Kill the 2 objects which haev collided.
            obj1.GetComponent<sphereScript> ().Kill ();
            obj2.GetComponent<sphereScript> ().Kill ();

            //Create a cube.
            GameObject cube = GameObject.CreatePrimitive (PrimitiveType.Cube);
            cube.transform.position = collisionPoint;

            // Invoke delegate invocation list
            PostCollision("Something is dead");
        }
    }
}

SphereScript .cs

using UnityEngine;
using System.Collections;

public class sphereScript : MonoBehaviour {
    // Am I alive?
    public bool isAlive;

    // Use this for initialization
    void Start () {
        // Add a function we want to be called when the EventManager invokes PostCollision
        EventManager.PostCollision += PostCollision;
        isAlive = true;
    }

    // Update is called once per frame
    void Update () {

    }

    //Invoked from EventManager.PostCollision delegate
    void PostCollision(string message){
        if(isAlive)
            Debug.Log (this.name + " message received: " + message);
    }

    // Called when it is time to destroy this gameobject
    public void Kill(){
        isAlive = false;
        Destroy (this.gameObject);
    }

    //On collision with another object
    void OnCollisionEnter2D(Collision2D collision){
        if (collision.gameObject.GetComponent<sphereScript>()) {
            EventManager.Collision (this.gameObject, collision.gameObject, collision.contacts [0].point);
        }
    }

    // Called after this object has been destroyed
    void OnDestroy(){
        // cleanup events for performance.
        EventManager.PostCollision -= PostCollision;
    }
}

那么为什么要使用这种方法呢?

此方法非常适合控制多个事件的发布。从一个地方。在这种情况下,我们在每个碰撞球的每个球上触发一个功能。然后,EventManager会在它们的尾迹中创建一个多维数据集,并在此之后通知任何剩余的多维数据集在场景中的其他位置发生了冲突。

答案 2 :(得分:-2)

你可以做的是创建另一个脚本,它只会破坏球但不会产生并将它附加到第二个球。第一球将具有破坏和重生功能。因此,当两个球相互摧毁时,一个将重生,而另一个则不会因为你没有将产卵特征附加到第二个球