Serwis Edukacyjny
Nauczycieli
w I-LO w Tarnowie

Do strony głównej I LO w Tarnowie

Materiały dla uczniów liceum

Zoptymalizowane dla
  
1280 x 1024

  Wyjście       Spis treści       Poprzedni       Następny  

©2019 mgr Jerzy Wałaszek
I LO w Tarnowie

https://images.fineartamerica.com/images/artworkimages/mediumlarge/1/atari-logo-marjan-mencin.jpg

Autor artykułu: mgr Jerzy Wałaszek

 

Rozdział 4

Grafika graczy i pocisków

Spis treści Zawartość
Kłopoty z szybką animacją
Podstawy grafiki graczy i pocisków
Ruch w pionie
Ruch w poziomie
Inne właściwości grafiki PM
Pociski
Pola gry i ich priorytety
Sprzętowe wykrywanie kolizji
Zastosowania grafiki PM
Specjalne znaki
 

 

Kłopoty z szybką animacją

Animacja jest ważnym aspektem dowolnego systemu opartego na komputerze domowym. Działania na ekranie mogą znacząco zwiększyć atrakcyjność i realizm dowolnego programu. Z pewnością animacja jest podstawowym elementem wielu gier komputerowych. Co więcej animowany obraz może przenosić  informację, która jest bardziej zrozumiała dla użytkownika i ma na niego większy wpływ od obrazu statycznego. Może przyciągać uwagę do istotnego elementu lub zdarzenia. Może bezpośrednio pokazać proces dynamiczny zamiast pośrednio go opisywać. Z tego powodu animację należy uważać za ważny element możliwości graficznych dowolnego systemu komputerowego.

Konwencjonalnym sposobem realizacji animacji za pomocą komputerów domowych jest przesuwanie danych obrazu poprzez obszar pamięci RAM ekranu. Wymaga to dwuetapowego procesu. Najpierw program musi wymazać stary obraz przez zapis wartości tła do pamięci RAM zawierającej obecny obraz. Następnie program musi zapisać dane obrazu do pamięci RAM w nowym miejscu tego obrazu. Przez powtarzanie w kółko tego procesu obraz na ekranie będzie się poruszał.

Są problemy z tą techniką. Po pierwsze, jeśli animacja jest wykonywana w trybie graficznym o dużych pikselach, ruch nie będzie płynny; obraz będzie przesuwał się po ekranie skokami. W innych komputerach jedynym rozwiązaniem jest użycie trybu graficznego z mniejszymi pikselami (o wyższej rozdzielczości). Drugi problem jest dużo gorszy. Ekran jest dwuwymiarowym obrazem, lecz pamięć ekranowa RAM jest zorganizowana w sposób jednowymiarowy. Oznacza to, że obraz ciągły na ekranie nie jest ciągły  w pamięci RAM. Tę rozbieżność pokazuje rys. 4-1.

Obraz

  Bajty obrazu w RAM

00 00 00
00 99 00
00 BD 00
00 FF 00
00 BD 00
00 99 00
00 00 00

Rozmieszczenie bajtów obrazu w RAM

00 00 00 00 99 00 00 BD 00 00 FF 00 00 BD 00 00 99 00 00 00 00

Rys. 4-1 Nieciągłe obrazy w pamięci RAM

Znaczenie tej rozbieżności nie staje się oczywiste aż do momentu, gdy próbujesz napisać program przesuwający taki obraz. Popatrz, jak bajty tworzące obraz są rozsypane po pamięci RAM. Aby je wymazywać, program musi obliczać ich adresy. Te obliczenia nie zawsze są łatwe do wykonania. Kod w asemblerze do dostępu do pojedynczego bajtu na pozycji ekranu (XPOS, YPOS) wyglądałby następująco (ten kod zakłada 40 bajtów na linię ekranu):
LDA SCRNRM     Adres początku pamięci ekranu RAM
STA POINTR     do wskaźnika na stronie zerowej
LDA SCRNRM+1   górny bajt adresu
STA POINTR+1   do górnego bajtu wskaźnika
LDA #$00
STA TEMPA+1    rejestr tymczasowy
LDA YPOS       pozycja w pionie
ASL A          razy 2
ROL TEMPA+1    przesuń przeniesienie do TEMPA+1
ASL A          razy 4
ROL TEMPA+1    przesuń przeniesienie ponownie
ASL A          razy 8
ROL TEMPA+1    przesuń ponownie
LDX TEMPA+1    zapamiętaj YPOS*8
STX TEMPB+1    w TEMPB
STA TEMPB      teraz dolny bajt
ASL A          razy 16
ROL TEMPA+1
ASL A          razy 32
ROL TEMPA+1
CLC
ADC TEMPB      dodaj YPOS*8, aby otrzymać YPOS*40
STA TEMPB
LDA TEMPA+1    teraz zajmij się górnym bajtem
ADC TEMPB+1
STA TEMPB+1
LDA TEMPB      TEMPB zawiera przesunięcie od góry ekranu do piksela
CLC
ADC POINTR
STA POINTR
LDA TEMPB+1
ADC POINTR+1
STA POINTR+1
LDY XPOS
LDA (POINTR),Y

