Jul 22

W grach często zachodzi potrzeba ciągłego, dynamicznego tworzenia i niszczenia różnych obiektów. Warto więc się zastanowić nad optymalizacją procesu alokacji pamięci pod te obiekty. Jak wiadomo new do najszybszych operacji nie należy, dlatego chciałbym wam przedstawić metodę o nazwie ‘Memory pool’ (i jej implementacje w C++), która uwalnia nas od konieczności ciągłego wywoływania operatora new.

Memory Pool polega na alokowaniu dużego bloku pamięci, podzieleniu go na kawałki o stałej długości i zwracania poszczególnych bloków gdy tworzymy jakiś obiekt. Implementacja która tu przedstawię jest bardzo optymalna i wymaga przechowywania tylko 2 wskaźników (żadnych niepotrzebnych wektorów ‘wolnych indeksów’).

A więc zaalokujmy sobie 20 bajtów pamięci (jej adres zapiszmy sobie do wskaźnika Pool) i podzielmy go na kawałki po 4 bajty

pic1
Po zaalokowaniu naszego bloku do każdego kawałka zapisujemy adres następnego kawałka. Na ostatnim bloku wpisujemy NULL. Będzie nam potrzebny jeszcze dodatkowy wskaźnik który będzie przechowywał adres pierwszego wolnego kawałka

pic2
Warto zaznaczyć jedną rzecz, adresy do następnego wolnego kawałka są zapisane bezpośrednio w miejscu normalnie przeznaczonym na obiekt (a nie jako dodatkowa zmienna w jakimś kontenerze). Nakłada to na nas wymóg minimalnego rozmiaru kawałka jako 4 bajty (8 bajtów na x64).

Jak wygląda alokacja? Sprawdzamy wskaźnik FreeChunk. Wiemy że wskazuje on miejsce gdzie jest zapisany wskaźnik (nazwijmy go tutaj next) do następnego wolnego kawałka pamięci. Wiec zwracamy użytkownikowi wartość FreeChunk a wskaźnik next zapisujemy do FreeChunk

Po jednej alokacji sytuacja przedstawiała by się tak:

ilustracja8
A po 3 tak

ilustracja6
Dojście do ostatniego kawałka spowoduje zapisanie NULL do FreeChunk. Co przy kolejnej alokacji wywoła błąd alokacji (zwracamy NULL, rzucamy std::bad_alloc(), co kto woli :D ).

Zwolnienie wygląda równie prosto jak alokacja. Do zwalnianego kawałka zapisujemy aktualną zawartość FreeChunk a następnie do FreeChunk zapisujemy adres tego zwalnianego kawałka.

Czyli gdybyśmy chcieli zwolnić kawałek np. Offset4 (mając stan jak na ostatniej ilustracji) to kolejno wykonujemy:

  1. Do Offset4 zapisujemy wskaznik FreeChunk czyli Offset12
  2. Do FreeChunk przypisujemy wskaznik na kawałek który zwalniamy czyli Offset4

Kod zródłowy: cmemorypool.h


Jul 16

Ostatnio pracuje sobie nad grą 2D która, była by reprezentacją możliwości mojego silnika Omikron2. Gra nazywa sie Tank vs Tank (albo krócej – TvsT). Na pierwszy rzut oka gra może przypominać  Scored Earth. Ot widok z boku, czołgi i masa broni z której można niszczyć przeciwników. Jednak projektując TvsT nie chciałem zrobić klona ale możliwie coś innego i przyjemnego do zabawy po sieci.

Czy tak będzie ocenicie niedługo sami tymczasem podaje najważniejsze cechy gry:

  • Gra lokalna albo przez sieć od 2 do 8 gracz.
  • SDK do tworzenia własnych modyfikacji.
  • 5 broni z której każda wymusza inny styl gry.
  • Dziesiątki bonusów urozmaicające rozgrywki.
  • Niskie wymagania sprzętowe (brak shaderów).
  • Ponad 50 Achivmentów do zdobycia.
  • Przyjemna dla oka grafika.

