我最近一直在尝试统一对象池,以同时加快多个游戏对象的实例化。
然而,由于这些是相当复杂的对象,当它们回到池中时,我需要重置它们。
我读到使用 ScriptableObject 可能是存储默认值以便轻松重置的好方法。但为了做到这一点,我需要在运行时加载一个新的 ScriptableObject 来存储对象的实际值。
所以在伪代码中,我会有一个带有public MyScriptableData data
and的类public MyScriptableData defaults
1) 使用默认的 ScriptableObject 创建新的池化对象data = defaults;
;
2) 做一些在对象生命周期内改变脚本对象值的事情
3) 停用,然后将池化对象返回到池中,将 scriptableObject 重置为其默认值(data = defaults;
再次)。
我有3个主要问题:
A)我不确定如何实际实现这一点。在我看来,在第 2 步中,默认值将被更改。因此,重置为默认值将无济于事。我想过使用创建我的可编写脚本对象的新实例
data = ScriptableObject.CreateInstance<MyScriptableData>();
但是我将如何从 复制默认值defaults
,以确保永远不会更改默认值?我希望默认值可以在统一编辑器中作为资产进行编辑。
B) 如果我使用 CreateInstance,性能会很差吗?我做这个对象池的全部原因是为了降低对象实例化的性能成本。我不想通过实例化可编写脚本的对象来重新引入慢代码。
C) 这种方法好吗?还是有更好的方法在返回池之前重置对象?
根据一些答案进行编辑:我已经有一个包含一长串字段的设置,然后将这些字段的默认值存储在字典中。但是我发现每次我想添加/更改/删除一个字段时,我都必须在几个地方更改代码
尝试的解决方案(但错误,见下文):我为 ScriptableObject 创建了一个扩展方法:
using UnityEngine;
using System.Reflection;
public static class ScriptableObjectExtension {
public static T ShallowCopy<T> (this T orig) where T : ScriptableObject {
T copiedObject = ScriptableObject.CreateInstance<T> ();
FieldInfo[] myObjectFields = orig.GetType ().GetFields (
BindingFlags.NonPublic | BindingFlags.Public |
BindingFlags.Instance);
foreach (FieldInfo fi in myObjectFields) {
fi.SetValue (copiedObject, fi.GetValue (orig));
}
return copiedObject;
}
}
最终解决方案:
上面的脚本用于克隆可编写脚本的对象,但是,我似乎在使用该解决方案时走错了路。
下面的几个人指出,对于大多数应用程序来说,池化在统一中并不那么重要。我最初尝试使用池化,因为根据分析器,我的帧速率约为 30-15 fps,我认为池化将有助于改善这一点。
根据评论我挖得更深一点,发现有一个名为 LogStringToConsole 的过程。我对自己说,这能像我的 Debug.Log 语句那样简单吗?我删除了它们,巨大的尖峰消失了。显然 Debug.Log 会导致巨大的性能问题。现在我的帧速已经超过 60fps。正因为如此,我决定不合并这些对象(但在另一种场景中,我仍然在更简单的对象上使用池,这些对象每秒会产生几次)。这意味着我根本不需要担心这里的可编写脚本的对象。我现在拥有并实例化加载一个预制件和一个 Init 方法来进行设置,并且对象在用完时被销毁。
当我重新使用实例化/销毁时,我没有注意到性能有显着变化。感谢所有的回复!