Z pewnością ten kod dostępu do pozycji ekranu jest zbyt toporny. Nie jest to oczywiście kod elegancki i najszybszy do rozwiązania problemu. Na pewno dobry programista skorzystałby ze specjalnych okoliczności, aby otrzymać kod bardziej zwarty. Chodzi o to, że dostęp do pikseli na ekranie wymaga dużo obliczeń. Powyższa procedura zajmuje około 100 cykli maszynowych przy dostępie do pojedynczego bajtu na ekranie. by przesunąć obraz zajmujący, powiedzmy 50 bajtów, potrzebne byłoby 100 dostępów lub około 10.000 cykli maszynowych, czyli w przybliżeniu 10 milisekund. Może to nie wydawać się dużo, lecz jeśli chcesz uzyskać płynny ruch, to musisz przesuwać swój obiekt co każde 17 milisekund. Jeśli są inne obiekty do poruszania lub jakieś obliczenia do przeprowadzenia, to nie zostaje na nie zbyt wiele czasu procesora. Oznacza to, iż ten rodzaj animacji (zwanej animacją na polu gry - ang. playfield animation) jest zbyt wolny dla wielu zastosowań. Wciąż możesz wykonywać animację w ten sposób, lecz wtedy będziesz ograniczony do niewielu obiektów, do małych obiektów, do wolnego ruchu lub do wykonywania niewielu obliczeń pomiędzy ruchami. Kompromisy, które musi przyjąć programista używający takiej animacji, są zbyt ograniczajace.

 

Podstawy grafiki graczy i pocisków

Rozwiązaniem tego problemu w komputerze domowym ATARI jest grafika graczy i pocisków (ang. player-missile graphics, PM graphics). W celu zrozumienia grafiki graczy i pocisków ważnym jest zrozumienie istoty problemu animacji na polu gry: obraz ekranowy jest dwuwymiarowy, natomiast obraz w pamięci RAM jest jednowymiarowy. Rozwiązanie polegało na stworzeniu obiektu graficznego, który jest jednowymiarowy zarówno na ekranie jak i w RAM. Obiekt ten (zwany graczem) pojawia się w RAM jako tablica o długości 128 lub 256 bajtów. Tablica ta jest bezpośrednio odwzorowana na ekranie. Pojawia się jako pionowy pas rozciągający się od góry ekranu do jego dołu. Każdy bajt w tablicy zostaje odwzorowany na ekranie w jedną lub dwie linie skanowania, a wybór ten jest dokonywany przez programistę. Obraz ekranowy jest prostą bit-mapą tych danych w tabeli. Jeśli bit jest ustawiony, to odpowiadający mu piksel w pionowej kolumnie jest zaświecony, jeśli bit jest wyzerowany, to odpowiadający mu piksel nie jest zaświecony. Dlatego obraz gracza nie jest dokładnie jednowymiarowy, w rzeczywistości ma szerokość ośmiu bitów.

Rysowanie obrazu gracza na ekranie jest dosyć proste. Najpierw rysujesz pożądany obrazek na kratkowanym papierze. Obrazek nie może być szerszy niż osiem pikseli. Następnie zamieniasz obrazek na kod binarny, zastępując piksele zaświecone jedynkami, a zgaszone zerami. Następnie zamieniasz wynikową liczbę binarną na liczbę dziesiętną lub szesnastkową, w zależności od tego, co jest dla ciebie bardziej wygodne. W pamięci RAM gracza umieszczasz zera, aby wyczyścić obraz. Wpisujesz dane obrazu do pamięci RAM gracza, bajt u góry obrazu gracza idzie najpierw, a później kolejno następne aż do spodu tego ciągu. Im dalej w pamięci RAM umieścisz dane, tym niżej na ekranie pojawi się obrazek.

 

Ruch w pionie