Rozpisze się może nieco więcej o podpunkcie drugim. Gra daje możliwość tworzenia własnych modyfikacji z którymi łatwo można się dzielić z innymi graczami (łatwo znaczy możliwe przeźroczyście dla gracza). Powiedzmy że stworzyłeś modyfikacje do gry (albo ściągnąłeś z internetu). Zakładasz serwer, koledzy dołączają się do ciebie i już jesteście gotowi do gry w ten własnie mod. Silnik gry zadba o to aby każdy klient miał wszystkie potrzebne skrypty i dane. Podobne rozwiązanie zastosował Valve w grze Left4Dead

Aktualnie w produkcji jest wersja Alfa2 (jedynka była niedawno testowana w zamkniętym gronie) którą mam zamiar zaprezentować publicznie na moim blogu i być może na portalu gamedev.pl.


May 31
Wstążki w akcji

Wstążki w akcji

Czym by były gry bez efektów specjalnych… Wybuchy, błyski, iskry, ogień i wiele innych. Bez tego gra, przypominała by bardziej program do oglądania wnętrz i świecących w niej modeli a nie super produkcje rodem z Valve. Większość tych efektów da się uzyskać przy pomocy tzw. „Cząsteczek”. W tej notce jednak chciałbym się skupić na efekcie trochę mniej osławionym, mianowicie na wstążkach (ang. ribbons).

Wstążka jest to byt (często ciągnący się za jakimś obiektem) pozostawiający za sobą „ogon”, który stopniowo zanika wraz z upływającym czasem.

Pozwalają one na uzyskanie wielu efektów, w których cząsteczki nie zawsze zdają egzamin. Jak np. dym rozchodzący się za szybką rakietą albo wyładowania elektryczne.

Zaprogramowanie takiego efektu nie jest trudne. Wstążka to nic innego jak prostokąty kolejno połączone ze sobą bokami w punktach, które są równomiernie rozłożonych na linii jej ruchu.

Ruch wstążki

Ruch wstążki

Zielone punkty reprezentują miejsca, w których nasze prostokąty będą stykały się bokami. Rozmieszczenie powinno być względnie równomiernie, pozwoli to nam uniknąć rzucających się w oczy rozciągnięć tekstury. Ważne jest też aby gęstości punktów była odpowiednia. Jeśli będzie za mała to nasza wstążka będzie kanciasta. Jeśli za duża to wygeneruje nam się dużo geometrii…

Wstążka powinna mieć tzw. punkt źródłowy, który pozwoli nam na określenie kiedy postawić następny punkt na linii ruchu wstążki. Co klatkę sprawdzamy jego odległość od ostatniego utworzonego punktu. Jeśli ta odległość przekroczy naszą jakąś stałą (ta która wpływa na gęstość rozmieszczenia) tworzymy nowy punkt.

Budowanie wstążki

Kolejne etapy budowanie wstążki

Ok. Powiedzmy, że nasze punkty już się tworzą. Ale jak je teraz wyrenderować aby powstała wstążka? W pierwszym etapie bierzemy dwa kolejno po sobie występujące punkty i sprawdzamy pod jakim kątem są do siebie zwrócone (a.). Następnie kąt ten używamy do stworzenia dwóch punktów oddalonych o jakąś wartość (widzmy to na rysunku b.).

Mające te punkty możemy już bez problemu stworzyć geometrie naszej wstążki (c.). :D


Sep 22

Wirtualny system plików (ang. Virtual File System) Rzecz, która występuje prawie przy każdej grze. A przy silniku jest to wręcz element obowiązkowy. VFS jest to najprościej mówiąc system przechowywania danych zoptymalizowany pod względem ich odczytu.

Dlaczego używać wirtualnego skoro mamy do dyspozycji zwykły FS? Powodów jest kilka

  • Dane są zabezpieczone przed przypadkowym zmodyfikowaniem, co zapewnia stabilność
  • Można użyć różnych algorytmów kompresujących
  • Instalacja dużej liczby małych plików na zwykłym FS trwa dłużej niż w przypadku jednego wielkiego

Chciałbym w tej notce przedstawić sposób w jaki napisałem swój własny VFS do mojego silnika Omikron2.

Struktura VFS

Struktura VFS

