64'er, Ausgabe 8/August 1989
Immer wieder faszinieren Spiele, die man zu zweit spielen kann. Oft wird dazu der Bildschirm in zwei Hälften geteilt, für jeden Spieler eine eigene. Lernen Sie, wie man solche Effekte selbst programmieren kann.
Es ist keine leichte Aufgabe, wenn man Grafik und Text gleichzeitig darstellen möchte. Sei es für mathematische Grafiken, die mit Text unterlegt sein sollen, oder für Adventures, deren Grafik im oberen und deren Text im unteren Teil des Schirms steht. Auch Spiele wie etwa »KickStart« (Bild 1) benutzen Bildschirm-Splitting, um das gleichzeitige Spielen zweier Spieler zu ermöglichen.
Bild 1. »KickStart« benutzt Bildschirm-Splitting, um das gleichzeitig Spielen zweier Spieler zu ermöglichen |
Das Aufteilen des Bildschirms läßt sich mit Rasterzeilen-IRQs realisieren. Dies funktioniert nach dem gleichen Prinzip wie das Teilen des Rahmens, das wir in der letzten Kursfolge behandelt haben. Einziger Unterschied: Nicht die Rahmenfarbe wird umgestellt, sodern der Darstellungsmodus des VICs. Es wird also an den Grenzen zwischen Textbildschirm und Grafikbildschirm hin- und hergeschaltet.
Um eine solche Routine zu schreiben und um überhaupt ein Spiel mit Grafik versehen zu können, müssen wir natürlich zunächst wissen, wie man einen Grafikbildschirm ein- und ausschaltet. Wie eine Bitmap (hochauflösende Grafik) organisiert ist, wurde bereits in zahlreichen Kursen beschrieben (z.B. 64'er Sonderheft 20 und 27), daher an dieser Stelle nur die wichtigsten Grundlagen zur Erinnerung:
Eine hochauflösende Bitmap (320 x 200 Pixel) benötigt außer ihrem normalen 8-KByte-Grafikspeicher zusätzlich ein 1 KByte langes Video-RAM, in dem die Vorder- und Hintergrundfarbe eines jeden 8 x 8 Pixel-Feldes steht. Das obere Nibble repräsentiert hierbei die Vordergrund- und das untere die Hintergrundfarbe. Eine Multicolor-Bitmap (160 x 200 Pixel) benötigt zusätzlich noch das Farb-RAM bei 55296 ($D800). Der 8-KByte-Grafikspeicher und das 1-KByte-Video-RAM lassen sich verschieben. Das Farb-RAM hingegen liegt fest bei $D800.
WICHTIG: Gemäß dem »Commdore 64 Programmer's Reference Guide« irrt Harald sich hier: Eine hochauflösende Bitmap benötigt einen 8-KByte-Grafikspeicher und das Farb-RAM (für die Vordergrundfarbe), eine Multicolor-Bitmap benötigt zusätzlich 1000 Bytes für zwei zusätzliche Vordergrundfarben, und die Hintergrundfarbe ist definiert durch das VIC Hintergrundfarbregister 0, in Speicherzelle 53281 ($D021)--Redaktion Webdokument. |
Um eine hochauflösende Grafik einzuschalten, müssen Sie in Assembler folgende Anweisungen eingeben:
LDA VIC+17 ORA # 32 STA VIC+17
Und in Basic:
POKE VIC+17,PEEK(VIC+17) OR 32
Das Ausschalten funktioniert in Assembler mit:
LDA VIC+17 AND # 223 STA VIC+17
Und in Basic:
POKE VIC+17,PEEK(VIC+17) AND 223
WICHTIG: Harald schrieb in dem orginalen Artikel: »Das Ausschalten funktioniert in Assembler mit derselben Befehlsfolge«. Natürlich würde dies nicht funktionieren! Aber es gibt eine Befehlsfolge die es ermöglicht hin und her zu schalten:
LDA VIC+17 EOR # 32 STA VIC+17 Das EOR-Befehl invertiert Bit 5 --Redaktion Webdokument. |
Bevor man aber eine Bitmap einschaltet, müssen noch einige weitere Parameter eingegeben werden:
Zunächst muß man dem Computer mitteilen, wo die Bitmap zu finden ist. Dies ist etwas kompliziert, da der VIC immer nur auf einem 16-KByte-Bereich (Bank) des Speichers zugreifen kann. Hat man diese Bank definiert, so muß noch der 8-KByte-Bereich innerhalb der Bank angegeben werden, den die Bitmap in Anspruch nehmen soll.
Die Bank legen Sie in Basic mit folgender Befehlsfolge fest:
POKE 56578,PEEK(56578) OR 3 POKE 56576,(PEEK(56576) AND 252) OR (3-Banknummer)
In Assembler entsprechend.
Die Banknummer liegt zwischen 0 und 3. Bank 0 liegt im Speicherbereich $0000 bis $3FFF und ist nach dem Einschalten aktiv, Bank 3 reicht von $C000 bis $FFFF.
Soll die Grafik im unteren Teil der Bank liegen, so geben Sie in Basic folgenden Befehl ein:
POKE VIC+24,PEEK(VIC+24) AND 247
Soll sie im oberen Teil liegen, so »sagen« Sie es dem Computer mit dem Befehl:
POKE VIC+24,PEEK(VIC+24) OR 8
In Assembler jeweils entsprechend.
Im allgemeinen wird das Video-RAM ebenfalls verschoben, um den Inhalt des normalen Textbildschirms nicht zu zerstören. Dies geschieht mit folgendem Befehl:
POKE VIC+24,(PEEK(VIC+24) AND 15) OR (A * 16)
Der Wert A ist die Nummer des 1-KByte-Speicherbereiches innerhalb der Bank (also 0 < = A < = 15). Haben Sie beispielsweise Bank 0 eingeschaltet und für A den Wert 0 eingestellt, so liegt das Video-RAM bei $0000. Hat A den Wert 1, so liegt das Video-RAM bei $0400 (wie nach dem Einschalten) und so weiter.
Nun muß nur noch der Farbmodus gewählt werden. Für Hiresgrafiken (320 x 200 Pixel, zwei Farben pro 8 x 8-Feld) geben Sie folgenden Befehl ein:
POKE VIC+22,PEEK(VIC+22) AND 239
Den Multicolormodus (160 x 200 Pixel, vier Farben pro 8 x 8-Feld) aktiviert man mit dem Befehl:
POKE VIC+22,PEEK(VIC+22) OR 16
Eine Zusammenfassung dieser Vorgehensweise finden Sie im entsprechende Textkasten. Wundern Sie sich jedoch nicht, wenn nach Eingabe der obigen Befehle nur »Müll« auf dem Bildschirm erscheint - noch wurden ja weder das neue Video-RAM noch die Bitmap selbst »passend« belegt.
Sehen Sie sich Listing 1 an. Es entspricht im wesentlichen Listing 4 des letzten Kursteils. Hinzugekommen ist die Routine »MAKEBITMAP«. Sie löscht die Bitmap und malt ein Rechteck. Anstelle der Umschaltung zwischen den Rahmenfarben ist hier die Umschaltung zwischen Text- und Grafikbildschirm gesetzt.
Aufmerksame Leser werden vielleicht festgestellt haben, daß bei der INIT-Routine zwei überflüssig scheinende Befehle auftreten. Nähmlich:
LDA IRQFLAG STA IRQFLAG
Warum löscht man hier das IRQ-Requestregister, obwohl doch der Befehl SEI jeden IRQ verhindert?
IRQs sind leider keine kurzen Impulse, die beim Prozessor sozusagen einmal kurz »anklingeln«, um bei verschlossener Tür (I-Flag gesetzt) höflich wieder zu gehen. Nein, IRQs »bimmeln« solange, bis sich die Tür irgendwann öffnet (I-Flag gelöscht), und dann haben sie den Fuß in der Tür. Bei unserem Programm kann nun unter Umständen folgendes geschehen: Unmittelbar nach Initialisierung des Raster-IRQs (Beschreiben des Maskenregisters) wird ein IRQ ausgelöst, der aber noch nicht abgearbeitet werden kann, da ja der Befehl CLI noch nicht abgearbeitet wurde. Unmittelbar nach Verlassen der INIT-Routine hat nun dieser IRQ »den Fuß in der Tür« und wird ausgeführt. Wenn dies aber bei einer Rasterzeile größer 255 geschieht, wird in der IRQ-Routine Bit 8 gesetzt, und das Beschreiben des Registers VIC+18 mit den richtigen Werten 100 beziehungsweise 200 führt tatsächlich zu den Rasterzeilennummern 356 beziehungsweise 456. Da derartige Rasterzeile aber gar nicht existieren, läuft der VIC Amok, und es kommt zu einem gewaltigen Programmabsturz. Lassen Sie ruhig einmal beide Zeilen fort. Meistens geht es gut, aber eben nicht immer.
Das zweite Programm, Listing 2, nennt sich »Koala-Split«. Mit ihm können Sie Multicolor-Grafiken im »Koala-Painter«-Format in den Computer laden. Anschließend besteht die Möglichkeit, den Bildschirm in Grafik und Text aufzuteilen. Die Programmierung von Grafik-Adventures wird somit sehr vereinfacht.
WICHTIG: Sie können das Programm auch downloaden |
Tippen Sie Listing 2 mit Hilfe des MSE ein und speichern Sie es. Versetzen Sie den C64 in den Einschaltzustand und laden Sie Listing 2 mit
LOAD "KOALA-SPLIT",8,1
(für Datassette: ,1,1)
Tippen Sie anschließend NEW ein. Um eine Grafik zu laden, geben Sie den Befehl
SYS 49152"?PIC?[Name]",8,0
ein. Der Bildschirm läßt sich mit folgendem Befehl splitten:
SYS 49280,[obere Rasterzeile][untere Rasterzeile]
Abschalten läßt sich das Splitting mit SYS 49350.
Beachten Sie bitte, daß die Bitmap bei 8192 und das Video-RAM bei 2048 liegt. Arbeiten Sie in Basic, so müssen Sie den Start des Basic-Textes auf 16384 heraufsetzen. Dies geht mit:
POKE 43,1:POKE 44,64:POKE 16384,0:NEW
Ein Programm, daß den Start des Basic-Textes heraufsetzt, »KOALA-SPLIT« und das eigentliche Programm (z.B. ein Adventure) lädt und startet, sieht folgendermaßen aus:
10 SYS 57812"KOALA-SPLIT",8,1:POKE 780,0:SYS 65493 20 PRINT "[CLR] POKE43,1:POKE44,64:POKE16384,0:NEW" 30 PRINT "[2 DOWN] LOAD"+CHR$(34)+"[Programmname]"; 40 PRINT CHR$(34)+",8"; 50 POKE 631,19:POKE 632,13:POKE 633,131 60 END
(Harald Rosenfeldt/mf)
Listing 1. Dieses Programm, das wir im Hypra-Ass-Format abgedruckt haben, demonstriert Bildschirm-Splitting (download Quellcode in Hypra-Ass Format) |
||
HYPRA-ASS ASSEMBLERLISTING: 5 -.LI1,4,0 10 -.BA 49152 ;STARTADRESSE 20 -.GL IRQVEC = $0314 ;IRQVEKTOR 30 -.GL IRQALT = $EA31 ;ALTE IRQ-ROUTINE 40 -.GL VIC = $D000 ;BASISADRESSE DES VIC 50 -.GL IRQMASK= VIC+26 ;IRQ-MASKENREGISTER 60 -.GL IRQFLAG= VIC+25 ;IRQ-REQUESTREGISTER 70 -.GL RASTER = VIC+18 ;RASTERZEILENREGISTER 80 -.GL BORDER = VIC+32 ;RAHMENFARBE-REGISTER 90 -.GL OBEN = 10 ;OBERE RASTERZEILE 100 -.GL UNTEN = 201 ;UNTERE RASTERZEILE 110 -.GL HIBIT = VIC+17 ;BIT 8 DER RASTERZEILENNUMMER 120 -.GL CIATIME= $DC0E ;TIMER A STEUERREGISTER ; 140 -.GL CTRL1 = VIC+24 ;VIC-KONTROLLREGISTER 1 150 -.GL CTRL2 = VIC+17 ;VIC-KONTROLLREGISTER 2 160 -.GL PNT1 = 251 ;ZERO-PAGE-POINTER 1 170 -.GL PNT2 = 253 ;ZERO-PAGE-POINTER 2 C000 78 :200 -INIT SEI ;IRQ SPERREN C001 A90A :210 - LDA #OBEN ;IRQ FUER RASTERZEILE 10 C003 8D12D0 :220 - STA RASTER C006 AD11D0 :230 - LDA HIBIT ;BIT 8 LOESCHEN C009 297F :240 - AND #127 C00B 8D11D0 :250 - STA HIBIT C00E A981 :260 - LDA #129 ;IRQ MASKIEREN C010 8D1AD0 :270 - STA IRQMASK ;RASTER-IRQ C013 A936 :280 - LDA #<(IRQNEU);IRQ-VEKTOR AUF NEUE C015 A2C0 :290 - LDX #>(IRQNEU);IRQ-ROUTINE STELLEN C017 8D1403 :300 - STA IRQVEC C01A 8E1503 :310 - STX IRQVEC+1 C01D AD0EDC :320 - LDA CIATIME ;TIMER A STOPPEN C020 29FE :330 - AND #254 C022 8D0EDC :340 - STA CIATIME C025 AD19D0 :350 - LDA IRQFLAG ;IRQFLAGS VORSICHTSHALBER C028 8D19D0 :360 - STA IRQFLAG ;LOESCHEN C02B 58 :370 - CLI ;IRQ WIEDER ZULASSEN C02C 2078C0 :380 - JSR MAKEBITMAP;BITMAP GENERIEREN C02F 60 :390 - RTS ;UND ZURUECK... ; C030 AD19D0 :410 -IRQNEU LDA IRQFLAG ;VIC-IRQ-FLAG LESEN C033 8D19D0 :420 - STA IRQFLAG ;UND WIEDER SCHREIBEN ; C036 AD12D0 :440 -VICIRQ LDA RASTER ;RASTERZEILENREGISTER LESEN C039 C9C9 :450 - CMP #UNTEN ;GROESSER/GLEICH 201 ? C03B B01F :460 - BCS TEXT ;JA, DANN TEXTBILDSCHIRM ; C03D AD18D0 :480 -BITMAPON LDA CTRL1 ;SONST BITMAP C040 290F :490 - AND #15 ;EINSCHALTEN C042 0920 :500 - ORA #32 C044 0908 :510 - ORA #8 C046 8D18D0 :520 - STA CTRL1 C049 AD11D0 :530 - LDA CTRL2 C04C 0920 :540 - ORA #32 C04E 8D11D0 :550 - STA CTRL2 C051 A9C9 :560 - LDA #UNTEN ;NAECHSTER IRQ BEI ZEILE 201 C053 8D12D0 :570 - STA RASTER ; C056 68 :590 -IRQRETURN PLA ;REGISTER ZURUECKHOLEN C057 A8 :600 - TAY C058 68 :610 - PLA C059 AA :620 - TAX C05A 68 :630 - PLA C05B 40 :640 - RTI ;UND MIT RTI ZURUECK... ; C05C AD18D0 :660 -TEXT LDA CTRL1 ;TEXTBILDSCHIRM EINSCHALTEN C05F 290F :670 - AND #15 C061 0910 :680 - ORA #16 C063 29F7 :690 - AND #247 C065 8D18D0 :700 - STA CTRL1 C068 AD11D0 :710 - LDA CTRL2 C06B 29DF :720 - AND #223 C06D 8D11D0 :730 - STA CTRL2 C070 A90A :740 - LDA #10 ;NAECHSTER IRQ BEI ZEILE 10 C072 8D12D0 :750 - STA RASTER C075 4C31EA :760 - JMP IRQALT ;UND ZUR ALTEN IRQ-ROUTINE... ; C078 A900 :780 -MAKEBITMAP LDA #<(8192) ;LOESCHEN DER BITMAP C07A A220 :790 - LDX #>(8192) C07C 85FB :800 - STA PNT1 C07E 86FC :810 - STX PNT1+1 C080 A220 :820 - LDX #32 C082 A000 :830 - LDY #0 C084 98 :840 - TYA C085 91FB :850 -CLRLOOP STA (PNT1),Y C087 C8 :860 - INY C088 D0FB :870 - BNE CLRLOOP C08A E6FC :880 - INC PNT1+1 C08C CA :890 - DEX C08D D0F6 :900 - BNE CLRLOOP C08F A900 :910 - LDA #<(2048) ;UND MIT FARBE BELEGEN C091 A208 :920 - LDX #>(2048) C093 85FB :930 - STA PNT1 C095 86FC :940 - STX PNT1+1 C097 A204 :950 - LDX #4 C099 A90F :960 - LDA #15 C09B 91FB :970 -COLORLOOP STA (PNT1),Y C09D C8 :980 - INY C09E D0FB :990 - BNE COLORLOOP C0A0 E6FC :1000 - INC PNT1+1 C0A2 CA :1010 - DEX C0A3 D0F6 :1020 - BNE COLORLOOP ; C0A5 A910 :1040 - LDA #<(9232) ;LINIEN ZEICHNEN C0A7 A224 :1050 - LDX #>(9232) C0A9 20C2C0 :1060 - JSR LINE1 C0AC A990 :1070 - LDA #<(12432) C0AE A230 :1080 - LDX #>(12432) C0B0 20C2C0 :1090 - JSR LINE1 C0B3 A910 :1100 - LDA #<(9232) C0B5 A224 :1110 - LDX #>(9232) C0B7 20DAC0 :1120 - JSR LINE2 C0BA A9A8 :1130 - LDA #<(9384) C0BC A224 :1140 - LDX #>(9384) C0BE 20DAC0 :1150 - JSR LINE2 C0C1 60 :1160 - RTS C0C2 85FB :1170 -LINE1 STA PNT1 ;UNTERROUTINE FUER WAAGERECHTE C0C4 86FC :1180 - STX PNT1+1 ;LINIEN C0C6 A214 :1190 - LDX #20 C0C8 A000 :1200 - LDY #0 C0CA A9FF :1210 - LDA #255 C0CC 91FB :1220 -LINE1LOOP STA (PNT1),Y C0CE C8 :1230 - INY C0CF C8 :1240 - INY C0D0 C8 :1250 - INY C0D1 C8 :1260 - INY C0D2 C8 :1270 - INY C0D3 C8 :1280 - INY C0D4 C8 :1290 - INY C0D5 C8 :1300 - INY C0D7 CA :1310 - DEX C0D8 D0F3 :1320 - BNE LINE1LOOP C0D9 60 :1330 - RTS C0DA 85FB :1340 -LINE2 STA PNT1 ;UNTERROUTINE FUER SENKRECHTE C0DC 86FC :1350 - STX PNT1+1 ;LINIEN C0DE A24F :1360 - LDX #79 C0E0 A001 :1370 - LDY #1 C0E2 A9C3 :1380 -LINE2LOOP LDA #195 C0E4 91FB :1390 - STA (PNT1),Y C0E6 CA :1400 - DEX C0E7 F017 :1410 - BEQ LINE2END C0E9 C8 :1420 - INY C0EA C008 :1430 - CPY #8 C0EC D0F4 :1440 - BNE LINE2LOOP C0EE A000 :1450 - LDY #0 C0F0 18 :1460 - CLC C0F1 A5FB :1470 - LDA PNT1 C0F3 6940 :1480 - ADC #<(320) C0F5 85FB :1490 - STA PNT1 C0F7 A5FC :1500 - LDA PNT1+1 C0F9 6901 :1510 - ADC #>(320) C0FB 85FC :1520 - STA PNT1+1 C0FD 4CE2C0 :1530 - JMP LINE2LOOP C100 60 :1540 -LINE2END RTS 60000-.EN | ||
Listing 2. Mit Hilfe von »Koala-Split« kann man Bilder im »Koala-Painter«-Format laden und »splitten« (Sie können dieses File auch downloaden) |
||
Name : koala-split c000 c14f ---------------------------------- c000 : a9 00 85 0a 20 d4 e1 a9 cf c008 : 00 a2 20 8d 6e c0 8e 6f 19 c010 : c0 a9 01 a2 08 a0 00 20 ff c018 : ba ff 20 c0 ff a2 01 20 4b c020 : c6 ff 20 cf ff 20 cf ff 28 c028 : a9 40 a2 1f 20 60 c0 a9 d9 c030 : 00 a2 08 8d 6e c0 8e 6f 3b c038 : c0 a9 e8 a2 03 20 60 c0 8f c040 : a9 00 a2 d8 8d 6e c0 8e 19 c048 : 6f c0 a9 e8 a2 03 20 60 22 c050 : c0 20 cf ff 8d 4e c1 20 a7 c058 : cc ff a9 01 20 c3 ff 60 8f c060 : 8d 7c c0 8e 78 c0 a2 00 45 c068 : a0 00 20 cf ff 9d ff ff f7 c070 : e8 d0 04 ee 6f c0 c8 c0 41 c078 : ff d0 ef e0 ff d0 eb 60 ee c080 : 20 fd ae 20 9e b7 8e 4b c7 c088 : c1 20 fd ae 20 9e b7 8e a1 c090 : 4c c1 ad 21 d0 8d 4d c1 7e c098 : 78 ad 4b c1 8d 12 d0 ad fa c0a0 : 11 d0 29 7f 8d 11 d0 a9 4c c0a8 : 81 8d 1a d0 ad 0e dc 29 a2 c0b0 : fe 8d 0e dc a9 e3 a2 c0 5a c0b8 : 8d 14 03 8e 15 03 ad 19 34 c0c0 : d0 8d 19 d0 58 60 78 a9 75 c0c8 : 00 8d 1a d0 ad 0e dc 09 00 c0d0 : 01 8d 0e dc a9 31 a2 ea 3b c0d8 : 8d 14 03 8e 15 03 20 28 3c c0e0 : c1 58 60 ad 19 d0 8d 19 1c c0e8 : d0 ad 12 d0 cd 4c c1 b0 d5 c0f0 : 2b ad 4e c1 8d 21 d0 ad 3e c0f8 : 18 d0 29 0f 09 20 09 08 6a c100 : 8d 18 d0 ad 11 d0 09 20 7f c108 : 8d 11 d0 ad 16 d0 09 10 34 c110 : 8d 16 d0 ad 4c c1 8d 12 bf c118 : d0 4c bc fe 20 28 c1 ad c3 c120 : 4b c1 8d 12 d0 4c 31 ea fb c128 : ad 4d c1 8d 21 d0 ad 18 1d c130 : d0 29 0f 09 10 29 f7 8d bf c138 : 18 d0 ad 11 d0 29 df 8d 37 c140 : 11 d0 ad 16 d0 29 ef 8d 19 c148 : 16 d0 60 00 00 00 00 ff de | ||