Animowanie tego obrazka jest bardzo proste. Ruch w pionie jest otrzymywany poprzez przesuwanie obrazu w pamięci RAM gracza.  zasadzie jest to ta sama metoda, której używa się w animacji na polu gry, lecz w praktyce występuje ogromna różnica; procedura ruchu pionowego porusza obrazkiem jednowymiarowo, a nie dwuwymiarowo. Program nie musi mnożyć przez 40 i często nie potrzebuje wykorzystywać pośredniości. Mógłby być tak prosty, jak ten poniżej:
     LDX $01
LOOP LDA PLAYER,X
     STA PLAYER-1,X
     INX
     BNE LOOP

Ta procedura zajmuje około 4 milisekund do przesunięcia całego gracza, około połowę tego, co procedura animacji na polu gry, która przesuwa tylko 50 bajtów, a ta przesuwa 256 bajtów. Jeśli potrzebna jest szybkość, to pętlę można skrócić do przesuwania tylko samych bajtów obrazu, a nie całego obszaru gracza, a wtedy pętla z łatwością wykona się w przeciągu około 100...200 mikrosekund. Chodzi tutaj o to, iż ruch w pionie graczy jest zarówno prostszy jak i szybszy od ruchu obiektów pola gry.

 

Ruch w poziomie

Ruch w poziomie jest nawet łatwiejszy od ruchu w pionie. Istnieje rejestr dla gracza zwany rejestrem pozycji poziomej (ang. horizontal position register). Wartość w tym rejestrze ustawia pozycję poziomą gracza na ekranie. Wszystko, co musisz zrobić, to umieścić liczbę w tym rejestrze, a gracz skoczy do tej pozycji w poziomie. Aby przesuwać gracza poziomo, po prostu zmień liczbę umieszczoną w rejestrze pozycji poziomej. Tylko tyle należy zrobić.

Ruchy w poziomie i w pionie są niezależne, możesz je łączyć w dowolny sposób.

Skalą pozycji w poziomie jest jeden cykl zegara koloru na jednostkę. W ten sposób dodanie jedynki do rejestru pozycji poziomej przesunie gracza o jeden cykl zegara koloru w prawo. W pojedynczej linii skanowania jest tylko 228 cykli koloru; co więcej niektóre z nich nie są wyświetlane, ponieważ znajdują się poza obrzeżem ekranu. Rejestr pozycji poziomej może przechowywać 256 pozycji, niektóre z nich są poza lewą lub prawą krawędzią ekranu. Pozycja 47 odpowiada lewej krawędzi standardowego pola gry; pozycja 208 odpowiada prawej krawędzi standardowego pola gry. Dlatego widoczny obszar dla gracza rozpościera się w poziomie od pozycji 47 do 208. Musisz jednak pamiętać, iż to zależy głównie od używanego odbiornika telewizyjnego z uwagi na różnice w wyświetlaniu obrazu. Standardowo przyjmuje wartości od 60 do 200. Ten zakres współrzędnych może czasem być toporny w użyciu, lecz oferuje on przydatną opcję: prostym sposobem usunięcia gracza z ekranu, jest ustawienie jego pozycji w poziomie na zero. Przy pomocy pojedynczego ładowania i zapisu w asemblerze (lub pojedynczej instrukcji POKE w języku BASIC) gracz zniknie.

 

Inne właściwości grafiki PM

System opisany do tego momentu umożliwia tworzenie szybkiej animacji. Istnieją liczne upiększenia, które w znaczny sposób przyczyniają się do jego ogólnej użyteczności. Pierwszym upiększeniem jest to, iż mamy do dyspozycji czterech indywidualnych graczy. Każdy z tych graczy posiada własny rejestr koloru oraz obszar w pamięci RAM, dlatego ich praca jest całkowicie niezależna. Nadano im nazwy od P0 do P3. Można ich użyć jeden obok drugiego otrzymując w ten sposób rozdzielczość w poziomie 32 pikseli, albo można ich użyć zupełnie niezależnie w celu otrzymania czterech ruchomych obiektów.

Każdy gracz posiada swój własny rejestr koloru, który jest całkowicie niezależny od rejestrów kolorów pola gry. Rejestry kolorów graczy nazywają się COLP(X) i posiadają swoje odpowiedniki w RAM pod nazwami PCOLR(X). To daje ci możliwość umieszczenia na ekranie większej liczby kolorów. Jednakże każdy gracz ma tylko jeden kolor, gracze o wielu kolorach nie są możliwi do uzyskania bez przerwań z listy wyświetlania (przerwania te opisane zostały w rozdziale 5).