Widzimy tutaj nagłówek zawierający podstawowe dane np. wersja archiwum, liczbę plików czy offsety. Tablica plików to rekordy o stałym rozmiarze zawierające hash nazwy, rozmiar, offset pliku w sektorze danych itp. Dane właściwe to pliki (skompresowane albo nie) upakowane w jeden ciąg danych, w tej samej kolejności co rekordy w tablicy plików.

No i tajemnicza końcówka o nazwie Tablica nazw. Co to takiego? No więc projektując VFS postanowiłem nazwy (a raczej pełne ścieżki) plików upakować na samiutkim końcu. Powodem takiego posunięcia był fakt, że nazwy plików potrzebne są tylko w jednym momencie -Gdy chcemy to archiwum rozpakować do normalnego FS. W innych przypadkach jak dostęp do poszczególnych plików wystarczy nam hash jego nazwy a do tego właściwa nazwa nie jest nam potrzebna.

To działanie znacząco uprosiło strukturę VFS i przyspieszyło jego wczytywanie. Bo wystarczy za jednym zamachem wczytać tablice plików z archiwum do pamięci aby mieć pełną informacje o danych się tam znajdujących.


Sep 21

Napisałem proste GUI do ogólnego przeznaczenia. Jeśli ktoś chce potestować może ściągnąć demko.

Okienka


Sep 18

W czasie gdy programista ma już dosyć tych gierek i silników, zasiada do… tworzenia zwykłych programów okienkowych (zwanych również użytkami). Odpala więc edytor, układa kontrolki, przypisujemy im odpowiednie zdarzenia i po paru chwilach widzi gotowy program…

A jak to wygląda w grach? No więc:

  • Układamy forme w jakimś własnym języku służącym do ich opisywania (np. jakaś odmiana XML).
  • Używamy takiego GUI który ma w zestawie edytor.
  • Wpisujemy wszystko ręcznie :)

Mi żadna z tych metod nie odpowiadała… Hmm gdyby użyć jakiegoś profesjonalnego edytora do okienek, pomyslałem. Np. to które znajduje się w środowisku Visual Studio. Zmusić je do kreowania własnego kodu (czy to XML czy zwykły C++) można by mieć naprawdę wielkie narzędzie na własność. W Windows Forms okazało się to szalenie łatwe. Wystarczy bowiem w runtime wykonać coś na kształt.

foreach (Control control in someform.Controls) {
 Type type = control.GetType();
 if (type == typeof(Button)) WriteButton((Button)control, sw);
 if (type == typeof(TextBox)) WriteTextBox((TextBox)control, sw);
 if (type == typeof(Label)) WriteLabel((Label)control, sw);
}

Czyli przechodzimy przez wszystkie kontrolki na okienku i wpisujemy ich pola w odpowiednim formacie do strumienia tekstowego. I tak np. wynikiem dla WriteButton będzie:

button1 = new CButton();
button1->SetLocation( vect2f(250, 19) );
button1->SetSize( vect2f(75, 23) );
button1->SetLabel( L"OK" );
button1->SetFont( verdana_f );
AddControl(button1);

W ten sposób można generować całe pliki źródłowe z oknami… :)

A

Tworzymy okno np. w WindowsDesigner z pakietu Visual Studio

B

Przy pomocy skryptu tworzymy kod w C++ który używa naszego API

C

Cieszymy sie nowoutworzonym oknem w naszej grze :)

.


Sep 9

Napisałem nowy FontManager oparty o bardzo dobrą bibliotekę FreeType2 (poprzednio do renderowania czcionek na teksturze używałem WinAPI). Co prawda nie obyło się bez kłopotów np. rozwikłanie metryk pojedynczego glifu… Ale po uporaniu się z różnymi przeciwnościami w końcu się udało, a efekt? Ocenicie sami :)

FontManager z wsparciem dla standardu Unicode oparty o Biblioteke FreeType2

FontManager z wsparciem dla standardu Unicode oparty o Biblioteke FreeType2


Aug 4

Po dosyć szczegółowych alpha-beta testach moge juz oficijalnie zaprezentowac moją małą acz pomocną aplikacje o nazwie ScreenUp.

ScreenUp jest programem służącym do tworzenia szybkich zrzutów ekranu i wysyłaniu ich, na dowolnie wybrany przez siebie serwer. Dzięki temu programowi można bardzo szybko pokazać innym zawartość swojego pulpitu.