Powrót do spisu treści

Rozdział 8

GRAFIKA GRACZY I POCISKÓW

    Jedną z najważniejszych czynności wykonywanych przez komputery domowe jest animacja. Stosowana jest ona nie tylko w grach komputerowych, lecz także w wielu programach edukacyjnych i użytkowych. Uzyskanie szybkiej i płynnej animacji jest jednak bardzo trudne ze względu na sposób przechowywania danych obrazu.

    We wszystkich komputerach pamięć obrazu jest zorganizowana liniowo. Oznacza to, że dane dla kolejnych linii obrazu są umieszczone w pamięci jedne po drugich. Utworzenie na ekranie niewielkiego obiektu polega na wpisaniu informacji o tym obiekcie w różne miejsca pamięci, oddalone od siebie (rys. 18). Przesunięcie obiektu wymaga usunięcia jego danych z pamięci obrazu, wpisania w to miejsce danych tła i umieszczenie obiektu w nowym miejscu. Ponieważ poszczególne fragmenty danych są od siebie oddalone, to jest to pracochłonne i stosunkowo powolne. Dodatkowym utrudnieniem jest to, że w trybach bitowych każdy bajt zawiera dane dla kilku punktów obrazu i trzeba zmieniać tylko określone bity tego bajtu. Taki sposób animacji wymaga więc od procesora dużej liczby obliczeń, a na dodatek nie zapewnia płynności ruchu.
                        pamięć obrazu
  ............|......XXX.......|......XXX.......|............
                      |                |
                      |                |
                      +-------+        |
                              |        |
       +----------------+     |        |
       |................|     |        |
       |................|     |        |
       |......XXX.......|<----+        |
       |......XXX.......|<-------------+
       |................|
       |................|
       +----------------+

      Rys.18. Rozmieszczenie danych obrazu w pamięci
    Stosowane są różne sposoby rozwiązywania tego problemu. Najczęściej stosuje się specjalny układ scalony, który umożliwia utworzenie tzw. ruchomych obiektów ekranowych. W komputerach Atari XL/XE układem tym jest GTIA, a technika uzyskiwania obiektów nazywa się grafiką graczy i pocisków (Player/Missile Graphics - P/MG). Umożliwia ona jednoczesne przedstawienie na ekranie czterech dużych obiektów zwanych graczami oraz czterech małych zwanych pociskami. Większa liczba obiektów jest dostępna poprzez zmiany parametrów P/MG przez procedury przerwania DLI.

    Zasada działania P/MG polega na umieszczeniu danych obiektu obok siebie w pamięci, dzięki czemu ich przemieszczanie staje się bardzo proste i, co ważniejsze, szybkie (rys. 19). Podczas tworzenia obrazu GTIA do danych aktualnej linii ekranu dodaje dane P/MG i w ten sposób obiekt pojawia się na ekranie. Oczywiście jest to znacznie bardziej skomplikowane i wymaga od komputera wykonania wielu operacji, lecz są one wykonywane przez układy komputera i nie angażują programisty.
                        pamięć obrazu
  ............|......ooo.......|......ooo.......|............
                      |                |
                      |                |
     pamięć P/MG      |                |
     ....XXX....      +-------+        |
          |                   |        |
          +---------+         |        |
                    |         |        |
                    v         |        |
       +----------------+     |        |
       |................|     |        |
       |................|     |        |
       |......ooo...X...|<----+        |
       |......ooo...X...|<-------------+
       |............X...|
       |................|
       +----------------+

      Rys.19. Umieszczenie danych P/MG na obrazie
    Podczas tworzenia obrazu ANTIC pobiera z pamięci, oprócz danych dla linii, także dane grafiki P/M i umieszcza je w rejestrze grafiki GRAFP lub GRAFM znajdującym się w GTIA. Gdy GTIA przenosi na ekran dane linii, to dodaje do nich dane z rejestrów grafiki. W ten sposób na ekranie uzyskujemy sumę danych obrazu i danych P/MG.

    Grafika graczy i pocisków nie jest wykorzystywana przez system operacyjny. Pomimo, iż działa ona sprzętowo, to jednak wszystkie czynności przygotowawcze oraz poruszanie obiektów muszą być zaprogramowane. Do tego celu konieczna jest znajomość działania układów ANTIC i GTIA, a przede wszystkim ich rejestrów służących do sterowania grafiką P/M.