Każdy gracz posiada kontrolowaną szerokość, którą możesz ustawić w rejestrach SIZEP(X) jako normalną, podwójną lub poczwórną. Jest to użyteczne przy tworzeniu graczy o różnych rozmiarach. Masz również opcję wyboru pionowej rozdzielczości graczy. Możesz używać rozdzielczości jednej linii, w której każdy bajt w tablicy gracza zajmuje jedną linię skanowania, lub rozdzielczości dwóch linii, w której każdy z tych bajtów zajmuje dwie poziome linie skanowania. Przy rozdzielczości jednej linii każda tablica bitmapowa gracza ma długość 256 bajtów, a przy rozdzielczości dwóch linii długość ta wynosi 128 bajtów. Jest to jedyny przypadek, gdzie własności graczy nie są niezależne, wybór rozdzielczości pionowej odnosi się do wszystkich graczy. Rozdzielczość pionowa jest sterowana bitem D4 rejestru DMACTL. W rozdzielczości pojedynczej pierwsze 32 bajty obszaru tablicy gracza leżą powyżej standardowego pola gry. Ostatnie 32 bajty leżą poniżej standardowego pola gry. W rozdzielczości podwójnej 16 pierwszych i 16 ostatnich bajtów leży poza polem gry.

 

Pociski

Następnym upiększeniem jest udostępnienie pocisków. Są to obiekty graficzne o szerokości 2 bitów związane z graczami. Jeden pocisk jest skojarzony z każdym graczem i ma ten sam kolor pobierany z rejestru koloru gracza. Kształt pocisku pochodzi z tablicy bitmapowej w RAM, która jest umieszczona przed tablicami graczy. Wszystkie cztery pociski są spakowane w tej samej tablicy (cztery pociski po 2 bity każdy daje w sumie 8 bitów). Pociski mogą poruszać się niezależnie od graczy; posiadają własne rejestry pozycji poziomej. Pociski posiadają swój własny rejestr rozmiaru, SIZEM, który może ustawiać szerokość w poziomie tak jak rejestry SIZEP(X) dla graczy. Jednakże pociski nie mogą mieć różnych rozmiarów, ustawiane są wszystkie razem. Pociski są użyteczne jako kule lub wąskie linie pionowe na ekranie. Jeśli jest pożądane, pociski można zgrupować razem w piątego gracza, w tym przypadku przyjmują kolor pola gry rejestru 3. Dokonuje się tego przez ustawienie bitu D4 w rejestrze sterującym priorytetami (PRIOR). Zauważ, iż pociski wciąż mogą poruszać się niezależnie, gdy opcja ta została wybrana; ich pozycje poziome są ustawiane w ich rejestrach pozycji poziomej. Bit uaktywniający piątego gracza wpływa jedynie na kolor pocisków.

W pionie poruszasz pociskiem w ten sam sposób jak dla graczy: przez przesuwanie obrazu pocisku w obszarze pamięci RAM pocisków. Może to być trudne do wykonania, ponieważ pociski są zgrupowane w tej samej tablicy w RAM. Aby uzyskać dostęp do pojedynczego pocisku, musisz wymaskować bity należące do innych pocisków.

 

Pola gry i ich priorytety

Ważną cechą grafiki graczy i pocisków jest ich całkowita niezależność od pola gry. Możesz łączyć je z dowolnym trybem graficznym, tekstowym lub bitmapowym. To stwarza problem: co dzieje się, gdy gracz kończy się nad jakimś obrazem pola gry? Który obraz ma priorytet? Masz opcję zdefiniowania priorytetów używanych przy wyświetlaniu graczy. Jeśli chcesz, to wszyscy gracze mogą mieć pierwszeństwo nad wszystkimi rejestrami koloru pola gry. Albo możesz ustawić pierwszeństwo wszystkich rejestrów koloru pola gry (z wyjątkiem koloru tła) nad kolorami wszystkich graczy. Albo możesz ustawić pierwszeństwo gracza o i gracza 1 (odtąd nazywanych P0 i P1) nad wszystkimi rejestrami koloru pola gry, a P2 i P3 z priorytetem niższym od priorytetu pola gry. Albo możesz ustawić priorytet rejestrów 0 i 1 koloru pola gry (PF0 i PF1) ponad wszystkimi graczami, którzy z kolei mają wyższy priorytet od PF2 i PF3. Priorytety te są ustawiane w rejestrze sterującym priorytetami (PRIOR), który posiada kopię w RAM o nazwie GPRIOR. Ta własność pozwala graczowi przesuwać się ponad jednym obrazkiem a pod spodem innego, co daje efekt trójwymiarowości.

 

