在 Unity 5 中,管理动态创建的游戏对象的“干净”方式是什么?
我编写了一个组件 ( MonoBehavior
),它创建/销毁了几个GameObjects
. 这些对象作为自定义自定义系统的一部分加载,该系统选择角色的部分 - 头发/衣服等。这意味着它们对玩家可见,在编辑器中可见,但不应该在编辑器中可编辑。正在加载的对象是带有骨架的网格。
该脚本以这种方式运行:
- 从资源中加载游戏对象(确切的对象在脚本中确定,它们不是预制件)
- 将它们附加到场景的某些部分(不一定附加到它自己的节点)
- 销毁时删除。
删除:
protected void unloadLastResource(){
if (lastResourceInstance){
if (Application.isEditor){
GameObject.DestroyImmediate(lastResourceInstance);
}
else
GameObject.Destroy(lastResourceInstance);
Resources.UnloadUnusedAssets();
lastResourceInstance = null;
}
}
创建:
GameObject target = getEffectiveTargetNode();
Object resource = Resources.Load(newResourceName);
instance = Instantiate(resource) as GameObject;
instance.hideFlags = HideFlags.HideAndDontSave;
instance.transform.parent = target.transform;
instance.transform.localPosition = Vector3.zero;
instance.transform.localRotation = Quaternion.identity;
instance.transform.localScale = Vector3.one;
销毁处理程序:
void OnDestroy(){
unloadLastResource();
}
这在编辑器中似乎工作正常,但是当我从游戏模式切换回编辑模式时,我收到很多警告:
Destroying object multiple times. Don't use DestroyImmediate on the same object in OnDisable or OnDestroy.
UnityEngine.Object:DestroyImmediate(Object)
我在场景层次结构的顶层获得了一堆新的对象树(那些应该被删除的树——树源自与原始“资源”一起加载并附加的对象)。
那么,我如何干净地处理动态创建的游戏对象呢?
我需要知道我需要设置哪些标志,以及我应该执行哪些步骤来确保对象不会“泄漏”到场景中并且在我删除创建它的组件时被正确销毁。
建议?
“ResourceLoader”使用的完整基类
public class BaseResourceLoader : MonoBehaviour {
public GameObject targetNode = null;
protected GameObject lastTargetNode{
get{return lastTargetNodeInternal;}
}
private GameObject lastTargetNodeInternal = null;
protected bool targetNodeChanged(){
return targetNode != lastTargetNode;
}
protected string lastResourceName{
get{return lastResourceNameInternal;}
}
private string lastResourceNameInternal = "";
//private Object lastResource;
private GameObject lastResourceInstance;
protected GameObject getEffectiveTargetNode(){
if (targetNode == null)
return this.gameObject;
return targetNode;
}
public void reloadResource(){
loadNewResource(lastResourceNameInternal, true);
}
protected void unloadLastResource(){
if (lastResourceInstance){
if (Application.isEditor){
GameObject.DestroyImmediate(lastResourceInstance);
}
else
GameObject.Destroy(lastResourceInstance);
Resources.UnloadUnusedAssets();
lastResourceInstance = null;
}
lastResourceNameInternal = "";
}
protected void loadNewResource(string newResourceName, bool forceReload){
if ((newResourceName == lastResourceNameInternal) && !forceReload)
return;
GameObject instance = null;
if (newResourceName != ""){
GameObject target = getEffectiveTargetNode();
Object resource = Resources.Load(newResourceName);
instance = Instantiate(resource) as GameObject;
instance.hideFlags = HideFlags.HideAndDontSave;
instance.transform.parent = target.transform;
instance.transform.localPosition = Vector3.zero;
instance.transform.localRotation = Quaternion.identity;
instance.transform.localScale = Vector3.one;
}
unloadLastResource ();
lastResourceInstance = instance;
lastResourceNameInternal = newResourceName;
lastTargetNodeInternal = targetNode;
}
void OnDestroy(){
unloadLastResource();
}
}