【问题标题】:How can I Require a public Variable (Prefab) to have a certain component (RigidBody) in UNITY?如何要求公共变量(预制件)在 UNITY 中具有某个组件(刚体)?
【发布时间】:2019-03-27 20:34:48
【问题描述】:

我正在尝试实现“Shoot”MonoBehaviour。 我希望它做一些非常简单的事情,它应该将 Prefab 作为“输入”(暂时将其存储在“projectile”公共变量中),然后简单地实例化它并为其 RigidBody 添加一个 Forward 力(相对于它附加到的对象,例如坦克)。

但是,如果我不小心插入了没有 RigidBody 的 Prefab,我不希望我的游戏崩溃。 (事实上​​,如果它甚至不允许我添加没有 RigidBody 的 Prefab 作为射弹,那就太好了。

我尝试过使用“RequireComponent”属性,但它看起来只适用于类。有什么方法可以做到这一点,而不必在每次我想射击时检查 Projectile 是否有刚体?

我尝试了下面的代码,但它给了我一个错误,说我不能将刚体实例化为游戏对象。这是可以理解的,但我的想法已经用完了。

public class Shoot : MonoBehaviour
{

    public Rigidbody projectile;
    public float firePower = 5f;

    public void Fire()
    {
        GameObject projectileInstance = Instantiate(projectile) as GameObject;
        //maybe add some particles/smoke effect
        projectile.GetComponent<Rigidbody>().AddForce(firePower * transform.forward);
    }
}

【问题讨论】:

    标签: unity3d components instantiation gameobject


    【解决方案1】:

    您可以在运行时添加您想要的组件,例如:

        // First check if there is no rigidbody component on the object
        if (!currentPrefab.GetComponent<Rigidbody>()){
            // Add the Rigidbody component
            currentPrefab.AddComponent<Rigidbody>();
    
            // You can also add a collider here if you want collisions
            var bc = currentPrefab.AddComponent<BoxCollider>();
    
            // And you'll have to calculate the new collider's bounds
            Renderer[] r = t.GetComponentsInChildren<Renderer>();
            for(var i=0; i<r.length; i++) {
                bc.bounds.Encapsulate(r[i].bounds);
            }
        }
    

    【讨论】:

      【解决方案2】:

      您可以检查预制件,看看它是否有像这样的刚体组件:

      if (currentPrefab.GetComponent<Rigidbody>()){
      
          // Do something
      
      }
      

      如果您作为参数输入的类型不存在,则 GameObject.GetComponent() 方法将返回 null。

      【讨论】:

        【解决方案3】:

        这里的其他人已经为您提供了一些关于如何在运行时执行此操作的示例,但是我建议您将 [RequireComponent(typeof(RigidBody))] 添加到您的射弹类(如果有的话)。

        每次您将组件附加到 gameObject 时,Unity 都会自动添加所需的组件,而不会影响游戏运行时的性能。只需将其添加到您的射弹脚本的类声明中。

        但是,您需要通过 Inspector 或 GetComponent 手动分配组件。但这可以确保您的对象附加了正确的组件。

        您需要在您的射弹上添加某种脚本才能使其正常工作。所以如果你没有,你应该使用这里指出的另一个选项。

        如果您有兴趣,可以在here找到文档。

        【讨论】:

        • 谢谢,但我有几个问题:
        • -您是否建议我应该添加一个类(例如:Projectile),它只指定基本 Projectile 所需的组件,然后在我的 Shoot Script 上而不是公共 GameObject,创建一个公共 Projectile?
        • 这有点令人困惑,因为我更习惯于 OOP 开发,而且我不太确定何时添加指定 GameObject 的类,因为它总是看起来我应该只是而是制作一个预制件。如果它是脚本(Projectile 类)的形式,我也可以以这种方式实例化一个对象
        • 如果您来自 OOP,则更容易将 gameObject 视为您的“根”对象,它附有组件(也称为实际类)。您很少实例化不是从 MonoBehaviour 派生的 C# 对象,因为它们只有在附加到游戏对象时才“工作”。简而言之:将您的类附加到您的游戏对象并将其实例化为预制件。关于我的回答:这只有在你的射弹预制件上附加了某种脚本时才有效。如果您不这样做,请使用另一个答案。仅仅为了需要一些东西而附加一个 MonoBehaviour 将是巨大的开销。
        • 让对象自己处理它们的组件并通过它们自己的脚本与它们交互是一种很好的做法。 (在您的具体示例中:ProjecileScript 处理组件并具有添加从您的 Shoot 类调用的速度的方法)我不知道这在您的具体情况下是否有意义,因为正如我已经说过的,MonoBehaviours 有巨大的开销。如果您只处理刚体的东西,请不要为每个射弹添加自己的脚本。
        【解决方案4】:

        我相信你已经在写作轨道上。您只需要通过执行以下操作来修复您的错误:

        public Rigidbody projectile;
        public float firePower = 5f;
        
        public void Fire()
        {
            if( projectile == null )
            {
                 Debug.LogError( "You forgot to provide a projectile prefab");
                 return;
            }
            Rigidbody projectileInstance = Instantiate(projectile) as Rigidbody;
            projectileInstance.AddForce(firePower * transform.forward);
        }
        

        但是,使用这种方法,您不能要求预制件具有多个组件。如果您需要这个,那么请使用其他答案提供的方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-07-05
          • 1970-01-01
          • 2020-02-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多