【问题标题】:How do non-instantiated loaded Prefabs compare to instantiated ones?非实例化加载的预制件与实例化的预制件相比如何?
【发布时间】:2017-06-15 05:10:40
【问题描述】:

示例

在 Unity5 中,假设名为“SomeObject”的 GameObject 作为预制件存储在 Assets/Resources/SomeObject.prefab,我知道我可以按如下方式创建预制件的实例:

GameObject prefab   = Resources.Load<GameObject>("SomeObject");
GameObject instance = GameObject.Instantiate(prefab);

一旦执行,instance GameObject 将是原始“SomeObject”预制件的副本,并将被放置在名为“SomeObject(Clone)”的当前活动场景中。


据我了解,GameObject prefab 代表实际的预制资产,对其所做的任何更改(设置名称、添加组件等)都会写入原始预制资产,这些更改即使在退出编辑器后仍然存在播放模式。

问题

  1. 由于所有游戏对象通常都存储在一个场景中,并且上面示例中GameObject prefab 上的scene 属性似乎是未加载/无效/未命名,我应该将这个特殊的游戏对象确切地考虑在哪里?我似乎可以用它做所有我可以用普通游戏对象做的事情,但在层次/场景视图中不可见。

    它是有效地处于某种不确定状态,还是特殊的 PseudoScene?它似乎在 LoadSceneMode.Single 场景更改中持续存在,但不像特殊的 DontDestroyOnLoad 场景,当对象被传递到 GameObject.DontDestroyOnLoad(...) 时会被移动到。

  2. 在上述示例中,prefabinstance 之间是否还有其他值得注意的区别,除了生命周期变化、无效场景和彼此不同的对象(具有不同的 GetInstanceID() 等)?

  3. 由于在prefab上调用GameObject.Instantiate(...) 会产生一个在有效场景中的游戏对象,有没有办法手动创建处于类似“无场景”状态的游戏对象?我知道 Unity 打算让所有游戏对象都出现在场景中,所以这纯粹是一个学术问题。

我曾尝试查看functions involveddocumentation,但没有人深入了解当您在预制资源上调用Resources.Load 时具体发生的事情的技术细节。

【问题讨论】:

  • 正如你可能告诉我的那样,我一次有效地推了 3 个问题,我现在缺乏直觉,无法真正知道我不知道的是什么,如果这样的话感觉。再试一次:由于 Resources.Load 产生的 GameObject 处于无法手动创建的状态,我很好奇这些差异的确切性质,并希望对幕后发生的事情有更多了解的人可以提供见解进入这里使用的系统,这可能不会从普通文档中立即显现出来。对于无法更清楚地表达这一点,我深表歉意。

标签: c# unity3d unity3d-editor unity3d-5


【解决方案1】:

1.我到底应该把这个特殊的游戏对象放在哪里?

它在一个单独的文件中,并没有在场景中引用。一旦Resources.Load&lt;GameObject&gt;("SomeObject");被调用,它就会被加载到内存中,等待GameObject.Instantiate被调用时使用。

如果它被声明为public GameObject prefab; 并从编辑器而不是GameObject prefab Resources.Load&lt;GameObject&gt;("SomeObject"); 分配,它将在场景加载时自动加载到内存中。

2.prefab和object之间还有其他值得注意的区别吗?

是的。

无法使用DestroyDestroyObject 函数销毁预制件。必须使用DestroyImmediate 函数将其销毁,方法是将true 传递给它的第二个参数:DestroyImmediate(prefab, true);

3.有没有办法手动创建类似“无场景”状态的游戏对象?

不,无法手动创建处于类似“无场景”状态的游戏对象。

虽然你可以伪造它。

最接近的方法是通过修改 GameObjects 的 hideFlags 变量,使 GameObject 在 Editor 的 HierarchyInspector 选项卡中不可见,然后停用该 GameObject。 p>

GameObject obj = new GameObject("SomeObject");
obj.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;

之后,停用 GameObject:

obj.SetActive(false);

现在,游戏对象在编辑器中是不可见的,在场景和游戏视图中也是不可见的。


预制件和典型的游戏对象之间并没有太大的区别。 Prefab 只是一个包含 GameObject 的容器,以便它可以在场景之间重复使用和共享。修改一个预制件将更新它的任何实例。

想象一下,当场景中有数百个相同类型的游戏对象并且需要修改所有这些对象时。使用预制件,您只需修改其中一个或只修改预制件,然后单击 Apply 即可更新其他实例。这是您唯一应该想到的预制件。

【讨论】:

  • 我也很好奇prefab gameObject和原始prefab之间的链接是怎么建立的,又是怎么马上序列化的。戳github.com/MattRix/UnityDecompiled 似乎Resources.Load 最终导致了一个外部函数,所以它位于Unity C++ 端的某个地方。一位朋友指出,预制件可能是使用 GameObject .net 接口的专用 C++ 对象。有什么想法吗?
  • 我必须通过.Net reflector 来查看这个以进行验证。它正在调用一个本机 C++ 函数,该函数采用预制件的路径和预制件的预制件类型:public static extern Object Load(string path, Type systemTypeInstance);。我认为 C++ 端将使用提供的路径加载文件,然后将该预制文件中的数据反序列化到内存中,然后将其返回为Object。预制文件格式是专有的,因此除非您为 Unity 工作并拥有 C++ 源代码,否则很难猜测其中的内容。
  • 对于第一次在这里了解hideFlags 的其他人,可能还值得附加HideFlags.HideFlags.DontSave 或仅使用HideFlags.HideAndDontSave,因为有你看不到的对象堆up 可能是一个潜在的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-04
  • 2014-05-27
  • 1970-01-01
相关资源
最近更新 更多