【问题标题】:Proper way to "spawn" game objects. (I want to spawn projectiles)“生成”游戏对象的正确方法。 (我想产生弹丸)
【发布时间】:2021-10-13 01:34:10
【问题描述】:

大家好,我创建了以下类在我的游戏中充当“子弹”,但我不知道如何使用我想要的参数(在运行时确定)构造这些子弹对象并在游戏中生成它们。

我的第一次尝试是这样的:

 if (canShoot())
        {
            shotCoolDown = FRAMES_BETWEEN_SHOTS;
            Bullet bullet = new Bullet().setLoft(LOFT).setWobble(WOBBLE).setInitialVel(INITIAL_VEL).setDirectionOffset(internalRecoil.getRecoil());
        }

但我从统一编辑器收到以下警告:

您正在尝试使用“new”关键字创建 MonoBehaviour。这是不允许的。 MonoBehaviours 只能使用 AddComponent() 添加。或者,您的脚本可以继承自 ScriptableObject 或根本不继承基类

生成这些项目符号并根据需要设置字段的正确方法是什么?

更多信息在这里是子弹类

 public class Bullet : MonoBehaviour
{
    private Rigidbody rigidbody;
    private float wobble;
    private float loft;
    private float initialVel;
    private Vector2 initialDirectionOffset;
    private bool wobbleDirection = false;
    
    private void Awake()
    {
        this.rigidbody = this.GetComponent<Rigidbody>();
    }

    private void Start()
    { 
        transform.Rotate(initialDirectionOffset); 
        rigidbody.AddForce(initialVel*transform.forward);
        rigidbody.AddForce(loft*transform.up);
    }

    private void FixedUpdate()
    {
        if (wobbleDirection)
        {
            rigidbody.AddForce(transform.right * wobble);
            wobbleDirection = false;
        }
        else
        {
            rigidbody.AddForce(-transform.right * wobble);
            wobbleDirection = true;
        }
    }

    public Bullet setWobble(float wobble)
    {
        this.wobble = wobble;
        return this;
    }
    
    public Bullet setLoft(float loft)
    {
        this.loft = loft;
        return this;
    }
    
    public Bullet setInitialVel(float initialVel)
    {
        this.initialVel = initialVel;
        return this;
    }

    public Bullet setDirectionOffset(Vector2 offset)
    {
        this.initialDirectionOffset = offset;
        return this;
    }
}

有关更多信息,这里是产生子弹的完整“枪”类。

public class Gun : MonoBehaviour
{
    private int FRAMES_BETWEEN_SHOTS = 10;
    private int shotCoolDown = 0;
    private const float LOFT = 100F;
    private const float WOBBLE = 100F;
    private const float INITIAL_VEL = 100F;
    private Vector3 directionOffset;
    private Recoil internalRecoil;
    

    private void Awake()
    {
        internalRecoil = this.GetComponent<Recoil>();
        if (internalRecoil == null)
        {
            throw new Exception("Could not find recoil component");
        }
    }

    private void FixedUpdate()
    {
        if (shotCoolDown > 0)
        {
            shotCoolDown--;
        }
    }

    private bool canShoot()
    {
        return shotCoolDown == 0;
    }

    public void performShoot()
    {
        if (canShoot())
        {
            //need to have a recoil component that reacts to bullet fire. then adjusts back to 0,0,0
            shotCoolDown = FRAMES_BETWEEN_SHOTS;
            Bullet bullet = new Bullet().setLoft(LOFT).setWobble(WOBBLE).setInitialVel(INITIAL_VEL).setDirectionOffset(internalRecoil.getRecoil());
        }
    }
}

我的第二次尝试看起来像:

 GameObject.Instantiate(new Bullet().setLoft(LOFT).setWobble(WOBBLE).setInitialVel(INITIAL_VEL)
                .setDirectionOffset(internalRecoil.getRecoil()));

这是正确的做法吗???

【问题讨论】:

  • 我会创建一个子弹预制件。另外,请记住 Unity C#与 .NET 或 Mono C# 相同。在幕后有很多编译器魔法来连接StartAwake 之类的东西。 (这就是为什么让它们publicprivate 无关紧要。)看看 Instantiate (docs.unity3d.com/ScriptReference/Object.Instantiate.html)。
  • @3Dave 是的,成功了!对于任何疑问,我在统一编辑器中创建了一个新游戏对象,将子弹脚本添加到它和任何其他组件中。需要子弹(刚体)然后在枪中我声明一个公共子弹预制件;然后在统一编辑器中单击并将我刚刚创建的子弹游戏对象拖到该字段中。
  • 很高兴它成功了。我试图同时浏览筷子、生鱼片和键盘,这增加了响应延迟。
  • 一件事:我知道流利的语法在某些领域风靡一时,但不要把所有这些废话放在同一行。它使调试几乎不可能。
  • 同意。我必须安装一个 linter/formatter

标签: c# unity3d


【解决方案1】:

正如 3Dave 所提到的,最好的方法是实例化一个预制件。假设您将处理多个射弹,我喜欢将其分离为一个实用函数,用于在给定位置实例化预制件。

public static class UnityUtil {

    public static GameObject instantiatePrefab(
        Object prefab, 
        Vector3 position,
        Transform? parent = null
    ){
        // Create an instance of the prefab
        GameObject instance = Object.Instantiate(prefab, position, Quaternion.identity) as GameObject;

        // Set the parent
       if(parent != null){
          instance.transform.parent = parent;
       }

       return instance;
    }

}

然后你可以有类似的代码

Transform projectileHolder;
GameObject myBulletPrefab;
Vector3 bulletPosition;

...setup variables...


var BulletGameObj = UnityUtil.instantiatePrefab(myBulletPrefab, bulletPosition, projectileHolder);
Bullet bullet = BulletGameObj.GetComponent<Bullet>();

我在我的 util 中保留了一些其他函数来处理通用的游戏对象案例,你可以see my full UnityUtil class here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多