Sprzętowe wykrywanie kolizji

Końcowym upiększeniem jest udostępnienie sprzętowego wykrywania kolizji. Jest to cenne głównie w grach. Możesz sprawdzać, czy dowolny obiekt graficzny (gracz lub pocisk) zderzył się z czymkolwiek innym. W szczególności możesz sprawdzać kolizje pocisk-gracz, kolizje pocisk-pole gry, kolizje gracz-gracz oraz kolizje gracz-pole gry. Istnieje w sumie 54 możliwe kolizje, i każda z nich posiada przydzielony bit, zatem można je sprawdzać. Jeśli bit zostanie ustawiony na 1, to dana kolizja miała miejsce. Bity te są odwzorowane w 15 rejestrach CTIA (tylko 4 dolne bity są używane, a z tych niektóre są bez znaczenia). Rejestry te można jedynie odczytywać, nie można ich wyzerować przez zapis w nich zera. Rejestry mogą zostać wyzerowane dla dalszego wykrywania kolizji przez zapis dowolnej wartości w rejestrze HITCLR. Operacja ta zeruje wszystkie rejestry kolizji.

Z punktu widzenia sprzętowego kolizja występuje, gdy obraz gracza łączy się z innym obrazem; stąd bit kolizji nie zostanie ustawiony aż do momentu, gdy część ekranu z kolizją nie zostanie narysowana. Oznacza to, iż wykrywanie kolizji może nie wystąpić aż upłynie do 16 milisekund po ruchu gracza. Preferowanym rozwiązaniem jest wykonanie ruchu graczem oraz wykrycie kolizji podczas wykonywania procedury obsługi przerwania z wygaszania w pionie (zobacz do rozdziału 5, który omawia przerwania w czasie wygaszania pionowego). W takim przypadku należy najpierw sprawdzić wykrywanie kolizji, następnie wyzerować kolizje, a potem wykonać ruch graczami. Innym rozwiązaniem jest odczekanie przynajmniej 16 milisekund po wykonaniu ruchu graczem przed sprawdzeniem kolizji dla tego gracza.

Istnieje pewna liczba niezbędnych kroków, aby używać grafikę graczy i pocisków. Najpierw musisz przygotować obszar pamięci RAM dla graczy i pocisków oraz poinformować komputer, gdzie ten obszar się znajduje. Jeśli używasz rozdzielczości jedno-liniowej, to obszar RAM będzie miał długość 1280 bajtów; jeśli używasz rozdzielczości dwu-liniowej, to będzie on miał rozmiar 640 bajtów. Dobrą praktyką jest używanie obszaru RAM tuż przed początkiem obszaru listy wyświetlania na szczycie RAM. Układ obszaru graczy-pocisków jest pokazany na rysunku 4-2.

PMBASE Rozdzielczość
dwuliniowa
Rozdzielczość
jednoliniowa
 
  Nieużywane Nieużywane  
+384 P3 P2 P1 P0  
+512 Gracz 0  
+640 Gracz 1  
+768 Gracz 2 P3 P2 P1 P0 +768
+896 Gracz 3  
+1024         Gracz 0 +1024
          Gracz 1 +1280
          Gracz 2 +1536
          Gracz 3 +1792
            +2048

Rys. 4-2 Rozkład pamięci RAM dla graczy i pocisków

Adres początku obszaru graczy i pocisków nosi nazwę PMBASE. Z powodu wewnętrznych ograniczeń procesora ANTIC, wskaźnik PMBASE musi wskazywać adres na granicy bloków 2KB dla rozdzielczości jednoliniowej lub na granicy bloków 1KB dla rozdzielczości dwuliniowej. Jeśli zdecydujesz się nie używać wszystkich graczy lub żadnego z pocisków, to obszary RAM nieużywanych obiektów mogą zostać wykorzystane do innych celów. Gdy zdecydujesz, gdzie będzie się znajdował obszar RAM dla twoich graczy i pocisków, informujesz o tym ANTIC'a przez zapisanie numeru strony PMBASE w rejestrze PMBASE procesora ANTIC. Zwróć uwagę, iż ograniczenia adresowe PMBASE uniemożliwiają pionowy ruch graczy przez modyfikację PMBASE.

W następnym kroku czyścisz obszar RAM graczy i pocisków przez umieszczenie w nim zer. Dalej narysuj graczy i pociski przez zapis danych ich obrazów w odpowiednich miejscach  obszaru RAM graczy i pocisków.

