libnds #1 Przedstawienie libnds i Spelunky

W tej serii na warsztat chcę wziąć istniejącą grę Spelunky i przepisać ją na konsolę Nintendo DS.
W pierwszym poście chcę jedynie pokazać możliwości a nie wprowadzić od podstaw do libnds – to być może przedstawię w innych postach (pisanie na dsa wydaje mi się dobrym wprowadzeniem do programowania na systemach embedded), tymczasem poniższe jest ciekawostką.

Przedstawienie Spelunky

Spelunky to darmowa gra napisana przez Dereka Yu w 2009 (która dorobiła się kontynuacji w 2012) z gatunku cave-exploration.

Spelunky is a cave exploration / treasure-hunting game inspired by classic platform games and roguelikes, where the goal is to grab as much treasure from the cave as possible. Every time you play the cave’s layout will be different. Use your wits, your reflexes, and the items available to you to survive and go ever deeper! Perhaps at the end you may find what you’re looking for…

Można ją pobrać ze strony autora, tutaj:

http://www.derekyu.com/games/spelunky_1_1.zip

Wydanie Spelunky przypadło na moje lekcje informatyki w gimnazjum (R.I.P), nie miało konkurencji przez to że waży tylko 9.5 MB, nie wymaga instalacji i działa bez problemu przez Wine.

Co istotne, Derek Yu udostępnił kod i inne zasoby gry na poniższej licencji;

http://www.spelunkyworld.com/files/COPYING.txt

…więc jest to świetny cel do przeniesienia na inną platformę (pomijając fakt że Spelunky zrobione są w Game Makerze i wydobycie czegoś z udostępnionych plików .gmk wymaga posiadania wymienionego).

Gameplay z komentarzem:

 

Wydobycie grafik

Znalezienie assetów oryginalnych Spelunków zacząłem nie od Game Makera ale od Githuba (z przeczucia że ktoś już próbował ruszyć temat).

To co znalazłem, to:

Właśnie to ostatnie było tym czego szukałem, skatagolowane pliki gry z odpowiednimi podpisami i kodem. Miałem już wszystko co potrzebne.

Przedstawienie libnds

Libnds wraz z przykładami dostarczany jest wraz z projektem devkitPro który zbiera wszystkie narzędzia potrzebne do pisania amatorskich programów na ds-a.

Do zautomatyzowanej instalacji devkitPro na linuksie udostępniony jest skrypt który wystarczy uruchomić interpreterem perla:

https://sourceforge.net/projects/devkitpro/files/Automated%20Installer/devkitARMupdate.pl/download

Po całej operacji brakuje tylko jednej rzeczy – emulatora NintendoDS – tutaj zdaje się że najlepszą opcją jest desmume.

Po przejściu do ~/devkitPro/examples/nds/Graphics i pierwszym uruchomieniu narzędzia make poproszeni zostaniemy o dodanie zmiennych DEVKITPRO i DEVKITARM do /etc/environment.

Po drugim uruchomieniu zbudowane zostaną pliki .nds, które będzie można włączyć emulatorem. Np. ~/devkitPro/examples/nds/Graphics/3D/3D_Both_Screens:

Screenshot from 2018-02-03 17-42-14.png

Zamierzam zrobić jakiś mały tutorial pisania na ds-a w następnych postach, więc daruję sobie przedstawianie szczegółów teraz. Gdyby ktoś szukał materiałów do nauki, to w kolejności od moim zdaniem najlepszych:

  • Patater + wspomniane przykłady od devkitPro

https://github.com/Patater/manual

https://patater.com/manual/

  • (niedokończony) tutorial z Githuba :

https://github.com/jdriselvato/NDS-Development/tree/master/examples/Graphics

  • (krótki) tutorial z czyjegoś bloga:

https://www.liranuna.com/nds-2d-tuts

  • W każdym z powyższych tutoriali przydaje się wyszukiwanie detali w docsach od libnds:

http://libnds.devkitpro.org/dma_8h.html#ac77a16a7cb9f2fa2b4361c22fe84245d

  • Czyjaś gotowa gra tekstowa:

https://github.com/richelbilderbeek/CityOfThieves

 

Użycie oryginalnej czcionki Spelunky do programu na ds-a

Najprostsze wprowadzenie jakie może być, bo polegające na wypisaniu tekstu w konsoli-konsoli. Jedyna różnica, to użycie czcionki innej niż systemowa.

 

Na bazie przykładu z ~/devkitPro/examples/nds/Graphics/printing/custom_font widać, że potrzebny będzie tilesheet z złączonymi wszystkimi znakami jakie potrzebujemy, aby móc pisać własną czcionką na ekranie ds-a.

W pobranym SpelunkyCommunityUpdateProject /spelunky/Sprites/sFont.images dostępne jest 59 znaków (od spacji do ‘Z’) w oddzielnych plikach ponumerowanych od 0 do 58, co odpowiada kodom znaków z tabeli ASCII przesuniętym o 32 (istotne później):

asciifull

Do złączenia tych znaków w jeden plik wykorzystałem narzędzie online Stitches:

http://draeton.github.io/stitches/

Aby Stitches nie zmieniło kolejności i wygenerowało jedną kolumnę ze znakami dokładnie w tej kolejności jak w tabeli ASCII, musiałem zmienić nazwy plików ze znakami tak jak poniżej (inaczej mocno się przetasowywało), czyli co 10 plików dodając kolejną literę alfabetu:

Screenshot from 2018-02-03 18-10-29

Po całej operacji Stitches wygenerowało taki plik:

spritesheet

Teraz ważna rzecz:

używane grafiki, muszą przejść przez (dołączony w devkitPro) program grit, wtedy w kodzie dołączone są jako plik nagłówkowy (z obrazek.bmp powstaje obrazek.h dołączony jako #include <obrazek.h>). Wytłumaczenie z tutoriala patater:

Working with the Makefile

The default template makefile will turn your graphic files into object files for linking into your program. Never include data as a header file.

The graphics must be in a lossless image format, such as gif, tif, bmp, or png in order to work with the provided template makefile. I prefer the png graphic format. Image conversion is usually done by a program called grit. The provided template makefile will ask grit to convert images in the gfx folder of your project root to a format ready for the Nintendo DS.

The provided template makefile, adapted from the default libnds template makefile, is a good base for most all projects. It will look in a folder called gfx (in the same directory as the makefile) for your graphics. If any are found, it uses a special bin2o rule to tell grit to turn your images into .o files, according to grit rule files (with the .grit files extension), which can be linked into your program. grit will create a header file (.h) for your data. The name format for them works like so: if a file is called orangeShuttle.png the header file will be called orangeShuttle.h. Inside this header file will be a reference to the data in the .o, named orangeShuttleTiles and orangeShuttlePal or orangeShuttleBitmap, depending on how the grit file specifies which format to convert your image into. It will also include the length in bytes of the data references as orangeShuttleTilesLen and orangeShuttlePalLen or orangeShuttleBitmapLen.

For our project, we’ll be putting the our graphic files and grit rule files into the gfx directory and having the makefile use grit on them.

Jeśli teraz nie rozumiecie, to po rzuceniu okiem na kod wszystko się wyjaśni.

Otrzymany obrazek .png koniecznie konwertujemy na .bmp z 4 lub 8 bitową głębią kolorów, dowolnym narzędziem, ja wykorzystałem to:

https://online-converting.com/image/convert2bmp/ 

…i wybrałem opcję ‘8 (indexed)’.

Trzeba dodać ważną rzecz – jak wrzucić font w formacie bmp, aby zawierał przeźroczyste obszary tzn. znak/cyfra na przeźroczystym tle (format bmp nie wspiera kanału alfa – przeźroczystości)?

Wybieramy kolor który nie pojawia się w czionce (piksele o tym kolorze będą interpretowane jako przeźroczystość), sprawdzamy jego wartość w hexach i wrzucamy do pliku grit z przykładu. Przykład z docsów grit:

NDS 16bpp bitmap, with cyan as transparent color
  -gb -gB16 -gT 00FFFF

Dopisuję odpowiednią flagę wraz z wartością (209c00) i edytuję spritesheet w gimpie, zmieniając tło znaków/liter/cyfr na zielony #209C00:

Screenshot from 2018-02-03 18-36-10

Zerknijmy teraz na kod który wypisze nasz tekst na ekran ds-a:

Screenshot from 2018-02-03 18-38-34

Tutaj jak wspomniałem wcześniej, przydaje się znajomość od którego znaku ASCII zaczynamy nasz spritesheet (linia z font.asciiOffset = 32).

W powyższym kodzie pojawia się kilka makr i funkcji biblioteki nds, nie ma co przedstawiać ich tutaj wybiórczo bo potrzebny jest do tego trochę pełniejszy obraz który można znaleźć w wymienionych wcześniej tutorialach.

Całość kompilujemy i włączamy emulatorem:

Screenshot from 2018-02-03 18-43-46

Koniec części 1.

 

Inne

Konfiguracja ndslib pozwalająca jednocześnie wypisywać konsolę + rysować sprite-y:

https://gamedev.stackexchange.com/questions/61065/using-ndslib-how-to-configure-video-modes-to-both-print-text-and-draw-bitmaps-o

 

Coś co mnie zastanawiało przeglądając przykłady ndslib:

https://stackoverflow.com/questions/30896489/why-is-u8-u16-u32-u64-used-instead-of-unsigned-int-in-kernel-programming

 

Operatory binarne w cpp takie jak ‘|’ czy ‘&’ są tu co chwile używane przy zmienianiu wartości rejestrów, warto się zapoznać:

https://www.tutorialspoint.com/cplusplus/cpp_operators.htm

 

Parę słownikowych terminów które się pojawi:

https://stackoverflow.com/questions/4917205/interrupt-masking-why

https://pl.wikipedia.org/wiki/Direct_Memory_Access

https://pl.wikipedia.org/wiki/Przerwanie

 

c++:

https://stackoverflow.com/questions/2575048/arrow-operator-usage-in-c

https://stackoverflow.com/questions/33333144/using-void-as-c-equivalent-of-java-object

https://stackoverflow.com/questions/4269034/what-is-the-meaning-of-prepended-double-colon

https://stackoverflow.com/questions/4269034/what-is-the-meaning-of-prepended-double-colon

Jak działają bitmapy:

http://paulbourke.net/dataformats/bitmaps/

https://pl.wikipedia.org/wiki/Głębia_koloru

 

 

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s