8.1. Tworzenie P/MG

    Grafika graczy i pocisków, tak jak obraz, musi posiadać obszar pamięci, w którym będą przechowywane dane do umieszczenia na ekranie. Wybór tego obszaru nie jest dowolny, lecz zależy od sposobu odczytu danych przez ANTIC. Ponieważ dostęp ANTIC-a do pamięci jest kontrolowany poprzez rejestr DMACTL, to trzeba zacząć od niego.

    Wcześniej było już opisane znaczenie bitów 0-2 i 5-7 rejestru DMACTL (str. 166). Pozostałe trzy bity sterują dostępem do danych P/MG.

    Bit 3 kontroluje dostęp ANTIC-a do obszaru pamięci dla pocisków. Gdy jest ustawiony, to dane te są przepisywane z pamięci do rejestru GRAFM (GRAphics For Missile).

    Bit 4 kontroluje dostęp ANTIC-a do obszaru pamięci dla graczy. Gdy jest ustawiony, to dane te są przepisywane z pamięci do rejestrów GRAFP0-3 (GRAphics For Player 0-3).

    Bit 5 ustala rozdzielczość grafiki P/MG. Gdy jest skasowany, to dane P/MG są pobierane z pamięci podczas tworzenia co drugiej linii ekranu. Każdy pixel obiektu ma więc wysokość dwóch linii ekranu. Po ustawieniu bitu 5 dane są odczytywane przy tworzeniu każdej linii, więc pixel ma wysokość jednej linii ekranu. Nazywa się to odpowiednio rozdzielczością dwuliniową lub jednoliniową.

8.1.1. Pamięć P/MG

    Bazowy adres pamięci graczy i pocisków jest umieszczany w rejestrze PMBASE (Player/Missile BASE - $D407). Całkowity adres danych obiektu dla konkretnej linii ekranu jest tworzony z trzech elementów: zawartości PMBASE, numeru gracza lub pocisku i licznika linii ekranu. Ponieważ częstość pobierania danych z pamięci zależy od wybranej rozdzielczości, to różny jest sposób zestawienia adresu. Różnice te wyjaśniają rysunki 20 i 21.
             PMBASE     numer obiektu  licznik linii
       +-+-+-+-+-+-+-+-+   +-+-+-+   +-+-+-+-+-+-+-+-+
       |7|6|5|4|3|2|1|0|   |2|1|0|   |7|6|5|4|3|2|1|0|
       +-+-+-+-+-+-+-+-+   +-+-+-+   +-+-+-+-+-+-+-+-+
       |         |         |     |   |               |
       +----+----+         +--+--+   +-------+-------+
            |                 |              |
            |                 |              |
            |                 |              |
            |                 |              |
            +------+       +--+       +------+
                   |       |          |
                   v       v          v
              +----+----+--+--+-------+-------+
              |         |     |               |
              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              |F|D|E|C|B|A|9|8|7|6|5|4|3|2|1|0|
              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     adres danych obiektu

Rys.20. Adres obiektu przy rozdzielczości jednoliniowej


             PMBASE     numer obiektu  licznik linii
       +-+-+-+-+-+-+-+-+   +-+-+-+   +-+-+-+-+-+-+-+-+
       |7|6|5|4|3|2|1|0|   |2|1|0|   |7|6|5|4|3|2|1|0|
       +-+-+-+-+-+-+-+-+   +-+-+-+   +-+-+-+-+-+-+-+-+
       |           |       |     |   |             |
       +-----+-----+       +--+--+   +------+------+
             |                |             |
             |                |             |
             |                |             |
             |                |             |
             +------+        ++        +----+
                    |        |         |
                    v        v         v
              +-----+-----+--+--+------+------+
              |           |     |             |
              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
              |F|E|D|C|B|A|9|8|7|6|5|4|3|2|1|0|
              +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                     adres danych obiektu

