Bir oyunda ölü nesnelerden etkili bir şekilde kurtulmak mı?


10

Güncellenmesi veya çizilmesi gerektiğinde tüm nesneler arasında döngü için for döngüsü veya foreach döngüsü (önemli değil) kullanıyorum. Ancak, bir nesne öldürüldüğünde, koleksiyondan tekrar kaldırılmasını istiyorum.

Bunu bir ölü nesneler listesine ekleyerek yapıyorum ve sonra her şey çizilip güncellendiğinde, listedeki nesneleri orijinal kaynaktan da kaldırarak bu listedeki her şeyi gözden geçiriyorum.

Bunu yapmanın daha iyi bir yolu var mı?



2
Bu, başlıkta "çöp" kelimesinin kullanılmasına ve şimdiye kadar .NET Çöp Toplayıcısından bahseden cevaplara rağmen, çöp toplama ile hiçbir ilgisi yoktur.
Andrew Russell

.NET çöp toplayıcısıyla karışıklığı önlemek için "çöp" kelimesini "ölü" olarak değiştirme özgürlüğünü aldım.
Nevermind

Oh bunun farkındayım. Çöp toplama makalesi hala önemlidir, çünkü bu ölü nesnelerle yaptığınız şeylerle oynayabilir. Ölü kalıntılar mı? Her şeyden bağlantısını kesin, varsayılanlara sıfırlayın, çöp kovasına geri koyun.
doppelgreener

Yanıtlar:


11

Her şeyden önce: terminoloji. "Çöp listesi" derseniz, insanlar çöp toplayıcı hakkında konuştuğunuzu düşüneceklerdir. Buna "ölü liste" diyelim.

Muhtemelen keşfettiğiniz gibi, bu nedenle sorunuz, bir koleksiyondan öğeleri yineleyerek kaldıramazsınız. Koleksiyonunuz bir List<>öğe ise, öğeleri ondan kaldırmanın en basit yoludur:

for(int i = list.Count-1; i >= 0; --i)
{
    if(list[i].IsDead)
        list.RemoveAt(i);
}

Geriye doğru yinelediğinizi unutmayın . İleriye doğru devam ederken öğeleri kaldırabilirsiniz, ancak bu daha karışıktır ve a gerektirir goto. İle yapamazsın foreach.

Kaldırma işlemini güncelleme döngünüzden ayrı olarak yapabilirsiniz. Veya güncelleme döngünüzde birleştirebilirsiniz. Her zaman RemoveAtdöngünün sonunda - döngüdeki bu noktadan sonra list[i]geçerli kabul edilemez (bir sonraki yinelemede tekrar geçerli olur).

Ayrıca, her nesnenin kendi IsDeadbayrağına sahip olduğunu unutmayın (elden çıkarma desenini kullanıyorsanız, bunu yapabilirsiniz IsDisposed) - aslında bir "ölü liste" tutmanıza gerek yoktur.

Kaldırmak için listede arama yapmaktan kaçındığınız için her öğede bir bayrak kullanmak performans için tercih edilir. Ayrıca tasarım için de tercih edilir - her bir nesnenin ölü olup olmadığını kolayca kontrol edebileceği anlamına gelir - böylece yanlışlıkla herhangi bir yöntemi çağırmazsınız (bu nesneler tek kullanımlık desen uyguluyorsa, ObjectDisposedExceptionbu durumda atabilirler ).

A dışında bir koleksiyonunuz varsa List<>, o koleksiyondan ölü öğelerin kaldırılması yine de bir ölü listenin oluşturulmasını içerebilir (yineleme sırasında kaldırma mümkün olmayabilir). Benim düşünceme göre, IsDeadlisteyi nesneler öldürülürken korumaya çalışmak yerine, bayrakları aramak için koleksiyonu tekrarlayarak, ölü listeyi kullanılmadan hemen önce oluşturmak daha güzel, tasarım açısından daha iyi.

Ölü bir listeyle işiniz bittiğinde, listeyi Clear()daha sonra yeniden kullanmak için saklamanız gerekir.


Öyleyse tek kullanımlık desen daha 'etkili' olarak kabul edilir mi?
Jonathan Connell

@Jonathan: Sorunu anlamıyorum. IsDeadDesen işlevsel özdeş IsDisposed. Anlamsal olarak kullanmak IsDead, ölü nesnelerin daha sonra kaldırılacağı bu nesnelerin bir Çiz / Güncelle listesini tuttuğunuz anlamına gelir. Bertaraf düzeni bunu ima etmez. Ayrıca, elden çıkarma modeli , söz konusu nesne tarafından yönetilen (genellikle oyun nesneleri için uygun olmayan) yönetilmeyen kaynaklara sahip olabileceğiniz anlamına gelir.
Andrew Russell

Bunu ters kullanarak kullanarak foreach ile yapabilirsiniz.
shinzou

0

Zamanın% 99,9'u, çöp toplayıcı (GC) sorunsuz her şeyi halledecektir. Bu nesneleri sildikten / kaldırdıktan sonra çalışmasına izin verin. Temizleme işleminde, bir dizi faktöre bağlı olan bir gecikme vardır (örneğin kaç bellek bloğu atandı), ancak endişelenmenize izin vermeyin. Sadece çalışmak için tasarlanmıştır. C'yi kullanmamak için C # kullanmanızın nedeni budur.

Genel olarak GC performansı, bunun bir darboğaz yarattığını (profilleme yoluyla) bilmediğiniz sürece kendinizi aşırı endişe etmeyin - bu genellikle oldukça zorlu oyunlarda. Bu durumda, GC.Collect () ve çeşitli tuzaklarına bakın, böylece ne zaman kullanmanın uygun olduğunu bilirsiniz. Ben googling "kuvvet gc xna" öneririm, orada bol malzeme var.


Bu yüzden her defasında Update () çağrımda kullandığım bir listem varsa, öğenin "boş" olduğu tüm öğeler otomatik olarak temizlenir VE kaldırılır?
Mathias Lykkegaard Lorenzen

Sorunuz hakkındaki yorumuma bakın. Çöp toplayıcı, koleksiyonunuz ve içeriği dahil olmak üzere erişebileceğiniz hiçbir şeyi değiştirmez.
Andrew Russell

1
Soru yok bir şey kelime "çöp" talihsiz bir seçim hariç, GC ile ilgisi yok.
Nevermind
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.