Tej nocy: Pojedyncze sprite'y są dla leszczy, dorzućmy więcej! No i poruszajmy tym trochę używając pada.Wiele Sprite'ówOstatnio był tylko jeden sprite, więc używaliśmy zaledwie kilku par LDA/STA żeby załadować jego dane. Tym razem będą 4 sprite'y na ekranie. Wykonywanie tylu wczyań/zapisów zajmuje sporo czasu i miejsca, więc zamiast tego użyjemy pętli podobnej do tej, która ustawiała wcześniej palety. Najpierw ustawiamy bajty używając dyrektywy .db:
sprite'y:
;pion tile atr poziom
.db $80, $32, $00, $80 ;sprite 0
.db $80, $33, $00, $88 ;sprite 1
.db $88, $34, $00, $80 ;sprite 2
.db $88, $35, $00, $88 ;sprite 3
Mamy 4 bajty na sprite w jednym wierszu. Bajty są we właściwej kolejności i łatwo je zmieniać. Są to tylko dane początkowe, kiedy program jest uruchomiony kopia w pamięci RAM może być zmieniana, żeby poruszać sprite'm.
Dalej potrzebujesz pętli, żeby skopiować dane do RAM'u. Ta pętla działa tak samo jak ta od ładowania palet z rejestrem X jako licznikiem pętli.
LoadSprites:
LDX #$00 ; zaczynamy od 0
LoadSpritesLoop:
LDA sprites, x ; załaduj dane z adresu (sprites + x)
STA $0200, x ; zapisz pod adresem RAM ($0200 + x)
INX ; X = X + 1
CPX #$10 ; Porównaj X z hex'em $10, dziesiętnie 16
BNE LoadSpritesLoop ; Odgałąź do LoadSpritesLoop jeśli porównanie Nie było równe 0
; Jeśli porównanie było równe 16, kontynuuj kod dalej (nie wracaj do pętli)
Jeśli chcesz dodać więcej sprite'ów, możesz dostawić linijkę do sekcji srpite .db i zwiększyć wartość porównywania CPX. Odtworzy to pętlę więcej razy, przekopiuje więcej bajtów.
Kiedy sprite został załadowany do RAM'u możesz zmieniać tam jego dane.
Porty kontrolerówKontrolery są dostępne pod adresami pamięci $4016 i $4017. Najpierw musisz wpisać wartość $01 a potem $00 do portu $416. To rozkaże kontrolerowi, by załapał aktualne pozycje przycisków. Potem je wczytujesz spod $4016 dla I pada, $4017 dla II. Przyciski są wysyłane na raz w bicie 0. Jeśli bit zerowy ma wartość 0 - przycisk nie jest wciśnięty; jeśli bit zerowy ma stan 1 - przycisk jest wciśnięty.
Stan przycisków dla każdego z padów jest wczytywany w tej kolejności: A, B, Select, Start, Góra, Dół, Lewa, Prawa.
LDA #$01
STA $4016
LDA #$00
STA $4016 ; rozkaż obu kontrolerom by załapały stany przycisków
LDA $4016 ; player 1 - A
LDA $4016 ; player 1 - B
LDA $4016 ; player 1 - Select
LDA $4016 ; player 1 - Start
LDA $4016 ; player 1 - Góra
LDA $4016 ; player 1 - Dół
LDA $4016 ; player 1 - Lewo
LDA $4016 ; player 1 - Prawo
LDA $4017 ; player 2 - A
LDA $4017 ; player 2 - B
LDA $4017 ; player 2 - Select
LDA $4017 ; player 2 - Start
LDA $4017 ; player 2 - Góra
LDA $4017 ; player 2 - Dół
LDA $4017 ; player 2 - Lewo
LDA $4017 ; player 2 - Prawo
Instrukcja ANDInformacja o stanie przycisku jest wysyłana tylko w bicie zerowym, więc wygodnie by było wykasować pozostałe, zbędne bity. Każdy z ośmiu bitów jest ANDowany z bitem spod następnej wartości. Jeśli oba mają wartość 1, wynikiem instrukcji AND jest też jedynka. W każdym innym przypadku wynikiem jest 0.
0 AND 0 = 0
0 AND 1 = 0
1 AND 0 = 0
1 AND 1 = 1
Dla jakichś dwóch przypadkowych bajtów wygląda to tak:
0 1 0 1
1 0 1
1AND 1 0 1 0
1 1 0
1---------------------
0 0 0 0
1 0 0
1Interesuje nas wyłącznie bit zerowy, więc czyścimy wszystkie pozostałe:
01011011 dane z kontrolera
AND 00000001 ANDujemy z tym
----------------
00000001 wynik (tylko pierwszy z prawej, bit 0 o wartości 1 ) pozostałe usunięta
Więc, aby usunąć zbędne bity podczas wczytywania kontrolerów trzeba dodać funkcję AND po każdym wczytaniu spod $4016 albo $4017:
LDA $4016 ; player 1 - A
AND #%00000001
LDA $4016 ; player 1 - B
AND #%00000001
LDA $4016 ; player 1 - Select
AND #%00000001
instrukcja BEQInstrukcja BNE (Branch if Not Equal) używana wcześniej w pętlach do Odgałęzienia, jeśli Nie Równe ustawionej wartości. Tutaj w BEQ (Branch if Equal) wykonuje się odgałęzienie, jeśli wartość wynosi zero.
ReadA:
LDA $4016 ; player 1 - A
AND #%00000001 ; wykasuj wszystko prócz bitu 0
BEQ ReadADone ; odgałąź do ReadADone jeśli przycisk NIE jest wciśnięty (0)
; tu dodajemy instrukcje jakie mają się wykonywać, kiedy przycisk JEST wciśnięty (1)
ReadADone: ; Zakończona obsługa przycisku.
instrukcje CLC/ADCDo naszego dema użyjemy kontrolera I gracza, by poruszyć sprite'm Mario. Żeby to zrobić musimy umieć dodawać wartości. ADC to dodawanie z przenoszeniem. Przed dodawaniem warto się upewnić, że przeniesienie jest wyczyszczone używając CLC. W przykładzie załadujemy pozycję sprite'a do A, wyczyścimy przeniesienie, dodamy jeden do wartości i wpiszemy wartość z powrotem jako pozycjię sprite'a":
LDA $0203 ; wczytaj poziomą pozycję sprite'a (X)
CLC ; czyścimy flagę przeniesienia
ADC #$01 ; A = A + 1
STA $0203 ; zapisz poziomą pozycję sprite'a (X)
instrukcje SEC/SBCBy poruszyć sprite w przeciwnym kierunku potrzebne jest odejmowanie. SCB to odejmowanie z przeniesieniem. Tu dla odmiany ustawiamy flagę przeniesienia (SEC).
LDA $0203 ; wczytaj pozycję sprite'a
SEC ; ustawiamy flagę przeniesienia
SBC #$01 ; A = A - 1
STA $0203 ; zapisz pozycję sprite'a
Podsumowująchttp://www.nespowerpak.com/nesasm/controller.zipPobierz i rozpakuj controller.zip. Powyższy kod znajuje się w pliku controller.asm. Upewnij się, że pliki mario.chr oraz controller.bat są w tym samym folderze NESASM, potem dwuklik w controller.bat. Włączy to NESASM i powinno utworzyć plik controller.nes. Otwórz go przez FCEUXD SP żeby zobaczyć małego Mario. Wciśnij przyciski A i B, żeby poruszyć sprite'm. Ruch będzie wykonywany raz na ramkę, lub 60 pikseli na sekundę w trybie NTSC. Jeśli Mario się nie rusza, upewnij się, że kontrolery są normalnie ustawione w menu Config pod Input... Jeśli wciśniesz oba przyciski na raz nic się nie powinno ruszać..
Spróbuj zedytować wartości ADC i SBC, żeby hydraulik ruszał się żwawiej. Ekran ma tylko 256 pikseli szerokości, więc jeśli przesadzisz będzie skakał losowo! poza tym spróbuj edytować kod tak, żeby poruszać czterema sprite'ami na raz.
Na koniec spróbuj użyć d-pada zamiast przycisków. Lewo/prawo niech porusza sprite'ami pozioma, a góra/dół pionowo.
Literatura uzupełniająca:Oryginał [ENG]:
http://www.nintendoage.com/forum/messageview.cfm?catid=22&threadid=7974Podręcznik ASM 6502 dla Atari [PL]:
http://atarionline.pl/biblioteka/materialy_ksiazkowe/Asembler%206502%20(v2).pdf