Rys.21. Adres obiektu przy rozdzielczości dwuliniowej
    Numer obiektu jest wybierany przez ANTIC na drodze sprzętowej według następującego schematu:
    000 - kombinacja niewykorzystana
    001 - kombinacja niewykorzystana
    010 - kombinacja niewykorzystana
    011 - odczyt danych dla pocisków
    100 - odczyt danych dla gracza 0
    101 - odczyt danych dla gracza 1
    110 - odczyt danych dla gracza 2
    111 - odczyt danych dla gracza 3
    Wynika z tego, że dane poszczególnych obiektów muszą być umieszczone w pamięci następująco:
             rozdz. dwuliniowa         rozdz. jednoliniowa
pociski  PMBASE+$0180-PMBASE+$01FF  PMBASE+$0300-PMBASE+$03FF
gracz 0  PMBASE+$0200-PMBASE+$027F  PMBASE+$0400-PMBASE+$04FF
gracz 1  PMBASE+$0280-PMBASE+$02FF  PMBASE+$0500-PMBASE+$05FF
gracz 2  PMBASE+$0300-PMBASE+$037F  PMBASE+$0600-PMBASE+$06FF
gracz 3  PMBASE+$0380-PMBASE+$03FF  PMBASE+$0700-PMBASE+$07FF
    Pozostawia to wolny obszar pamięci o wielkości 384 lub 768 bajtów. Zwykle pamięć P/MG jest zabezpieczana przed ingerencją systemu operacyjnego (przez zmianę RAMTOP), więc ten obszar można przeznaczyć na umieszczenie procedur w języku maszynowym. Jeżeli zostanie ustawiona rozdzielczość jednoliniowa i nie będą wykorzystywane pociski, to pozostaje wolny obszar 1 KB, w którym można umieścić dodatkowy zestaw znaków.

    Widoczne jest także ograniczenie dla wartości PMBASE. Ponieważ nie wszystkie bity tego rejestru są wykorzystywane do tworzenia adresu obiektu, to PMBASE musi wskazywać początek bloku 1 KB przy rozdzielczości dwuliniowej i 2 KB przy jednoliniowej.

    Obiekty mogą też być tworzone na ekranie bez pośrednictwa ANTIC-a i bez korzystania z opisanego wyżej obszaru pamięci. Trzeba w tym celu wpisać bajt wzoru bezpośrednio do rejestru grafiki GRAFM lub GRAFP. Każdy rejestr GRAFP odpowiada bajtowi danych gracza, zaś w rejestrze GRAFM każdemu pociskowi odpowiadają dwa bity. Umieszczone w ten sposób dane będą wyświetlane na całym ekranie, otrzymamy więc pionowy pas. Zmienić zawartość rejestrów grafiki, tak aby uzyskać widoczny efekt na ekranie, można tylko podczas tworzenia obrazu, czyli przy pomocy procedury przerwania DLI.

    Niezależnie od sposobu zapisywania danych w rejestrach grafiki (bezpośrednio lub przez ANTIC) należy jeszcze zasygnalizować układowi GTIA, że dane z tych rejestrów mają być przeniesione na ekran. Do tego celu służą dwa najmłodsze bity rejestru PMCTL (Player/Missile ConTroL - $D01D). Bit 0 steruje pociskami, a bit 1 graczami. Ustawienie tych bitów powoduje dodawanie danych gracza lub pocisku do danych tworzonej linii.

