W Unity 5, jaki jest "czysty" sposób zarządzania dynamicznie tworzonymi obiektami gry?Unity 5: Czysty sposób na zarządzanie dynamicznie stworzonym GameObjects
Napisałem komponent (MonoBehavior
), który tworzy/niszczy kilka GameObjects
. Obiekty są ładowane jako część niestandardowego systemu dostosowywania, który wybiera fragmenty postaci - włosy/ubrania itp. Oznacza to, że są widoczne dla gracza, widoczne w edytorze, ale nie powinny być edytowalne w edytorze. Załadowane obiekty to siatki ze szkieletami.
Skrypt zachowuje się w ten sposób:
- Ładunki GameObjects z zasobów (dokładny przedmiot jest określony w scenariuszu, nie są one prefabrykatów)
- przymocowanie ich do pewnej części sceny (niekoniecznie do jej własny węzeł)
- Usuwa po zniszczeniu.
Usunięcie:
protected void unloadLastResource(){
if (lastResourceInstance){
if (Application.isEditor){
GameObject.DestroyImmediate(lastResourceInstance);
}
else
GameObject.Destroy(lastResourceInstance);
Resources.UnloadUnusedAssets();
lastResourceInstance = null;
}
}
utworzenia:
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;
obsługi Zniszczenie:
void OnDestroy(){
unloadLastResource();
}
To wydaje się działać prawidłowo w edytorze, ale po przełączeniu z trybu gier z powrotem w trybie edito otrzymuję wiele ostrzeżeń:
Destroying object multiple times. Don't use DestroyImmediate on the same object in OnDisable or OnDestroy.
UnityEngine.Object:DestroyImmediate(Object)
I dostać grono nowych obiektów drzew (te, które mają być usunięte - drzew pochodzą od obiektu, który został załadowany wraz z oryginalnymi „zasobów” i został dołączony) na górnym poziomie sceny hieararchy.
Więc, jak mogę obsługiwać dynamicznie stworzone obiekty gry?
Muszę wiedzieć, które flagi muszę ustawić i jakie kroki należy wykonać, aby upewnić się, że obiekt nie "wycieknie" do sceny i zostanie poprawnie zniszczony po usunięciu komponentu, który je utworzył.
Porady?
Pełna klasa zasada stosowana przez „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();
}
}
Dzięki za urywek. Obecnie analizuję to i szukam różnic w porównaniu do mojego kawałka kodu (przechowuję również instancję obiektu w zmiennej, więc powinny robić to samo) – SigTerm
Sprawdziłem twój skrypt i odkryłem, że działa dokładnie tak jak kopalnia. Pomyślałem o tym problemie, jeśli jesteś zainteresowany. Zobacz odpowiedź. – SigTerm