2015-03-30 20 views
5

Unity 5'te, dinamik olarak oluşturulmuş oyun nesnelerini yönetmenin "temiz" yolu nedir?Unity 5: Dinamik olarak oluşturulmuş GameObject'leri yönetmenin yolu temizle

Birkaç GameObjects oluşturan/yok eden bir bileşen (MonoBehavior) yazdım. Nesneler karakter - saç/giysi vb. Kısımlarını seçen özel kişiselleştirme sisteminin bir parçası olarak yüklenir. Oyuncuya görebildikleri, editörde görülebildikleri, ancak editörde düzenlenebilir olmaması gerektiği anlamına gelir. Yüklenen nesneler, iskeletlerle kafeslerdir.

komut dosyası, bu şekilde davranır:

    Kaynaklardan
  1. yükler GameObjects (tam bir nesne komut olarak belirlenir, bu prefabrik değildir)
  2. mutlaka (sahnenin bazı bölümleri için onları takılır onun kendi düğüm)
  3. Yok edildiğinde silinir.

Silme:

protected void unloadLastResource(){ 
    if (lastResourceInstance){ 
     if (Application.isEditor){ 
      GameObject.DestroyImmediate(lastResourceInstance); 
     } 
     else 
      GameObject.Destroy(lastResourceInstance); 
     Resources.UnloadUnusedAssets(); 
     lastResourceInstance = null; 
    } 
} 

Oluşturma:

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; 

İmha işleyicisi: editörü iyi çalışıyor görünüyor, ama

void OnDestroy(){ 
    unloadLastResource(); 
} 

geri oyun modundan geçiş yaptığınızda edito moduna, bir çok uyarı aldım:

Destroying object multiple times. Don't use DestroyImmediate on the same object in OnDisable or OnDestroy. 
UnityEngine.Object:DestroyImmediate(Object) 

Ve yeni nesne ağaçların demet (sözde olanlar Silinecek - ağaçlar orijinal "kaynaklar" ile birlikte yüklendi ve bağlıydı nesneden kaynaklanan) almak sahne hieararchy en üst düzeyinde.

Dinamik olarak oluşturulmuş gameobject'leri nasıl temizlerim?

Hangi bayrakların ayarlanacağını ve hangi nesnenin sahnede "sızıntı" yapmadığından ve onu oluşturan bileşeni sildiğimde düzgün şekilde imha edildiğinden emin olmak için ne yapmam gerektiğini bilmem gerekiyor.

Tekrar - - "ResourceLoader" tarafından kullanılan


Tam taban sınıfı

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(); 
    } 
} 

cevap

4

Ben bunu anladım.

sorun bu hat kaynaklanır: hiyerarşide

instance.hideFlags = HideFlags.HideAndDontSave; 

bu işaret yalnızca BİR nesneyi etkileyen ve nesnenin çocukları etkilemez. Sonuç olarak, bu bayrağı hiyerarşideki kök nesneyi ve sahneyi kurtarırsanız kök kökeni imha edilecek, ancak çocukları serileştirilecek (sahneyi yeniden yükledikten sonra denetçide görünecekleri anlamına gelir) VE Aynı nesneyi birçok kez imha etmekle ilgili uyarılar.

Sorunla başa çıkmak için, tüm hiyerarşide gezinmek ve bayrağı hiyerarşideki tüm nesnelere ayarlamak gerekir. Hangi sorunu giderir ve tüm hataları ortadan kaldırır.

void makeHierarchyHidden(GameObject obj){ 
    obj.gameObject.hideFlags = HideFlags.HideAndDontSave; 
    foreach(Transform child in obj.transform){ 
     makeHierarchyHidden(child.gameObject); 
    } 
} 

..... 
       makeHierarchyHidden (newObject); 
..... 

diskten olmayan prefabrik yükleme, ya da sadece tüm hiyerarşik nesnelerle genel durumda iken bunun sadece olursa belli değildir.

2

hata iletisi hangi olur OnDestroy() içinden bir nesne destorying çünkü kodunuzu sonsuz bir yineleme oluşturmak anlamına gelir çağrı

: Bu nesne üzerinde OnDestroy() ve benzeri ...

beni ben bütün Davranışlar için temel sınıf olarak kullanmak Bu kod parçasını paylaşalım
using UnityEngine; 
using System.Collections.Generic; 

namespace de.softfun.drawntogether { 
    public class EnhancedBehavior : MonoBehaviour { 
     private List<GameObject> linkedObjects = new List<GameObject>(); 

     protected void destroy(params GameObject[] objects) { 
      foreach (GameObject o in objects) { 
       try { 
        Destroy(o); 
       } catch { 
        continue; 
       } 
      } 
     } 

     public void LinkObjects(params GameObject[] objects) { 
      foreach (GameObject o in objects) { 
       linkedObjects.Add(o); 
      } 
     } 

     void OnDestroy() { 
      foreach (GameObject o in linkedObjects) { 
       destroy(o); 
      } 
     } 

     protected T instantiate<T>(T prefab, bool addLink = true) where T : Object { 
      T o = (T)Instantiate(prefab); 
      if (addLink && (o is GameObject)) { 
       linkedObjects.add(o); 
      } 
      return o; 
     } 

    } 
} 

burada hünerBu MonoBehaviour bağlanmıştır ve 'ebeveyn' imha alırsa yok edilmelidir GameObjects bir List toplamak olmasıdır.Bu sınıfın instantiate'u kullanırken, bu yöntemde addLinkfalse olarak ayarlanmadığı sürece, oluşturulan nesne otomatik olarak List'a eklenir.

Belki bunu veya benzerlerini kullanabilirsiniz.

+0

Snippet için teşekkürler. Şu anda onu analiz ediyorum ve kod parçamla karşılaştırıldığında farklar arıyorum (aynı zamanda değişkende nesne örneğini saklıyorum, bu yüzden aynı şeyi yapmalıdırlar) – SigTerm

+0

Komut dosyanızı inceledim ve tam olarak çalıştığını öğrendim Mayın. İlgilenirseniz, sorunu çözdüm. Cevabı gör. – SigTerm

İlgili konular