8.1.2. Wielkość i kolor obiektów

    Kolejny wniosek dotyczy efektu uzyskiwanego na ekranie. ANTIC przenosi po jednym bajcie danych obiektu dla każdej tworzonej linii ekranu. Oznacza to, że można uzyskać obiekt o wysokości całego ekranu i szerokości jednego bajtu (gracz) lub dwóch bitów (pocisk). Szerokość wyrażona w bitach nic jeszcze nie mówi o rzeczywistej szerokości obiektu. Każdy bit reprezentuje jeden pixel obrazu. Pixel ten jest niezależny od aktualnego trybu obrazu.

    Wysokość pixela jest wyznaczana przez wybraną rozdzielczość i jest jednakowa dla wszystkich obiektów. Szerokość pixela jest ustalana przez zawartość rejestru SIZEM lub SIZEP. W rejestrach SIZEP0-3 (SIZE Player 0-3) szerokość określają dwa najmłodsze bity (pozostałe są niewykorzystane). W rejestrze SIZEM (SIZE Missiles) każda para bitów określa szerokość pixeli odpowiedniego pocisku: bity 0 i 1 - pocisk 0, bity 2 i 3 - pocisk 1, bity 4 i 5 - pocisk 2 oraz bity 6 i 7 - pocisk 3. Szerokość pixeli jest wyznaczana według schematu:
    para bitów 00 - pixel o szerokości 1 cyklu koloru
    para bitów 01 - pixel o szerokości 2 cykli koloru
    para bitów 10 - pixel o szerokości 1 cyklu koloru
    para bitów 11 - pixel o szerokości 4 cykli koloru
    Maksymalna szerokość gracza wynosi więc 6*4=32 cykle koloru. Jest to 1/5 normalnej szerokości obrazu. Przy użyciu czterech graczy i czterech pocisków można całkowicie pokryć obraz.

    Wygląd obiektu na ekranie jest określany przez jego dane. Każdy bajt danych określa jedną linię pixeli. Natomiast wygląd poszczególnych pixeli określają bity tego bajtu. Skasowany bit oznacza przezroczysty pixel, czyli pixel w takim kolorze jaki znajduje się w tym miejscu na ekranie. Bit ustawiony powoduje nadanie odpowiadającemu mu pixelowi koloru z rejestru COLPM0-3 (COLor of Player/Missile 0-3). Kolory te są identyczne parami, to znaczy gracz 0 i pocisk 0 mają kolor z rejestru COLPM0, gracz 1 i pocisk 1 z rejestru COLPM1 itd.

    Gdy obiekt znajduje się na tle obrazu, nie ma żadnych kłopotów. Problem pojawia się dopiero wtedy, gdy obraz zawiera jakąś treść. Chodzi o to, czy obiekt będzie zasłaniał zawartość obrazu, czy odwrotnie. Nazywamy to priorytetem - kolor o wyższym priorytecie będzie zasłaniał kolory o niższym priorytecie. Do określenia kolejności kolorów służy rejestr GTIACTL (GTIA ConTroL - $D01B). Jego bity 0-3 ustalają 2następujące priorytety kolorów:
        bit 0       bit 1       bit 2       bit 3
        COLPM0      COLPM0      COLPF0      COLPF0
        COLPM1      COLPM1      COLPF1      COLPF1
        COLPM2      COLPF0      COLPF2      COLPM0
        COLPM3      COLPF1      COLPF3      COLPM1
        COLPF0      COLPF2      COLPM0      COLPM2
        COLPF1      COLPF3      COLPM1      COLPM3
        COLPF2      COLPM2      COLPM2      COLPF2
        COLPF3      COLPM3      COLPM3      COLPF3
        COLBAK      COLBAK      COLBAK      COLBAK
    Ustawienie jednego z tych bitów ustala określone przez niego priorytety. Ustawienie więcej niż jednego bitu powoduje niejednoznaczne określenie priorytetów. W takim przypadku, gdy obszary o jednakowym priorytecie będą się pokrywały, to uzyskają one kolor czarny. Przy ustalaniu priorytetów trzeba pamiętać, że w niektórych trybach ANTIC-a (2, 3 i F) z rejestru COLPF1 jest pobierana tylko jasność pixela. W tych trybach wszystkie pixele obrazu mają priorytet taki jak COLPF2, niezależnie od aktualnego priorytetu COLPF1.

    Przy tworzeniu P/MG wykorzystywane są jeszcze dwa bity rejestru GTIACTL (4 i 5). Ustawienie bitu 4 powoduje nadanie wszystkim pociskom koloru określonego rejestrem COLPF3. Można w ten sposób uzyskać piątego gracza. Każda część takiego gracza jest jednak niezależna - może być poruszana oddzielnie i mieć różną szerokość.

    Bit 5 wywołuje po ustawieniu zmianę priorytetów par graczy 0-1 i 2-3. Każdy gracz z takiej pary ma kolor określony odpowiednim rejestrem. Gdy pixele graczy pokrywają się, to kolor wynikowy jest otrzymywany poprzez operację OR wykonaną na bitach kolorów (np. dla graczy 0 i 1 - COLMP0 ORA COLMP1). Także w tym przypadku pozostałe parametry graczy są ustalane odrębnie.

