von Harald Schönfeld Nachdem wir uns im letzten Teil mit dem Sortieren von Zahlen beschäftigt haben, folgt diesesmal eine typischere QUICK- "Anwendung". Wir werden uns ansehen, wie man in QUICK einfach, schnell und ruckelfrei einen Player bewegt. Ich werde jetzt allerdings nicht auf die Grundlagen der Player/Missile-Pro- grammierung eingehen (das kann man ja anderswo nachlesen), sondern ich möchte zeigen, welche Besonderheiten in QUICK zu beachten sind. ACHTUNG: Im Listing auftauchende runde Klammern, die mit einem Plus gekenn- zeichnet sind )+ und (+ , müssen als eckige Klammern ohne Plus eingegeben werden. PEEK und POKE ade Während die Playerbewegung in BASIC ein einziges Herumgepoke ist, bietet QUICK Fähigkeiten, die solche Probleme viel einfacher und übersichtlicher gestal- ten. Der GRAFIK-Header Auf der QUICKmagazin Disk III gab es die sogenannten QUICK-Header. Dabei handelt es sich um QUICK-Quelltexte, in denen nichts weiter getan wird, als OS-Variablen zu definieren. Da steht z.B.: BYTE (+ HPOSP0=53248 )+ Damit liegt die Variable HPOSP0 ("Horizontale Position von Player 0") auf der Adresse 53248. Will man also die Position dieses Players auf den Wert 128 (Mitte des Screens) setzen, so schreibt man einfach: HPOSP0=128 In BASIC müßte man dazu schreiben: POKE 53248,128 Was natürlich gar nichts aussagt. Man muß natürlich nicht diese Header be- nutzen, sondern kann sich die gebrau- chen Variablen selbst definieren. Der PLAYER-Befehl Sowas gibts in BASIC (auch TURBO-BASIC) leider (hä,hä) gar nicht. Der Playerbefehl kann eine bestimmte Anzahl von Bytes von einer bestimmten Anfangsposition an die Anfangs-Adresse eines Players kopieren, wobei die Y-Position einfach als zusätzlicher Pa- rameter angegeben werden muß. Liegen z.B. die Definitions-Daten an der Adresse $600, und der Playerbereich des Players beginnt bei $7400, so stellt der Befehl: PLAYER($7400,Y,L,$600) L Playerdaten an der Y-Position auf dem Bildschirm dar. Die X-Position wird wie immer über HPOSx bestimmt. PLAYER-Felder Es stellt sich nun nur noch die Frage, wo man die BYTE-Definition der Player im Speicher ablegen kann. Dazu defi- nieren wir uns einfach entsprechend große ARRAY: ARRAY (+ FORM(10),LEER(10) )+ Damit haben wir 2 Arrays von je 10 Bytes. L wäre damit also 10 und der Player könnte 10 Zeilen hoch sein. In FORM werden wir nun 10 Formbytes schreiben und in LEER schreiben wir 10 mal die 0, um den Player später einfach löschen zu können. Mit DATA(FREE) (+ 0,0,0,0,0,0,0,0,0,0 )+ DATA(FORM) (+ 1,2,3,4,5,1,2,3,4,5 )+ füllen wir die ARRAYs mit den gewünsch- ten Daten auf. Um diese Playerdaten mit dem PLAYER- Befehl an die richtige Stelle im Speicher kopieren zu können benötigen wir nun die Anfangsadresse unserer Arrays. Diese Adressen schreiben wir dann in die WORDs FREEADR und FORMADR. Die Adresse erhalten wir mit dem Befehl VADR(FREE). Er schreibt die Adresse von FREE in Speicherzellen 208,209. Legen wir die Variable VARADR mit dem Befehl WORD (+ VARADR=208 )+ an diese Stelle, so leistet die Folge VADR(FREE) FREEADR=VARADR das Gewünschte. Es ist günstig, sich die alte Y-Posi- tion zu merken, um so zuerst die vor- herigen Daten mit PLAYER($7000,AY,10,FREEADR) zu löschen. Mit PLAYER($7400,Y,10,FORMADR) kopieren wir dann die Playerdaten an die rich- tige Y-Adresse. Das Einschalten der Player Das übernimmt für uns die Routine .INIT, die den DMA-Modus und die An- fangsadresse der Player setzt. (Näheres siehe z.B. QUICKmagazin, ATARI-Profi- buch oder Mein ATARI Computer). Die Joystick-Abfrage Der Wert den Joystick 0 befindet sich netterweise in einer OS-Variable. Sie liegt bei 532. Der Befehl BYTE (+ STICK=532 )+ sorgt also dafür, daß wir aus dieser Variable jederzeit den aktuellen Joy- stickwert lesen können. Die Änderung der X und Y Koordinate geschieht nun schneller und besser als in BASIC. Man weiß ja (oder auch nicht), daß jeweils ein nicht gesetztes Bit angibt, daß sich der Joystick u.a. in diese Richtung bewegt hat. Fragt man alle 4 Bits ab (also die Werte 1,2,4,8) so kann man den Stick auch diagonal leict kontrollieren. Die Abfrage ge- schieht durch Ausmaskieren des ent- sprechenden Bits mit AND. Damit der Player sich nun schön gleich- mäßig bewegt, sorgen wir mit einem OS- Timer dafür, daß immer x/50tel Sekunden vergehen, bevor der Player wieder be- wegt wird. Quick-Sourcetext D1:PLAYER1.QIK ---------------- Length: $0DA7 Free : $69C4 ---------------- * PLAYER-DEMO in QUICK * (c) H.Schoenfeld '90 * Grafik-Variablen Header * (c) RAINDORF SOFT '90 * aus QUICKmagazin III BYTE (+ ATRACT=77 *Farbwechsel LMARGN=82 *Linker Rand RMARGN=83 *Rechter Rand ROWCRS=84 *Cursorzeile DINDEX=87 *Graphics Nr SDMCTL=559 *DMA Zugriff GPRIOR=623 *Farbkontrolle/Prioritaet PCOLR0=704 *Playerfarben PCOLR1=705 PCOLR2=706 PCOLR3=707 COLOR0=708 *Farbregister COLOR1=709 COLOR2=710 COLOR3=711 COLOR4=712 CRSINH=752 *Cursorsteuerung CHAT=755 *Zeichendarstellung CHBAS=756 *ZS-Anfangsadr.Highbyte HPOSP0=53248 *Hor. Playerpos. HPOSP1=53249 HPOSP2=53250 HPOSP3=53251 M0PF=53248 *Koll.reg. Missile/Playfi. M1PF=53249 M2PF=53250 M3PF=53251 HPOSM0=53252 *Hor. Missilepos. HPOSM1=53253 HPOSM2=53254 HPOSM3=53255 P0PF=53252 *Koll.reg. Player/Playfie. P1PF=53253 P2PF=53254 P3PF=53255 SIZEP0=53256 *Playerbreiten SIZEP1=53257 SIZEP2=53258 SIZEP3=53259 M0PL=53256 *Koll.reg. Missile/Player M1PL=53257 M2PL=53258 M3PL=53259 SIZEM=53260 *Missilebreiten P0PL=53260 *Koll.reg. Player/Player P1PL=53261 P2PL=53262 P3PL=53263 COLPM0=53266 *Farbregister Player + Mis COLPM1=53267 COLPM2=53268 COLPM3=53269 COLPF0=53270 *Farbregister Anzeigenfeld COLPF1=53271 COLPF2=53272 COLPF3=53273 COLPF4=53274 PRIOR=53272 *Prioritaet VDELAY=53276 *2-zeilige Aufloesung GRACTL=53277 *Grafikkontrolle HITCLR=53278 *Kollision loeschen PBCTL=54019 DMACTL=54272 *DMA-Kontrolle CHACTL=54273 *Zeichendarstellungkontr. HSCROL=54276 *Horiz. Scrolling VSCROL=54277 *Vert. Scrolling PMBASE=54279 *Anfang der PM's CHBASE=54281 *Anfang des Zeichensatzes WSYNC=54282 *Zeilensynch. )+ WORD (+ COLCRS=85 *Cursorspalte SAVMSC=88 *BS-Adresse SDLSTL=560 *Zeiger auf DPL DLIST=54274 *Zeiger auf DPL )+ BYTE (+ X,Y,AX,AY )+ WORD (+ SHAPEADR,FREEADR,VARADR=208 )+ ARRAY (+ FREE(10),SHAPE(10) )+ * Hauptprogramm * Setzt Playerformen fest * Initialisiert * Bewegt Player MAIN * "leerer Player" DATA(FREE) (+ 0,0,0,0,0,0,0,0,0,0 )+ VADR(FREE) FREEADR=VARADR * Playerform DATA(SHAPE) (+ 8,8,28,28,28,62,127,107,107,65 )+ VADR(SHAPE) SHAPEADR=VARADR X=48 Y=32 .INIT REPEAT .MOVE .WAIT(1) * Hier koennte ein anderer Programm- * teil stehen, der nicht laenger als * die Wartezeit (hier 1/50 Sek) sein * sollte UNTIL 1=0 ENDMAIN * Warteschleife, bis OS-TIMER * abgelaufen ist. Dann Timer neu * setzen PROC WAIT IN BYTE (+ TIME )+ LOCAL BYTE (+ TIM3=540 )+ BEGIN REPEAT UNTIL TIM3=0 TIM3=TIME ENDPROC * Playerbewegung koordinieren PROC MOVE BEGIN .STICK .PLAYER ENDPROC * Stick abfragen und * Playerkoordinaten entspr. aendern PROC STICK LOCAL BYTE (+ STICK=632,TST )+ BEGIN IF STICK<>15 AY=Y AX=X AND(STICK,1,TST) IF TST=0 Y- ELSE AND(STICK,2,TST) IF TST=0 Y+ ENDIF ENDIF AND(STICK,4,TST) IF TST=0 X- ELSE AND(STICK,8,TST) IF TST=0 X+ ENDIF ENDIF ENDIF ENDPROC * Player darstellen PROC PLAYER BEGIN * Player an alter Pos. loeschen PLAYER($74,AY,10,FREEADR) * Player an neue Pos. kopieren HPOSP0=X PLAYER($74,Y,10,SHAPEADR) ENDPROC * Grafik und Player initialisieren PROC INIT BEGIN CLOSE(6) OPEN(6,8,12,"S:") *Grafik 12 HPOSP0=0 *player ganz rechts PCOLR0=136 *Playerfarbe Blau CLR($70,8) *Playerbereich loeschen SDMCTL=62 *Player an PMBASE=$70 *Anfang der PM's GRACTL=2 *Grafikkontrolle Player ENDPROC So, das war die erste Version des Programms. Dabei ist übrigens nicht der gesamte Header notwendig, sondern nur die Definition der Variablen, die auch wirklich gebraucht werden. Das Programm hat 2 Nachteile: -Es könnte sein, daß der Player doch mal flackert (obwohl ich das nie bemerkt habe). -Wenn wir das Hauptprogramm um einen Spieleteil erweitern, könnte es sein, daß der player nicht mehr regelmäßig bewegt wird, weil zwischen 2 Aufrufen von WAIT zuviel Zeit vergeht. Deshalb nutzen wir nun die Fähigkeiten von QUICK noch mehr aus, und legen das Unterprogramm MOVE als VBI fest: INTER MOVE ... ENDVBI Damit wird es automatisch jede 50tel Sekunde einmal aufgerufen, egal was wir im Hauptprogramm tun ! Natürlich darf MOVE nur sehr kurz sein, sonst bekommen wir größte Schwierig- keiten. Aber ein paar PLAYER kann man ohne weiteres bewegen. (Das Spiel RUBBERBALL ist fast ein ein- ziger großer VBI!). Damit wird na- türlich die Prozedur WAIT überflüssig, und das Programm sieht nun so aus: Quick-Sourcetext D1:PLAYER2.QIK ---------------- Length: $0D3D Free : $6A2E ---------------- * PLAYER-DEMO in QUICK * (c) H.Schoenfeld '90 * Grafik-Variablen Header * (c) RAINDORF SOFT '90 * aus QUICKmagazin III BYTE (+ SDMCTL=559 *DMA Zugriff GPRIOR=623 *Farbkontrolle/Prioritaet PCOLR0=704 *Playerfarben COLOR0=708 *Farbregister HPOSP0=53248 *Hor. Playerpos. M0PF=53248 *Koll.reg. Missile/Playfi. HPOSM0=53252 *Hor. Missilepos. P0PF=53252 *Koll.reg. Player/Playfie. SIZEP0=53256 *Playerbreiten M0PL=53256 *Koll.reg. Missile/Player SIZEM=53260 *Missilebreiten P0PL=53260 *Koll.reg. Player/Player COLPM0=53266 *Farbregister Player + Mis COLPF0=53270 *Farbregister Anzeigenfeld PRIOR=53272 *Prioritaet VDELAY=53276 *2-zeilige Aufloesung GRACTL=53277 *Grafikkontrolle HITCLR=53278 *Kollision loeschen DMACTL=54272 *DMA-Kontrolle CHACTL=54273 *Zeichendarstellungkontr. PMBASE=54279 *Anfang der PM's CHBASE=54281 *Anfang des Zeichensatzes )+ BYTE (+ X,Y,AX,AY )+ WORD (+ SHAPEADR,FREEADR,VARADR=208 )+ ARRAY (+ FREE(10),SHAPE(10) )+ * Hauptprogramm * Setzt Playerformen fest * Initialisiert * Bewegt Player MAIN * "leerer Player" DATA(FREE) (+ 0,0,0,0,0,0,0,0,0,0 )+ VADR(FREE) FREEADR=VARADR * Playerform DATA(SHAPE) (+ 8,8,28,28,28,62,127,107,107,65 )+ VADR(SHAPE) SHAPEADR=VARADR X=48 Y=32 .INIT VBI(MOVE) * Hier koennte ein weiteres * Programm stehen, das nun voellig * unabhaengig von der Playerbewegung * laufen kann ENDMAIN * VBI zur Playerbewegung, der jede * 50/tel Sekunde aufgerufen wird. * Dabei wird 1 mal der Stick abgefragt * und 1 mal der PLAYER entspr. gesetzt INTER MOVE BEGIN .STICK .PLAYER ENDVBI * Stick abfragen und * Playerkoordinaten entspr. aendern PROC STICK LOCAL BYTE (+ STICK=632,TST )+ BEGIN IF STICK<>15 AY=Y AX=X AND(STICK,1,TST) IF TST=0 Y- ELSE AND(STICK,2,TST) IF TST=0 Y+ ENDIF ENDIF AND(STICK,4,TST) IF TST=0 X- ELSE AND(STICK,8,TST) IF TST=0 X+ ENDIF ENDIF ENDIF ENDPROC * Player darstellen PROC PLAYER BEGIN * Player an alter Pos. loeschen PLAYER($74,AY,10,FREEADR) * Player an neue Pos. kopieren HPOSP0=X PLAYER($74,Y,10,SHAPEADR) ENDPROC * Grafik und Player initialisieren PROC INIT BEGIN CLOSE(6) OPEN(6,8,12,"S:") *Grafik 12 HPOSP0=0 *player ganz rechts PCOLR0=136 *Playerfarbe Blau CLR($70,8) *Playerbereich loeschen SDMCTL=62 *Player an PMBASE=$70 *Anfang der PM's GRACTL=2 *Grafikkontrolle Player ENDPROC Um den VBI auszuschalten, schaltet man einen DUMMY-VBI ein: INTER NOTHING BEGIN ENDVBI Es könnte ja schließlich sein, daß man den player irgendwann nicht mehr bewegen will... Bis zum nächsten Mal ...