Nowa gra Ms Lily's Haunted ShopDrukuj stronę
2021-01-18
O nie jednym, a dwóch powodach, dla których każdy, kto potrafi kodować, powinien dołączyć do konkursu charytatywnego C64 „Cassette 50”! W tym poście postaram się również wyjaśnić, dlaczego zamiast skupić się na innym projekcie (Meonlawel), postanowiłem na chwilę zboczyć z głównego kursu i dołączyłem do konkursu z grą Ms Lily's Haunted Shop.
Zanim przejdę do tego jak powstawała ta gra, zachęcam najpierw do zagrania jeżeli nie mieliście jeszcze okazji! Gra jest dostępna za darmo, i możecie w nią zagrać w przeglądarce na tej stronie.
Po pierwsze, moją główną motywacją uczestniczenia w tym konkursie było wsparcie Special Effect Charity. Dzięki za tę inicjatywę! Pod labelem Commocore, myślałem o pisaniu po części gier 'careware' ale nie stworzyłem jeszcze takiego planu z uwagi na fakt, że moje projekty wciąż są na wczesnych etapach.
Drugim aspektem motywacyjnym były wymagania odnośnie ograniczeń konkursu...
Ograniczenia
Porozmawiajmy o ograni... o wyzwaniach! Kod musi zmieścić się w pamięci poniżej lokacji $1000. Także, kod nie może zapisywać do komórek pamięci powyżej $1000 z wyjątkiem obszaru $D000 - $DFFF. To oznacza, że program może zajmować co najwyżej 4kb. Ale nie cały ten obszar jest dostępny... Część lokacji pamięci poniżej $0400 jest używana przez BASIC i KERNAL. Możliwe jest wyłączenie BASICa ale co z KERNALem? By wyłączyć KERNAL, trzeba zmienić wektory IRQ znajdujące się pod $FFFE/$FFFF ale tym sposobem złamane by zostały zasady. Zapisywanie do pamięci powyżej $DFFF nie jest dozwolone. W rezultacie, część lokacji pamięci w dolnym obszarze jest ciągle nadpisywana przez KERNAL. I to sprawia, że konkurs jest nieco trudniejszy. By użyć więcej miejsca, wymagana jest znajomość tych obszarów pamięci, które mogą być nadpisane przez KERNAL. Tylko w ten sposób możliwe jest zmieszczenie kawałków kodu w wolnych przestrzeniach. Na końcu tego wpisu zamieściłem mapę pamięci kodu gry Ms Lily's Haunted Shop.
Pokonywanie ograniczeń
To jest właśnie to dlaczego kodowanie w asemblerze, z ograniczeniem programu poniżej 4kb, dla komputera ~1MHz z 1982 - ma sens... Przynajmniej dla mnie. Jest to zabawa. Ile można z tego wycisnąć? To był mój pierwszy projekt napisany w asemblerze, gdzie zostawiłem KERNAL włączony. Normalnie, pierwszą linią kodu w moich projektach jest wyłączenie KERNALa i przejęcie pełnej kontroli nad maszyną. Muszę więc przyznać: nauczyłem się więcej niż sądziłem, że wiem o Commodore 64. Gdy to piszę, kończę kolejną grę do tego samego konkursu (nazywa się "Red Is Blue", tłum. "Czerwony jest niebieski"). Przygoda trwa!
Przez ograniczenia, część rzeczy nie zmieściła się w grze, i musiałem zastosować sztuczki by zachować bajty pamięci. Na końcu, nie pozostał mi ani jeden wolny bajt pamięci. Więc tak, był to ciągły proces optymalizacji i próby wrzucenia kolejnych rzeczy do gry dopóki mogłem iść do przodu. To jest mój trzeci konkurs z rzędu, zdobyłem więc już pewne doświadczenie w zakresie optymalizacji. To zabawne jak ograniczenia pamięci były coraz trudniejsze z każdym kolejnym konkursem do którego dołączyłem. Zaczęło się to z RGCD 2019 i luksusowymi 16kb pamięci. To wtedy powstał Swarm 16k. Po tym, wysłałem grę Bring back my bones 4k na konkurs Reset64 4k, gdzie zajęła piąte miejsce. Ale wciąż, było to pełne 4kb pamięci wolne do użycia.
Wróćmy więc do Ms Lily's Haunted Shop. Nie używałem żadnych nielegalnych rozkazów. Jestem zbyt dużym tchórzem by używać LAX, SBX i wszystko inne co dostępne jest na "czarnym rynku" procesora 6510. To było moje własne wyzwanie myślę, by używać jedynie "legalnych" rozkazów, które po prostu biorą więcej cennych bajtów. Pewnie w przyszłości spróbuję jednak coś napisać z wykorzystaniem tych rozkazów.
Porozmawiajmy o sztuczkach. Jednym z nich było użycie tylko połowy banku sprite'a, dzięki czemu zamiast dwóch sprite'ów przeszkadzajek występujących w grze, byłem w stanie zmieścić cztery! Proste, ale poprawia grywalność.
Co do muzyki, napisałem prosty player, który robi tylko to co powinien robić. Możliwość odgrywaniu patternów pomogła oszczędzić pamięć. Użyłem także ograniczoną ilość nut w tablicy referencyjnej. Wszystkie te małe rzeczy to jedyny ratunek by zwolnić cenne miejsce... w zasadzie uratowały one cały projekt!
Ale takich małych smaczków jest więcej... Niektóre tablice, na przykład tablica z wynikami potęgi drugiej czy tablice z lokacjami na ekranie są generowane podczas inicjalizacji programu. Eksperymentowałem z każdą tablicą by zobaczyć czy lepiej jest ją wygenerować w locie, czy może lepiej użyć w gotowej formie statycznej. Okazało się, że w większości przypadków, generowanie tablic za pomocą procedury zajmuje mniej miejsca niż zamieszczanie gotowych tablic w programie.
Co się nie zmieściło?
No cóż, wszystko co chciałem albo... może nie rozmawiajmy o tym :D. Powinienem pewnie spędzić więcej czasu nad muzyką i zrobić lepszy kawałek. Podczas testów, przyzwyczaiłem się do tych kilku na szybko stworzonych patternów na tyle, że postanowiłem je zostawić! Ta melodia to taki "robak w uchu". Myślę, że potrzebuję miesiąc przerwy, by stwierdzić czy jest to dobra melodia czy nie.
Nie udało mi się zmieścić nazwy gry, ekranu tytułowego i ekranu końcowego. Jako, że używam kompilera 64tass, nie udało mi się zastosować sztuczek Shallana opublikowanych na stronie konkursu. Program po prostu się "wysypywał". Dlatego też, kod gry nie zaczyna się od $0400 a od $0519.
Podziękowania
Mam nadzieję, że ten wpis był interesujący, i choć trochę przydatny. Tak czy siak, chciałem podzielić się moim entuzjazmem i podziękować organizatorom za tę inicjatywę. Sprawdźcie inne gry w tym konkursie! Jako, że celem było stworzenie gry w duchu niesławnej kompilacji Cascade 50 z 1983 roku, chciałem napisać coś co nie musi być wcale przyjemną rozrywką. Mogło to wyglądać raczej niespecjalnie, brzmieć prosto i prawdopodobnie być frustrujące. Ale podczas zabawy z kodem zacząłem bawić się samą grą. W rezultacie, włożyłem w ten projekt więcej serca niż planowałem. Zdecydowałem by stworzyć coś prostego i skończonego. Mam nadzieję, że udało mi się przynajmniej spełnić jeden z tych kryteriów, jak myślicie?Wielkie podziękowania dla wszystkich, którzy udzielili się na Twitterze z sugestiami na nazwę gry. Tutaj znajdziecie więcej szczegółów. Nie spodziewałem się tak zabawnych gier słownych! Boot Stomp, Wander Wanda lub Wanda Wander, Wandering Wanda's Wondrous Wander, Shooty McShoeFace, If the shoe fits, lub... All Your Boots Are Belong To Space Wizard. A propos czarodzieja... użyłem tego pomysłu do samej historii gry więc dzięki za pomysł! Jako, że moja żona oglądała ostatnio dokument o minimalistach (nie o tych, którzy używają jednej szczoteczki do wszystkiego, tylko takich "zwyklejszych" minimalistów), jak piorun z nieba wpadł mi pomysł do głowy, że czarodziejem tym jest Minimalis z krainy Abandonii, który chce zawładnąć Fulfilią. I to był ten ostatni brakujący element dlaczego w tej grze, owa dama lata po jakimś zwariowanych sklepie z różdżką w ręku. Dzięki!
Wasz Bartosz!
Ms Lily's Haunted Shop - mapa pamięci
Program inicjujący przed uruchomieniem gry właściwej: $0519 - $07f6
- $0002 - $0070 Zmienne
- $0071 - $008f Procedura resetująca grę (relokowana przy inicjalizacji programu)
- $0090 - $00ff <nieużywane> kontrolowana przez KERNAL
- $0100 - $011f Stos (ograniczony do $1f przy inicjalizacji programu)
- $0120 - $01ce Nuty piosenki
- $01cf - $01ff <nieużywane>
- $0200 - $021f Tablice ruchu przeszkadzajek i różnych typów ruchu
- $0220 - $0227 tablica power2 (generowana przy inicjalizacji programu)
- $0228 - $022f tablica power2 inverted (generowana przy inicjalizacji programu)
- $0230 - $026e Procedura resetowania zmiennych w pokoju (relekowana przy inicjalizacji)
- $026f - $02a6 <nieużywane> tu jest niebezpiecznie, lepiej nie używać (np. $0277)
- $02a7 - $02ec Animacja eksplozji (relokowana przy inicjalizacji z powodu braku pamięci powyżej $0801)
- $02ed - $030c Procedura czyszczenia ekranu, wyświetlenie tekstu "ROOM" (relokowana przy inicjalizacji)
- $030d - $0313 <nieużywane>
- $0314 - $0315 IRQ adres
- $031a - $03a5 Tablice kul
- $03a6 - $03b1 Pierwsza linia tekstu zakończonego levelu (relokowana przy inicjalizacji)
- $03b2 - $03bd Druga linia tekstu zakończonego levelu
- $03be - $03bf <nieużywane>
- $03c0 - $03ff Bank sprite'a (kopiowany ze źródła $0f40+ w locie dla każdego pokoju)
- $0519 - $07ee Kod inicjujący (wykonany tylko raz, nadpisany później przez rysowanie ekranu w tej lokacji)
- $07e8 - $07f4 Tablica pamięci ekranu (lo-byte) (generowana przy inicjalizacji)
- $0800 - $080c Tablica pamięci ekranu (hi-byte) (generowana przy inicjalizacji)
- $080d - $080e Tablica kolorów przeszkadzajek (generowana przy inicjalizacji)
- $0801 - $0f3c Program
- $0f40 - $0fff Sprite'y