Następnie ustaw parametry graczy przez określenie początkowych wartości ich kolorów, pozycji poziomych i rejestrów szerokości. Jeśli będzie konieczne, ustaw priorytety graczy i pola gry. Poinformuj ANTIC o pożądanej rozdzielczości pionowej przez ustawienie bitu D4 w rejestrze DMACTL (kopia w pamięci pod adresem SDMCTL) dla rozdzielczości jednoliniowej lub wyzerowanie tego bitu dla rozdzielczości dwuliniowej. Na koniec uaktywnij graczy przez ustawienie bitu włączającego PM DMA w rejestrze DMACTL. Postaraj się nie zaburzyć pozostałych bitów w DMACTL. Przykładowy program ustawiający gracza i poruszający nim za pomocą dżojstika podany jest poniżej:

1  PMBASE=54279:REM                    Wskaźnik początku obszaru RAM graczy i pocisków
2  RAMTOP=106:REM                      Wskaźnik szczytu RAM systemu operacyjnego
3  SDMCTL=559:REM                      Kopia rejestru DMACTL w RAM
4  GRACTL=53277:REM                    Rejestr sterujący grafiką CTIA
5  HPOSP0=53248:REM                    Pozioma pozycja gracza P0
6  PCOLR0=704:REM                      Kopia rejestru koloru gracza 0 w RAM
10 GRAPHICS 0:SETCOLOR 2,0,0:REM       Ustaw kolor tła na czarny
20 X=0:REM                             Pozycja pozioma gracza w BASIC'u
30 Y=48:REM                            Pozycja pionowa gracza w BASIC's
40 A=PEEK(RAMTOP)-8:REM                Zarezerwuj 2KB RAM poniżej szczytu RAM
50 POKE PMBASE,A:REM                   Poinformuj ANTIC o położeniu obszaru PM
60 MYPMBASE=256*A:REM                  Zapamiętaj adres obszaru PM
70 POKE SDMCTL,46:REM                  Uaktywnij PM DMA z rozdzielczością dwuliniową
80 POKE GRACTL,3:REM                   Włącz wyświetlanie graczy i pocisków
90 POKE HPOSP0,100:REM                 Ustaw pozycję poziomą
100 FOR I=MYPMBASE+512 TO MYPMBASE+640:REM Ta pętla czyści gracza
110 POKE I,0
120 NEXT I
130 FOR I=MYPMBASE+512+Y TO MYPMBASE+518+Y
140 READ A:REM                         Ta pętla rysuje gracza
150 POKE I,A
160 NEXT I
170 DATA 8,17,35,255,32,16,8
180 POKE PCOLR0,88:REM                 Zrób gracza różowym
190 A=STICK(0):REM                     Czytaj dżojstik
200 IF A=15 THEN GOTO 190:REM          Jeśli nie jest aktywny, spróbuj jeszcze raz
210 IF A=11 THEN X=X-1:POKE HPOSP0,X
220 IF A=7 THEN X=X+1:POKE HPOSP0,X
230 IF A<>13 THEN GOTO 280
240 FOR I=8 TO 0 STEP -1
250 POKE MYPMBASE+512+Y+I,PEEK(MYPMBASE+511+Y+I)
260 NEXT I
270 Y=Y+1
280 IF A<>14 THEN GOTO 190
290 FOR I=0 TO 8
300 POKE MYPMBASE+511+Y+I,PEEK(MYPMBASE+512+Y+I)
310 NEXT I
320 Y=Y-1
330 GOTO 190

Gdy gracze są już wyświetlani na ekranie, usunięcie ich z niego może być trudne. Jest tak, ponieważ procedura ich wyświetlania obejmuje kilka kroków. Po pierwsze ANTIC pobiera dane graczy i pocisków z RAM (jeśli pobieranie to zostało uaktywnione w rejestrze DMACTL). Nastepnie ANTIC wysyła dane graczy i pocisków do CTIA (jeśli takie działanie zostało uaktywnione w GRACTL). CTIA wyświetla cokolwiek znajduje się w jego rejestrach grafiki graczy i pocisków (od GRAFP0 do GRAFP3 i GRAFM). Wielu programistów próbuje wyłączania grafiki graczy i pocisków przez wyzerowanie bitów sterujących w DMACTL i GRACTL. To jedynie zapobiega przesyłaniu nowych danych graczy i pocisków przez ANTIC do CTIA; stare dane w rejestrach GRAF(X) będą wciąż wyświetlane. Aby zupełnie wyczyścić graczy, rejestry GRAF(X) muszą zostać wyzerowane po wyzerowaniu bitów sterujacych  wDMACTL i GRACTL. Prostszym rozwiązaniem jest pozostawienie gracza włączonego, lecz ustawienie jego pozycji poziomej na zero. Oczywiście, jeśli to rozwiązanie zostanie zastosowane, to ANTIC będzie wciąż używał DMA (ang. Direct Memory Access – bezpośredni dostęp do pamięci) do pobierania danych graczy i pocisków, co prowadzi do marnowania około 70.000 cykli maszynowych na sekundę.

 