8.1.3. Umieszczenie obiektu na ekranie

    Teraz nadeszła już pora przeniesienia obiektu na ekran. Podczas tworzenia kolejnych linii ekranu GTIA odczytuje zawartość rejestrów grafiki GRAFP0-3 i GRAFM i dodaje ją do danych linii. W ten sposób pionowa pozycja obiektu na ekranie odpowiada dokładnie położeniu danych tego obiektu w 128- lub 256-bajtowym obszarze pamięci P/MG.

    Wybranie rozdzielczości dwuliniowej uniemożliwia jednak umieszczenie obiektu na ekranie z dokładnością jednej linii ekranu. Aby usunąć tą niedogodność w GTIA został przewidziany rejestr VDELAY (Vertical DELAY - $D01C). Jeżeli zawarty w nim bit jest skasowany, to odpowiadający mu obiekt jest umieszczany na ekranie tak, jak to zostało wcześniej opisane. Natomiast ustawienie bitu powoduje opóźnienie o jedną linię przesyłania danych z rejestrów grafiki na ekran. Dzięki temu cały obiekt jest przesunięty o jedną linię ekranu w dół. Bity rejestru VDELAY odpowiadają kolejno pociskom od 0-3 i graczom 0-3:
bit 0 - pocisk 0 bit 1 - pocisk 1 bit 2 - pocisk 2 bit 3 - pocisk 3 bit 4 - gracz 0 bit 5 - gracz 1 bit 6 - gracz 2 bit 7 - gracz 3     GTIA musi jeszcze wiedzieć, w którym miejscu linii ma umieścić dane obiektu. Do tego celu służy osiem rejestrów poziomej pozycji obiektów - HPOSP0-3 (Horizontal POSition of Player 0-3) i HPOSM0-3 (Horizontal POSition of Missile 0-3). Każdy z nich zawiera numer cyklu koloru, w którym rozpoczyna się przenoszenie na ekran danych odpowiedniego obiektu.

    Aby obiekt był widoczny na ekranie, jego pozycja nie może być dowolna, lecz musi mieścić się w pewnych granicach. Dla pionowej pozycji granice te zależą od przyjętej rozdzielczości. Przy rozdzielczości jednoliniowej w obrębie obrazu mieszczą się pozycje od 32 do 224. Dla rozdzielczości dwuliniowej są to pozycje od 16 do 112.

    Znacznie większe jest zróżnicowanie pozycji poziomych - zależą one bowiem od szerokości obiektów. Wartości te zawiera poniższa tabela.
obiekt całkowicie:       na obrazie     poza obrazem
granica od strony:      lewej  prawej   lewej  prawej
szerokość:
pojedyncza - gracz        48     200      40     208
           - pocisk       48     206      46     208
podwójna   - gracz        48     192      32     208
           - pocisk       48     204      44     208
