在不继承单行为的情况下实例化预制件

时间:2019-05-15 16:34:08

标签: c# unity3d

我正在尝试为我在Unity 3D中制作的游戏制作主要脚本。

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

class Main
{
    public GameObject ship;

    [RuntimeInitializeOnLoadMethod]
    static void OnRuntimeMethodLoad()
    {
        GameObject player = Object.Instantiate (ship, transform.position, Quaternion.identity) as GameObject;
    }
}

但是,这给了我一个错误:An Object Reference is Required for non-static field, method, or property 'Main.Ship'是否可以在不继承MonoBehaviour的情况下实例化对象?

2 个答案:

答案 0 :(得分:2)

您在静态方法中使用了非静态值,因此无效。

您必须从方法中删除静态变量:

void OnRuntimeMethodLoad()

或在字段中添加static:

public static GameObject ship;

注意事项

我不确定这是否可以让您轻松实现飞船,因为您将无法在编辑器中进行设置(静态字段不会显示在“检查器”窗口中)。

您将需要使用其他脚本注入它们,从资源中收集它们或在Main类中创建它们。

注射

理论上,您可以从其他脚本中进行设置,但是由于您使用的是RuntimeInitializeOnLoadMethodit,因此可能会很有挑战性。

您可以使用脚本对象OnDisable或OnEnable方法来做到这一点。

OnEnable() { Main.ship = something }

无论如何,我建议不要这样做,因为您不知道何时调用脚本。
来自RuntimeInitializeOnLoadMethod - Unity

  

注意:不能保证标记为[RuntimeInitializeOnLoadMethod]的方法的执行顺序。

资源收集者

这可能是最简单的解决方案。

您可以从Resources Folder

收集预制件
//Load a gamobject file (Assets/Resources/GameObjects/ship.prefab)
ship = Resources.Load<GameObject>("GameObjects/ship");

在主要班级创建

最后,您可以直接在Main类中创建飞船。

代码如下:

void CreateShip()
{
   ship = new GameObject();
   var shipComponent = ship.AddComponent<ComponentToAdd>();
   shipComponent.Setup();
   //add any other components
}

结论

您始终可以还原并返回另一个更简单的解决方案,例如在MonoBehaviour中调用代码。

如果您需要经理,则可以使用单身such as this

如果您确认要使用RuntimeInitializeOnLoadMethodit,我建议继续使用Resource解决方案。

答案 1 :(得分:2)

如前面的答案所述,您正在混合实例范围和类(静态)范围。

尽管提到了几种方法可以使该脚本以启动方式起作用(您可以使用静态Resources类在资产中搜索文件名),但我还是建议采取另一种方法,并使您的课程成为MonoBehaviour。尽管这对于使用c语言进行编码并希望为其代码提供清晰入口点的人们来说可能违反直觉,但在许多情况下,习惯于需要添加一个包含主对象的GameObject这一事实非常有用。脚本。

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

class ShipInstanceCreator: MonoBehaviour
{
    public GameObject ship;

    void Start()
    {
       GameObject player = Object.Instantiate (ship, transform.position,   transform.rotation) as GameObject;
   }

有什么好处? 第一个主要的好处是,从MonoBehaviour继承的所有内容都会得到UnityEditor的全面支持-因此,您将获得免费的“检查器”窗口,您可以在其中免费拖放东西,具有滑块等,您会获得“启用/禁用”复选框,当启用/禁用状态更改时,您将获得回调,您将获得本地转换组件(这常常令人惊讶地有用),发生冲突等。

Unity还可以序列化其状态,而无需手动进行操作,这意味着您可以获得对象的完全定义的生命周期(当重新加载部件的某些部分而某些部分不需要重新加载时,它在编辑器中的作用就很时髦t)。

这种脚本还可以实例化敌方船只和小行星(以其自身的变换位置和方向),并且由于它们之间的功能差异可以(并且应该)实现为给定预制件的特定行为,因此不需要实例化器类,除了它应该是一个GameObject以外,它还知道其他有关其实例的信息

最后,在一个编写良好的Unity项目中,很少有“主”类。如果将职责分解为独立的组件,并且它们之间的依赖关系应尽可能少,则效果最好(对UnityEngine的依赖关系可以)。而不是“编写主脚本”,您应该编写“ InstantiatePlayerScript”,并且很有可能已经完成了,您可以继续编写另一个定义其他行为的脚本。这就是为什么它们被称为行为。实例化玩家是一种修改场景的行为,它应该像其他对象一样生活在场景中,而不是尝试将其作为上帝对象“坐在云上”,从高处监督一切。尽管写这样的游戏绝对有可能,但是随着复杂度的增加,这种方式变得更加困难。

游戏中的某些部分可以使游戏走向全球(例如,MusicManager-您一次只能播放一种音乐,但是对于播放器而言),如果有一天您想制作自己的音乐,该怎么办游戏多人游戏?尽管Singleton Pattern(也可以在某个地方编写主类)在Unity中可以很好地完成许多工作,但是它很容易被覆盖。