Zastosowania grafiki PM

Grafika graczy i pocisków udostępnia kilka specjalnych możliwości. Bez wątpienia są one bardzo cenne w animacjach. Posiadają jednak ograniczenia: jest tylko czterech graczy, a każdy z nich ma szerokość ośmiu bitów. Jeśli potrzebujesz większą rozdzielczość w poziomie, to zawsze możesz wrócić do animacji na polu gry. Lecz przy szybkich animacjach grafika graczy i pocisków spisuje się doskonale.

Możliwe jest pominięcie ANTIC'a i zapis danych graczy i pocisków bezpośrednio do ich rejestrów (GRAFP(X)) w CTIA. Daje to programiście więcej kontroli nad grafiką graczy i pocisków. Również zwiększa to jednocześnie obowiązki. Programista musi zarządzać danymi graficznymi graczy i pocisków i wpisywać je w odpowiedniej chwili do rejestrów graficznych. W rezultacie mikroprocesor 6503 staje się niewolnikiem cyklu rysowania ekranu. Jest to toporna technika, która oferuje niewiele korzyści za wiele wysiłku programistycznego. Programista omijający moc sprzętową procesora ANTIC musi zastąpić ją własnym wysiłkiem.

Gracze mogą zostać użyci do wytworzenia na ekranie namiastki ruchu trójwymiarowego.  Dokonuje się tego przy pomocy zmiany szerokości gracza. Każdy gracz jest rysowany za pomocą jednej z kilku map bitowych. Jedna mapa bitowa pokazuje gracza o szerokości 6 bitów, a inna pokazuje gracza o szerokości 8 bitów. Gdy gracz 6-bitowy jest rysowany przy normalnej rozdzielczości, to będzie on szeroki na 6 cykli koloru. Następny krok rozmiaru jest uzyskiwany przez przejście do podwójnej szerokości przy obrazie 6-bitowym; da to szerokość 12 cykli koloru. Obraz 8-bitowy będzie miał szerokość 16 cykli koloru. Podobnie, przejście  do poczwórnej szerokości utworzy obrazy szerokie na 24 i 32 cykle koloru. W ten sposób obraz może rosnąć na szerokość od 6 cykli koloru do 32 cykli koloru. Technika ta jest używana bardzo efektywnie w grze STAR RAIDERS. Zyloni są tam dwoma graczami o 16-bitach, zatem przejścia rozmiarów są nawet bardziej płynne.

Oprócz animacji grafika graczy i pocisków oferuje wiele możliwości. Gracze mogą być doskonałym sposobem zwiększenia ilości koloru na ekranie. Cztery dodatkowe rejestry koloru pozwalają na cztery dodatkowe kolory w każdej linii obrazu. Oczywiście, 8-bitowa rozdzielczość ogranicza zakres ich zastosowań. Istnieje sposób ominięcia tych ograniczeń, który czasami może zostać użyty. Weź gracza z czterokrotną szerokością i umieść go na ekranie. Następnie ustaw priorytety tak, aby gracz miał niższy priorytet od koloru pola gry. Następnie zamień ten kolor pola gry z kolorem tła, w ten sposób widoczny kolor tła ekranu jest w rzeczywistości kolorem pola gry. Gracz zniknie za tym nowym, fałszywym kolorem tła. Teraz wytnij dziurę w tym fałszywym tle przez narysowanie na nim prawdziwego koloru tła. Gracz pojawi się przed kolorem tła, lecz jedynie tam, gdzie narysowano prawdziwe tło. W ten sposób gracz może mieć więcej niż 8-bitów rozdzielczości w poziomie. Oto przykładowy program:

1 RAMTOP=106:REM                      wskaźnik szczytu RAM systemu operacyjnego
2 PMBASE=54279:REM                    Wskaźnik RAM graczy i pocisków dla ANTIC'a
3 SDMCTL=559:REM                      Kopia w RAM rejestru DMACTL
4 GRACTL=53277:REM                    Rejestr sterujący grafiką CTIA
5 HPOSP0=53248:REM                    Pozycja pozioma gracza P0
6 PCOLR0=704:REM                      Kopia RAM rejestru koloru gracza 0
7 SIZEP0=53256:REM                    Rejestr sterujący szerokością gracza
8 GPRIOR=623:REM                      Rejestr sterujący priorytetami
10 GRAPHICS 7
20 SETCOLOR 4,8,4
30 SETCOLOR 2,0,0
40 COLOR 3
50 FOR Y=0 TO 79:REM                   Ta pętla wypełnia ekran
60 PLOT 0,Y
70 DRAWTO 159,Y
80 NEXT Y
90 A=PEEK(RAMTOP)-20:REM               Musimy cofnąć się dla grafiki 7
100 POKE PMBASE,A
110 MYPMBASE=256*A
120 POKE SDMCTL,46
130 POKE GRACTL,3
140 POKE HPOSP0,100
150 FOR I=MYPMBASE+512 TO MYPMBASE+640
160 POKE I,255:REM                     Utwórz gracza o pełnym kolorze
170 NEXT I
180 POKE PCOLR0,88
190 POKE SIZEP0,3:REM                  Ustaw czterokrotną szerokość gracza
200 POKE GPRIOR,4:REM                  Ustaw priorytet
210 COLOR 4
220 FOR Y=30 TO 40
230 PLOT Y+22,Y
240 DRAWTO Y+43,Y
250 NEXT Y

Program tworzy następujący obraz:

Rys.4-3 Maskowanie gracza dla wyższej rozdzielczości.

 

Specjalne znaki

Innym zastosowaniem grafiki graczy i pocisków są znaki specjalne. Istnieje wiele specjalnych typów znaków, które wychodzą poza pionowe granice w normalnym zestawie znaków. Jednym ze sposobów rozwiązania tych problemów jest stworzenie specjalnych zestawów znaków. Innym sposobem jest użycie gracza. Indeksy, znaki całki oraz inne symbole specjalne można utworzyć w ten sposób. Przykładowy program wykonujący to zadanie wygląda tak:
1 RAMTOP=106:REM                      Wskaźnik szczytu pamięci RAM
2 PMBASE=54279:REM                    Wskaźnik pamięci RAM obszaru graczy i pocisków dla ANTIC'a
3 SDMCTL=559:REM                      Kopia DMACTL
4 GRACTL=53277:REM                    Rejestr sterowania grafiką CTIA
5 HPOSP0=53248:REM                    Rejestr pozycji poziomej gracza P0
6 PCOLR0=704:REM                      Kopia rejestru koloru gracza 0
10 GRAPHICS 0:A=PEEK(RAMTOP)-16:REM   Należy cofnąć się przy rozdzielczości 1-liniowej
20 POKE PMBASE,A
30 MYPMBASE=256*A
40 POKE SDMCTL,62
50 POKE GRACTL,3
60 POKE HPOSP0,102
70 FOR I=MYPMBASE+1024 TO MYPMBASE+1280
80 POKE I,0
90 NEXT I
100 POKE PCOLR0,140
110 FOR I=0 TO 15
120 READ X
130 POKE MYPMBASE+1100+I,X
140 NEXT I
150 DATA 14,29,24,24,24,24,24,24
160 DATA 24,24,24,24,24,24,184,112
170 ? CHR$(125):REM                   Wyczyść ekran
180 POSITION 15,6
190 ?"xdx"

Program tworzy następujący obrazek:

Rys.4-4 Użycie gracza jako znaku specjalnego.

Szczególnie użytecznym zastosowaniem graczy są kursory. Z ich możliwościami płynnego przesuwania się w dowolne miejsce na ekranie bez zaburzania jego zawartości gracze nadają się idealnie do takich zastosowań. Kursor może zmieniać kolor w trakcie ruchu po ekranie, aby wskazywać, co ma pod sobą.

Grafika graczy i pocisków udostępnia wiele możliwości. Jej zastosowanie do gier akcji jako animowanych obiektów jest oczywiste. Posiada ona również wiele poważnych zastosowań. Może dodawać koloru i zwiększać rozdzielczość na dowolnym ekranie. Może pokazywać znaki specjalne. Może być użyta do tworzenia kursorów. Stosuj ją.

 

Zespół Przedmiotowy
Chemii-Fizyki-Informatyki

w I Liceum Ogólnokształcącym
im. Kazimierza Brodzińskiego
w Tarnowie
ul. Piłsudskiego 4
©2019 mgr Jerzy Wałaszek

Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone
pod warunkiem podania źródła oraz niepobierania za to pieniędzy.

Pytania proszę przesyłać na adres email: i-lo@eduinf.waw.pl

Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.