poczwórna  - gracz        48     176      16     208
           - pocisk       48     200      40     208
    Na zakończenie tego opisu krótka procedura umieszczająca na ekranie gracza 0.
            0100 ;Player 0 routine
            0110 ;
            0120 COLPM0S = $02C0
            0130 DMACTLS = $022F
            0140 GTICTLS = $026F
            0150 HPOSP0 = $D000
            0160 PMBASE = $D407
            0170 PMCTL = $D01D
            0180 PMSTRT = $9000
            0190 SIZEP0 = $D008
            0200 ;
            0210     *=  $9000
            0220 ;
            0230     LDX #$00
            0240 LOOP LDA SHAPE,X
            0250     STA PMSTRT+$0400+VPOS,X
            0260     INX
            0270     CPX #$19
            0280     BNE LOOP
            0290     LDA # >PMSTRT
            0300     STA PMBASE
            0310     LDY #$02
            0320     STY PMCTL
            0330     DEY
            0340     STY GTICTLS
            0350     DEY
            0360     STY SIZEP0
            0370     LDA HPOS
            0380     STA HPOSP0
            0390     LDA #$0E
            0400     STA COLPM0S
            0410     LDA #$3A
            0420     STA DMACTLS
            0430     RTS
            0440 ;
            0450 VPOS .BYTE $78
            0460 HPOS .BYTE $7A
            0470 SHAPE .BYTE $00,$00,$0C,$18
            0480     .BYTE $38,$7C,$54,$7C
            0490     .BYTE $28,$38,$38,$3C
            0500     .BYTE $7E,$FB,$B9,$38
            0510     .BYTE $38,$3C,$1C,$1C
            0520     .BYTE $0E,$06,$03,$00,$00

8.2. Przemieszczanie obiektów

    Po tym, co zostało napisane w poprzednim rozdziale, łatwo już zrozumieć sposób przemieszczania obiektu po ekranie. Trzeba jednak wspomnieć o kilku ograniczeniach i dodatkowych możliwościach.

    Rejestry pozycji poziomej obiektów, jak prawie wszystkie rejestry GTIA, są jednokierunkowe - w tym przypadku można jedynie do nich zapisywać. Próba odczytu da nam w efekcie wartość zupełnie bez sensu. Jeśli zatem zachodzi potrzeba zmiany pozycji poziomej obiektu o pewną wartość, to trzeba aktualną zawartość rejestru HPOS... przechowywać w dodatkowym rejestrze RAM. Jest to uwidocznione w zamieszczonych przykładach.

    Istnienie rejestrów pozycji poziomej umożliwia uzyskanie praktycznie dowolnej liczby obiektów na ekranie. Jest tylko jedno ograniczenie - w jednej linii ekranu nigdy nie można umieścić więcej niż czterech graczy i cztery pociski. Zwielokrotnienie obiektu wykonuje się przez zapisanie w jego polu pamięci danych dla kilku obiektów. Wszystkie te obiekty będą przy tym położone jeden nad drugim i będą się poruszały razem. Do ich usamodzielnienia należy wykorzystać najczęściej wymienianą w tej książce procedurę - przerwanie DLI. Podczas procedury, która je obsługuje można wpisać do rejestru pozycji nową wartość i następny obiekt znajdzie się w zupełnie innym miejscu. Trzeba jednak pamiętać o jednym - rejestry HPOS... nie są odnawiane podczas przerwania VBLK. Należy więc użyć tej procedury dwukrotnie, a w przypadku większej liczby obiektów - tyle razy, ile obiektów znajduje się w jednym polu danych P/MG.

    Więcej kłopotu sprawia przemieszczanie w pionie. Tu konieczne jest przepisywanie danych wewnątrz obszaru pamięci dla danego obiektu. Ponieważ obszar taki nigdy nie przekracza jednej strony pamięci, to napisanie odpowiedniej procedury jest bardzo proste. Dla przesunięcia zawartości całego pola pamięci o jeden bajt w górę przy rozdzielczości jednoliniowej wystarczy taka procedura:
            0100 ;Move Up
            0110 ;
            0120     LDX #$01
            0130 LOOP LDA PLAYER,X
            0140     STA PLAYER-1,X
            0150     INX
            0160     BNE LOOP
    Podobna procedura przesuwa pole pamięci o jeden bajt w dół.
            0100 ;Move Down
            0110 ;
            0120     LDX #$FF
            0130 LOOP LDA PLAYER-1,X
            0140     STA PLAYER,X
            0150     DEX
            0160     BNE LOOP
    Dla rozdzielczości dwuliniowej należy tylko zamienić rozkazy BNE LOOP na BPL LOOP i w drugiej procedurze rozkaz LDX #$FF na LDX #$7F.

    Gdy przemieszczenie ma dotyczyć tylko części pola (np. przy wykorzystywaniu go dla kilku obiektów), to trzeba wprowadzić ograniczenia pętli LOOP. Zwiększa to długość procedury, lecz skraca czas jej wykonywania. Przykład takiej procedury jest pokazany dalej.

    Przy wykorzystywaniu rozdzielczości dwuliniowej przesunięcie obiektu o jeden bajt powoduje przemieszczenie obiektu o dwie linie ekranu. Czasami może to wywoływać wrażenie niezbyt płynnego ruchu. Można to ominąć poprzez naprzemienne kasowanie i ustawianie odpowiedniego bitu w rejestrze VDELAY oraz przesuwanie obiektu. Uzyskuje się wtedy jeszcze większą płynność ruchu.

    Teraz dalszy ciąg procedury pokazanej w poprzednim rozdziale (należy to po prostu dopisać do niej usuwając rozkaz RTS). Przesuwa ona utworzony obiekt w zależności od położenia joysticka (w celu praktycznego wykorzystania trzeba ją dołączyć do programu i nieco zmienić zakończenie, aby nie działała w pętli bez końca).
            0530 ;Player 0 Movement
            0540 ;
            0550 JOY0  = $0278
            0560 ;
            0570 MOVE LDA JOY0
            0580     EOR #$FF
            0590     AND #$0F
            0600     BEQ MOVE
            0610     CLC
            0620     ROR A
            0630     BCC E1
            0640     LDX #$01
            0650 LP1 LDA PMSTRT+$0400,X
            0660     STA PMSTRT+$03FF,X
            0670     INX
            0680     BNE LP1
            0690     BEQ MOVE
            0700 E1  ROR A
            0710     BCC E2
            0720     LDX #$FF
            0730 LP2 LDA PMSTRT+$03FF,X
            0740     STA PMSTRT+$0400,X
            0750     DEX
            0760     BNE LP2
            0770     BEQ MOVE
            0780 E2  ROR A
            0790     BCC E3
            0800     DEC HPOS
            0810     JMP HP
            0820 E3  INC HPOS
            0830 HP  LDA HPOS
            0840     STA HPOSP0
            0850     JMP MOVE

