2013-08-19 13 views
5

Tworzę grę opartą na płytkach 2D. Używam poszarpanej tablicy 2D do przechowywania liczby całkowitej, a renderer rysuje określony obraz w zależności od tego, jaka jest ta liczba całkowita. Mam tę część mojego kodu działającego, jednak doszedłem do punktu, w którym nie jestem pewien, jak postępować dalej.C# Arrays - Używanie ich do przechowywania poziomu gry

Gdy odtwarzacz przechodzi przez grę, muszę mieć możliwość przechowywania informacji o każdej komórce w tablicy 2D, takich jak poziom światła lub liczba kliknięć przez użytkownika tej komórki lub obrót wartość obrazu w tej komórce lub poziom alfa dla tego obrazu itp.

Jedyny sposób, w jaki mogę to zrobić, to stworzyć tablicę 2D, tak jak zrobiłem to wcześniej, dla każdej informacji "Używam. Tak więc na przykład:

AlphaLevel[][] 
NumberOfTimesClicked[][] 

A potem, jeśli potrzebne (na przykład), aby sprawdzić, ile razy użytkownik kliknął komórka 5,5 mogę zrobić NumberOfTimesClicked [5] [5], lub jeśli potrzebowałem ustaw rotację, którą mógłbym wykonać SetRotation [5] [5] = 90.

Rzecz, której nie jestem pewien, to to, jak wydajna jest, posiadanie tablicy dla każdej informacji nie wydaje się, że pamięć jest wydajna.

Czy pomysł mam dobre rozwiązanie, czy jest lepszy sposób, o którym nie myślałem?

Każda rada byłaby świetna! Dzięki

+0

