Skutecznie pozbywasz się martwych obiektów w grze?


10

Korzystam z pętli for lub foreach (nie ma znaczenia), aby przeglądać wszystkie moje obiekty, gdy trzeba je zaktualizować lub narysować. Jednak gdy obiekt zostanie zabity, chcę, aby został ponownie usunięty z kolekcji.

Robię to, dodając obiekt do listy martwych obiektów, a następnie, gdy wszystko zostało narysowane i zaktualizowane, przeglądam wszystko na tej liście, usuwając również obiekty na liście z oryginalnego źródła.

Czy jest na to lepszy sposób?



2
To naprawdę nie ma nic wspólnego z odśmiecaniem, pomimo użycia słowa „śmieci” w tytule i dotychczasowych odpowiedzi, które wspominały o .NET Garbage Collector.
Andrew Russell,

Pozwoliłem sobie na zmianę słowa „śmieci” na „martwe”, aby zapobiec pomyłkom z urządzeniem do usuwania śmieci .NET.
Nevermind,

Och, jestem tego świadomy. Artykuł na temat usuwania śmieci jest nadal aktualny, ponieważ może zagrać w to, co robisz z tymi martwymi obiektami. Np. Martwe szczątki? Odłącz go od wszystkiego, zresetuj do ustawień domyślnych, umieść z powrotem w wiadrze na śmieci.
doppelgreener

Odpowiedzi:


11

Przede wszystkim: terminologia. Jeśli powiesz „lista śmieci”, ludzie pomyślą, że mówisz o śmieciarzu. Nazwijmy to „martwą listą”.

Jak zapewne odkryłeś, stąd twoje pytanie, nie możesz usuwać przedmiotów z kolekcji podczas iteracji. Jeśli Twoja kolekcja jest List<>najprostszym sposobem na usunięcie z niej przedmiotów:

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

Pamiętaj, że iterujesz wstecz . Możesz usuwać elementy podczas iteracji do przodu, ale jest to bardziej skomplikowane i wymaga goto. Nie możesz tego zrobić foreach.

Możesz wykonać usuwanie oddzielnie od pętli aktualizacji. Lub możesz połączyć go w pętlę aktualizacji. Zawsze wykonuj RemoveAtna końcu pętli - po tym punkcie w pętli list[i]nie można jej uznać za poprawną (staje się znów ważna przy następnej iteracji).

Zauważ też, że każdy obiekt ma swoją własną IsDeadflagę (jeśli używasz wzorca usuwania, możesz to zrobić IsDisposed) - tak naprawdę wcale nie musisz utrzymywać „martwej listy”.

Używanie flagi na każdym elemencie jest lepsze ze względu na wydajność, ponieważ unikasz konieczności przeszukiwania listy w celu usunięcia. Jest również preferowany przy projektowaniu - oznacza to, że każdy obiekt może łatwo sprawdzić, czy jest martwy - więc nie wywołujesz przypadkowo żadnych metod na nim (jeśli obiekty te implementują wzór jednorazowy, mogą ObjectDisposedExceptionw tym przypadku rzucić ).

Jeśli masz kolekcję inną niż a List<>, usunięcie martwych elementów z tej kolekcji może nadal wymagać utworzenia martwej listy (ponieważ usunięcie podczas iteracji może być niemożliwe). Moim zdaniem, lepiej jest zaprojektować martwą listę tuż przed jej użyciem, iterując kolekcję w poszukiwaniu IsDeadflag, zamiast starać się zachować listę, gdy obiekty są zabijane.

Gdy skończysz z martwą listą, powinieneś Clear()ją zachować, a następnie pozostawić w pobliżu, aby użyć jej później.


Zatem wzór jednorazowy jest uważany za bardziej „skuteczny”?
Jonathan Connell,

@Jathanathan: Nie rozumiem twojego pytania. IsDeadWzór jest funkcjonalnie identyczne IsDisposed. Semantyczne użycie IsDeadoznacza, że ​​utrzymujesz listę Rysuj / Aktualizuj tych obiektów, które później będą miały usunięte martwe elementy. Wzór usuwania nie oznacza tego. Ponadto wzór utylizacja nie oznacza, że można mieć niezarządzanych zasobów posiadanych przez danego obiektu (który zwykle nie jest odpowiednie dla obiektów rozgrywki).
Andrew Russell,

Możesz to zrobić za pomocą Foreach za pomocą rewersu.
shinzou,

0

W 99,9% przypadków śmieciarz (GC) zajmie się wszystkim bez żadnych problemów. Po prostu pozwól mu działać po usunięciu / unieważnieniu tych obiektów. Opóźnienie w czyszczeniu zależy od wielu czynników (na przykład, ile bloków pamięci zostało przypisanych), ale zwykle nie musisz o tym nawet wiedzieć, nie mówiąc już o tym. Jest przeznaczony do pracy. Co jest jednym z powodów, dla których używasz C #, a nie C.

Jeśli chodzi o wydajność GC w ogóle, nie przejmuj się nadmiernie, chyba że wiesz (poprzez profilowanie), że tworzy on wąskie gardło - dotyczy to tylko dość wymagających gier. W takim przypadku zajrzyj do GC.Collect () i jego różnych pułapek, abyś wiedział, kiedy należy go użyć. Sugeruję, że googling „force gc xna”, jest tam mnóstwo materiału.


Więc jeśli mam listę, której używam w moim wywołaniu Update () za każdym razem, wszystkie elementy, w których element ma wartość „null”, zostaną automatycznie wyczyszczone ORAZ usunięte?
Mathias Lykkegaard Lorenzen

@Mathias Nie. Zobacz mój komentarz do twojego pytania. Śmieciarka nie zmodyfikuje niczego, do czego nadal masz dostęp - w tym twojej kolekcji i jej zawartości.
Andrew Russell,

1
Pytanie nie ma nic wspólnego z GC, z wyjątkiem niefortunnego wyboru słowa „śmieci”.
Nevermind
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.