8.3. Zderzenia między obiektami

    Dodatkowym zyskiem z zastosowania grafiki graczy i pocisków jest możliwość sprzętowego wykrywania kolizji. Są to przypadki zetknięcia się poszczególnych obiektów między sobą oraz z elementami obrazu (zwanego tu polem gry), które mają kolor inny niż kolor tła. Ponieważ jest to działanie sprzętowe (wbudowane w strukturę układu GTIA), to użytkownik musi jedynie sprawdzić w odpowiednim rejestrze, czy takie zetknięcie wystąpiło i odpowiednio zareagować.

    Można w ten sposób wykrywać wszelkie spotkania obiektów, bez przeprowadzania żmudnych obliczeń sprawdzających, czy dwa pixele należące do różnych obiektów zajmują to samo miejsce na ekranie. W tym celu należy jedynie zbadać zawartość jednego z rejestrów kolizji.

    Tych rejestrów kolizji jest w układzie GTIA aż szesnaście. Można je podzielić na cztery grupy: rejestry kolizji pocisków z polem gry (KOLMPF), graczy z polem gry (KOLPPF), pocisków z graczami (KOLMP) i graczy z graczami (KOLPP). Niemożliwe jest w ten sposób jedynie wykrycie kolizji pocisku z innym pociskiem. We wszystkich wymienionych rejestrach do wykrywania kolizji służą bity 0-3, a bity 4-7 są niewykorzystane. Normalnie wszystkie bity są skasowane. Ustawienie bitu oznacza zaistnienie kolizji obiektu, do którego należy ten rejestr, z odpowiednim obiektem lub kolorem pola gry.

    Znaczenie poszczególnych bitów w rejestrach wskazujących kolizje obiektów z polem gry (KOLM0-3PF - KOLlision Missile 0-3 to Play Field i KOLP0-3PF - KOLlision Player 0-3 to Play Field) jest następujące:
        bit 0 - kolizja z obszarem o kolorze z COLPF0
        bit 1 - kolizja z obszarem o kolorze z COLPF1
        bit 2 - kolizja z obszarem o kolorze z COLPF2
        bit 3 - kolizja z obszarem o kolorze z COLPF3
    Podobnie w rejestrach wskazujących kolizje obiektów z innymi obiektami (KOLM0-3P - KOLlision Missile 0-3 to Player i KOLP0-3P - KOLlision Player 0-3 to Player) poszczególne bity oznaczają:
           bit 0 - kolizja z graczem 0
           bit 1 - kolizja z graczem 1
           bit 2 - kolizja z graczem 2
           bit 3 - kolizja z graczem 3
    W przypadku rejestrów kolizji graczy z graczami (KOLPP) bit odpowiadający graczowi, do którego należy ten rejestr jest zawsze skasowany. Na przykład w rejestrze KOLP0P zawsze skasowany jest bit 0, a w KOLP1P bit 1.

    Wykrycie kolizji i ustawienie odpowiedniego bitu następuje zawsze dopiero po wyświetleniu linii na ekranie. Aby uniknąć pomyłek najlepiej wszystkie kolizje sprawdzać dopiero po utworzeniu całego obrazu, czyli podczas przerwania VBLK. Jeżeli procedura wywoływana przez zderzenie obiektów jest bardzo długa, to można zastosować przepisywanie zawartości rejestru kolizji do określonego miejsca w pamięci RAM. Jeżeli nie jest istotne natychmiastowe wykrycie kolizji, to sprawdzenie można wykonać w dowolnej chwili, gdyż rejestry kolizji nie są kasowane po przerwaniu zetknięcia.

    No tak! Rejestry kolizji można tylko odczytywać, a bity wskazujące kolizje nie są kasowane. Z tego wynika, że są to rejestry jednorazowego użytku. Po wykryciu kolizji trzeba wyłączyć komputer i uruchomić ponownie, aby wykryć następne spotkanie tych samych obiektów. To jakie to ułatwienie? Na szczęście nie jest tak źle. Wszystkie rejestry kolizji są kasowane przez wpisanie dowolnej wartości do rejestru HITCLR (HIT CLeaR - $D01E). Rejestr ten nie służy ponadto do niczego, więc jest obojętne, co zostanie w nim zapisane.

    Procedura wykrywania kolizji między obiektami powinna kolejno sprawdzać wszystkie konieczne rejestry kolizji i wywoływać odpowiednie części programu lub odczytane wartości przepisywać do innych komórek. Następnie musi zapisać dowolną wartość do HITCLR, aby umożliwić wskazanie następnych kolizji i już... może się powtarzać od początku. A oto przykład:
            0100 ;Player 0 Collisions Detection
            0110 ;
            0120 HITCLR = $D01E
            0130 KOLP0PF = $D004
            0140 KOLP0P = $D00D
            0150 ;
            0160     *=  $0600
            0170 ;
            0180     LDA #$00
            0190     LDX #$07
            0200 LOOP STA PF0,X
            0210     DEX
            0220     BPL LOOP
            0230     LDY #$FF
            0240     LDX #$00
            0250     LDA KOLP0PF
            0260     AND #$0F
            0270     CLC
            0280 LP1 ROR A
            0290     BCC NX1
            0300     STY PF0,X
            0310 NX1 INX
            0320     CPX #$04
            0330     BNE LP1
            0340     LDA KOLP0P
            0350     AND #$0F
            0360     CLC
            0370 LP2 ROR A
            0380     BCC NX2
            0390     STY PF0,X
            0400 NX2 INX
            0410     CPX #$08
            0420     BNE LP2
            0430     STY HITCLR
            0440     RTS
            0450 ;
            0460 PF0 .BYTE $00,$00,$00,$00
            0470 PL0 .BYTE $00,$00,$00,$00
Zientara Wojciech: Mapa pamięci Atari XL/XE. Procedury wejścia-wyjścia, SOETO, Warszawa, 1988.