Może Ci się przydać [Wzór ciężaru] (http://en.wikipedia.org/wiki/Flyweight_pattern). – JDB

+6

["1. Spraw, aby działało 2. Spraw, aby działało prawidłowo 3. Spraw, aby działało szybko."] (Http://c2.com/cgi/wiki?MakeItWorkMakeItRightMakeItFast) Próbujesz zacząć od kroku 3. Start w kroku 1 i zoptymalizuj, gdy odkryjesz wąskie gardła. – cdhowie

Odpowiedz

22

Wykonaj obiekt Tile, który zawiera informacje, takie jak AlphaLevel i NumberOfTimesClicked, i utworzyć poszarpany układ tych obiektów. Następnie potrzebujesz tylko jednej poszarpanej tablicy do przechowywania wszystkich twoich informacji i jest ona zorganizowana ładniej, ponieważ możesz łatwo znaleźć wszystkie właściwości, które ma Tile.

Jeśli interesuje Cię optymalizacja pamięci, NPSF3000 ma słuszność mówiąc, że struktury będą nieznacznie lepsze. Upewnij się, że wiesz, jakie wartości i typy referencji różnią się przed ich użyciem.

Przechowywanie danych w mniejszym formacie zawsze będzie większe niż przechowywanie danych w ogóle. Oprócz pracy nad kompresją bieżących danych w jak największym stopniu, spójrz na sposoby przechowywania starych danych, których nie potrzebujesz na dysku, lub odrzucając dane, które możesz wygenerować później.

Ostatnia uwaga: czy na pewno chcesz ją skompresować? Kiedy w przeszłości pracowałem nad systemami płytek 2D, odkryłem, że w rzeczywistości przechowuję dodatkowe dane, aby poprawić prędkość, ponieważ nie korzystałem z tak dużej ilości pamięci. Przeprowadź kilka liczb, aby upewnić się, że faktycznie używasz wystarczającej ilości pamięci, aby optymalizacje były tego warte.

+0

To jest poprawne podejście dla języka C#. Używanie obiektów do przechowywania danych każdego kafelka ma więcej sensu i będzie bardziej wydajne niż wielowymiarowe tablice danych płytek. Ponadto użyłbym generycznych kolekcji C# zamiast poszarpanych tablic. Generalnie kolekcje ogólne są zarządzane znacznie wydajniej w języku C#. –

+0

@NickZimmerman Podejrzewam, że się mylisz w obu przypadkach. Obiekty nie są zbyt wydajne w porównaniu do tablic danych (potrzeba więcej miejsca, gorzej w pamięci podręcznej, wolniej itd.). Ponadto nie widzę, jak "kolekcja generyczna" byłaby szybsza niż tablica poszarpana z reguły. – NPSF3000

+1

@ NPSF3000 Ogólne kolekcje są często szybsze * dla ich zamierzonego celu *. Na przykład 'Dictionary' jest bardzo szybki dla odnośników z klucza, w porównaniu do przeszukiwania tablicy dla obiektu/struktury z tym samym kluczem, ze względu na jego wewnętrzne hashowanie. Masz jednak rację, że nie są one z reguły szybsze; nie ma złapania wszystkich rozwiązań. To tylko spojrzenie na twój przypadek użycia i zobaczenie, co jest najlepsze. –

5

Rzecz nie jestem pewien, o to, jak skuteczne jest to, że ma szereg dla każdej informacji nie wydaje się, że pamięć wydajny.

Krótka odpowiedź: Możesz użyć Structs jako alternatywy - pozbyłaby się dodatkowych tablic po prostu "przechowując wszystko razem".


Długi Odpowiedź:

reprezentacja tablicy jest coś takiego, co następuje: Header:Data gdzie nagłówek jest 4 bajtowy Int32.

Obecnie Twoja pamięć może wyglądać mniej więcej tak:

IIII:B:B:B //Byte array (e.g. alpha level) 
IIII:SS:SS:SS //Short array (e.g. num times clicked) 
IIII:B:B:B //Byte array 

Where I, B i S reprezentowania bajt int, Byte i Short odpowiednio. Z Struct mogą przechowywać je wszystkie razem - tak:

IIII:BSSB:BSSB:BSSB 

Jeśli używasz klas zamiast wygląda zupełnie inaczej, jako klasa są przechowywane w tablicy jako odniesienie do lokalizacji danych:

IIII:RRRR:RRRR:RRRR 
BSSB //These can be stored anywhere in memory 
BSSB //These can be stored anywhere in memory 
BSSB //These can be stored anywhere in memory 

Podczas gdy struktura może zaoszczędzić trochę pamięci, nie jest to dużo. Korzystanie z klas zamiast faktycznie kosztuje pamięć! Jednak pamięć, której używa, nie musi być ciągła, co może pomóc w przechowywaniu dużych zbiorów danych (na przykład 1GB +) esp. na 32-bitowych komputerach ... ale to dyskusja na inny dzień.

Oczywiście to czysto mówi o wydajności wielkości pamięci, jeśli obciążenie pracą wykonuje obliczenia dla poszczególnych pól, wtedy poszczególne tablice będą o wiele bardziej przyjazne pamięci podręcznej - i dlatego wydajne. I odwrotnie, jeśli masz tendencję do wykonywania obliczeń na podstawie kafelka, wówczas odwrotność jest prawdą. Klasy są nieefektywne w przypadku pamięci masowej, ale jeśli pasują do twojego paradygmatu kodowania, mogą znacznie ułatwić rozwój. Ponadto klasy są dobre, gdy wiele obiektów wymaga odniesienia do danych , które mogą nawet zaoszczędzić pamięć przez zmniejszenie liczby duplikatów!

Mam nadzieję, że to pomaga, jak widać dobre zrozumienie podstaw pomaga trochę. Najważniejsze jest jednak, aby ocenić swój czas i czy/kiedy wydajność staje się testem i testem wydajności dla samego siebie.

Zastrzeżenie: Napisane wcześnie rano, może być źle/mają braki itp

+0

Nie jestem pewien, jakie zasady podąża C#, ale wiem, że w GCC nie masz żadnej gwarancji, że dane struktury są ciasno upakowane. Czasami dodaje dopełnienie w strukturze między danymi, jeśli uważa, że ​​kod ten można przyspieszyć, robiąc to. Wątpię, że wpłynie to na OP, po prostu zostawiam to na wypadek, gdyby ktoś robił coś bardziej skupionego na pamięci. –

+0

@MikePrecup Dobry punkt. Gdybyś podążał tą drogą i pojawiły się problemy, zajrzałbym do http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutoutube.pack.aspx i podobnych. – NPSF3000

0

Cztery podejścia są:

  • Zdefiniuj poszarpaną tablicę dla każdego atrybutu posiadanych przez każdą komórkę mapy
  • Kombajny wiele atrybutów komórki do typu struktury (eksponuj pola publiczne zamiast właściwości dla najlepszej wydajności i semantyki) i zdefiniuj poszarpaną tablicę tych
  • Definiowanie niezmiennej klasy typu klasy e, który przechowuje wiele atrybutów komórki, definiuje poszarpaną tablicę tych i inicjuje wszystkie elementy za pomocą instancji domyślnej.
  • Zdefiniuj zmienny typ klasy, który zawiera wiele atrybutów komórki, zdefiniuj poszarpaną tablicę tych elementów, zainicjuj każdy element tablicy, aby odwoływał się do odrębnej instancji obiektu, i nigdy nie pisz do tablicy ponownie (tylko zmutuj instancje, do których jest ona przypisana) zawiera odniesienia).

Jeśli istnieją pewne grupy atrybutów, które prawdopodobnie będą dostępne blisko siebie, a inne nie, można osiągnąć optymalną wydajność przy użyciu drugiego podejścia, grupując rzeczy, które często idą w parze. Jeśli istnieją pewne kombinacje wartości atrybutów, które będą występować znacznie częściej niż inne, może być sens łączyć te konkretne atrybuty w niezmienną klasę. Ogólnie rzecz biorąc, w przypadku typu danych wewnętrznych moją preferencją byłoby użycie poszarpanej tablicy typu struktury o otwartym polu.

Dla tej aplikacji, mantra, której struktury powinny być niezmienne, jest po prostu błędnie. Semantyka zmiennych struktur różni się od klas; każdy, kto tego nie rozumie, może uznać je za mylące. Nie znaczy to jednak, że należy unikać używania struktur. Oznacza to raczej, że każdy, kto chce być dobrym programistą, powinien zrozumieć, jak działają struktury. Wszystkie struktury o odkrytych polach zachowują się w ten sam sposób, a uczenie się, jak zachowują się wszystkie takie struktury, nie powinno zająć dłużej niż nauczenie się korzystania z typowej klasy Framework.

Powiązane problemy