【问题标题】:Detect collision from different objects?检测来自不同物体的碰撞?
【发布时间】:2018-02-09 14:47:18
【问题描述】:

我无法为这个问题想出合适的标题,但我会解释一下。

我有一个碰撞盒,里面有一个脚本。该脚本有一个 if 语句,用于检测来自对象“Cube001”的冲突并将 Debug.Log 发送到控制台。

 using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;

 public class cubeDetect : MonoBehaviour {

     void OnCollisionEnter(Collision collision) {

         if (collision.gameObject.name == "Cube001")
         {
             Debug.Log("Cube001 hit!");
         }
     }

 }

使用这种方法,盒子碰撞器知道是什么立方体接触到了它,正如我所指示的那样

collision.gameObject.name == "Cube001"

但是如果我有 10 个立方体与碰撞框发生碰撞,我该如何更改 if 语句,而不是编写另外 9 个 if 语句来检查它是否触及碰撞框,我可以只使用 1 个 if 语句检测到来自另一个立方体的碰撞,知道哪个立方体撞到了盒子,并且有了这些知识,就能够执行 Debug.Log 来显示立方体击中了盒子。

我已尝试浏览 OnCollisionEnter 的文档,但找不到任何帮助。

【问题讨论】:

  • 使用标签而不是对象名称进行检查(并且只将name放在Debug.Log中)
  • @UnholySheep 标记仍然需要许多 if 语句。我认为 OP 希望删除执行此操作所需的许多 if 语句
  • 嗨@UnholySheep,如果我使用标签,那么每个立方体本质上都是同一个对象,这只会将我的问题传播到多个对象
  • @toadflax 每个对象都有唯一的名称吗?
  • @toadflax 如果你给他们相同的标签,你仍然可以打印对象的唯一名称,正如我在下面的解决方案所述......因此确定碰撞的唯一对象。所有游戏对象的信息都存储在传递给 OnCollisionEnter 函数的碰撞对象中

标签: c# unity3d collision-detection


【解决方案1】:

一种选择是用相同的名称标记您想要碰撞的所有相似对象。假设我们给他们标签“Cubicle”。然后我们可以执行以下操作:

Gameobject myCube;
void OnCollisionEnter(Collision collision) {

     if (collision.collider.tag == "Cubicle")
     {
         Debug.Log(collision.gameObject.name + " hit!");
         myCube = collision.gameObject; // store colliding gameobject info for use elsewhere
     }
 }

【讨论】:

  • 对不起,我没有看到这个答案,我已经投了赞成票。这个方法似乎有效!但是有没有办法可以将最后一个立方体的信息存储在一个变量中,该变量可以在这个 if 语句之外使用?
  • 绝对,只要在函数外声明一个变量,并在其中存储对撞机信息。我已经更新了我的答案。
【解决方案2】:

您需要使用Dictionary。这消除了对所有if 语句的需要。

Dictionary 应该是这样的:

public static Dictionary<GameObject, System.Action> objToAction = new Dictionary<GameObject, Action>();

然后是一个函数,用于在实例化对象时将对象添加到字典中,如果它们已经存在,则添加到 Start 函数中

public void registerObject(GameObject obj, System.Action action)
{
    objToAction.Add(obj, action);
}

Dictionary 中的键是 GameObject(Cube),也可以使用 string(GameObject 的名称),但使用 GameObject 更好。 Dictionary 中的值存储了您在调用 OnCollisionEnter 时要执行的操作。 所以应该在 if 语句中的代码应该放在这里。 这是通过 Actiondelegate 完成的。您可以根据需要添加任意数量的游戏对象(立方体)。

您必须使用上述函数将这些 Cube 对象添加到字典中:

public GameObject prefab;

void Start()
{
    //Create new Cube
    GameObject obj = Instantiate(prefab);
    obj.name = "Cube001";

    //Add it to the Dictionary
    registerObject(obj, delegate { Debug.Log("Hit: " + obj.name); });
}

您的新OnCollisionEnter 代码如下。不需要if 声明。如果对象存在于Dictionary 中,则为每个关键游戏对象执行我们存储在Dictionary 值中的代码。

void OnCollisionEnter(Collision collision)
{
    Action action;

    if (objToAction.TryGetValue(collision.gameObject, out action))
    {
        //Execute the approprite code
        action();
    }
}

请注意,objToAction 变量应设为 static 或放置在附加到空游戏对象的另一个脚本中,以便您可以访问它。它应该只有一个实例。

【讨论】:

    【解决方案3】:

    最适合我的是使用接口和组件并进行检查。如果您对碰撞有一定的逻辑,这非常有用,但如果没有,您可以使用tag 并将其设置为"collidable" 之类的东西。

    接口解决方案:

    public interface ICollidableObject
    {
        void CollidedWith(ICollidableObject other);
    }
    
    public class CollidableBlock : MonoBehaviour, ICollidableObject
    {
        public void CollidedWith(ICollidableObject other)
        {
            Debug.Log((other as MonoBehaviour).gameObject.name);
        }
    }
    
    public class CollidableSphere : MonoBehaviour, ICollidableObject
    {
        public void CollidedWith(ICollidableObject other)
        {
            Debug.Log("sphere001");
        }
    }
    

    然后像这样使用它:

    void OnCollisionEnter(Collision collision) 
    {
        ICollidableObject collidedWith = collision.gameObject.GetComponent<ICollidableObject>();
        if ( collidedWith != null )
            collidedWith.CollidedWith(this);
    }
    

    【讨论】:

      猜你喜欢
      • 2013-01-28
      • 1970-01-01
      • 1970-01-01
      • 2015-02-10
      • 2010-11-19
      • 1970-01-01
      • 2014-04-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多