COLLISION
COLLISION | |
Syntax: | COLLISION <Kollisionsquelle> [,<Zeilennummer>] |
Parameter | |
<Kollisionsquelle>: numerischer Ausdruck im Wertebereich von 1 bis 3 | |
<Zeilennummer>: numerischer Ausdruck im Wertebereich von 0 bis 65535 | |
Einordnung | |
Typ: | Anweisung |
Kontext: | Sprites |
Aufgabe: | Kollisionsbehandlungsroutine aktivieren oder deaktivieren |
Abkürzung: | coL |
Token: | $fe $17 (254 23) |
Verwandte Befehle | |
BUMP, PEN, TRAP |
Anmerkung: Dieser Artikel beschreibt den BASIC-Befehl COLLISION ab Commodore BASIC V7.0 oder höher.
Die Anweisung COLLISION dient dazu, Unterprogramme zur Kollisionsbehandlung festzulegen oder die Kollisionsbehandlung wieder abzuschalten.
Die Anweisung kennt folgende 2 Parameter:
- <Kollisionsquelle>: gibt an, welche Kollisionsquelle abgefangen wird. Folgende Werte sind erlaubt:
- 1: Sprite-Sprite-Kollision
- 2: Sprite-Bildschirm-Kollision
- 3: Lightpen-Impuls
- Andere Werte führen zu einem ?ILLEGAL QUANTITY ERROR.
- <Zeilennummer>: die Zeilennummer, an der die Kollisionsbehandlungsroutine beginnt. Erlaubt sind die Werte von 0 bis 65535, auch wenn Werte ab 64000 unsinnig sind, da eine Programmzeile maximal mit Zeilennummer 63999 angelegt werden kann. Fehlt der Parameter, so wird die Kollisionsbehandlung für die angegebene Quelle abgeschaltet. Obwohl beliebige numerische Ausdrücke erlaubt sind, sollte immer eine Konstante als Zeilennummer angegeben werden, da bei einem RENUMBER-Aufruf nur solche berücksichtigt und automatisch anpasst werden.
Tritt das angegebene Kollisionsereignis auf, so wird der augenblicklich ausgeführte BASIC-Befehl noch beendet und dann zur festgelegten Zeilennummer verzweigt. Existiert das Sprungziel nicht, wird die Fehlermeldung ?UNDEF'D STATEMENT ERROR IN <Zeilennummer> ausgegeben, wobei <Zeilennummer> die Zeile des zuletzt ausgeführten Befehls meint.
Treten während der Abarbeitung der Kollisionsbehandlungsroutine weitere Kollisionsereignisse auf, werden diese bis zur Beendigung der Routine zurückgestellt.
Bei mehreren gleichzeitigen Unterbrechungsanforderungen werden diese nacheinander, aufsteigend nach Nummer der Kollisionsquelle, aufgerufen.
Anmerkungen:
- Um die Unterbrechungsanforderungen schnell abzuarbeiten, sollten die Routinen möglichst am Anfang des Programms stehen. Ebenso sollten sie möglichst geschwindigkeitsoptimiert programmiert sein.
- Mit hoher Wahrscheinlichkeit wird während der Abarbeitung der Kollisionsbehandlungsroutine die Unterbrechungsanforderung erneut ausgelöst. Dies ist zu berücksichtigen, um mehrfaches Abarbeiten derselben Kollision zu verhindern.
- Beim Abschalten einer Kollisionsbehandlungsroutine wird die Registrierung neuer Unterbrechungsanforderungen der passenden Quelle abgeschaltet und zusätzlich (eigentlich unnötigerweise) das Sprungziel auf 0 gesetzt. Tritt nun während des Abschaltens das passende Kollisionsereignis auf, wird nach Abschluss des COLLISION-Befehls trotzdem noch die Kollisionsbehandlung aufgerufen, aber mit Zeilennummer 0. Existiert diese nicht, kommt es zu einem ?UNDEF'D STATEMENT ERROR IN <Zeilennummer>, ansonsten, falls dieser Fall nicht abgefangen wird, zu auf den ersten Blick unerklärlichen Fehlern im Programmablauf. Einige Möglichkeiten, diesen Bug zu umgehen, sind:
- Vor Abschalten der Kollisionsbehandlung sicherstellen, dass keine entsprechenden Unterbrechungsanforderungen mehr ausgelöst werden (z.B. durch Abschalten der Sprites).
- Abfangen des ?UNDEF'D STATEMENT ERROR durch eine passende TRAP-Routine.
- Das Programm mit Zeilennummer 0 beginnen und dort eine Wächtervariable überprüfen:
0 IF XX THEN RETURN:ELSE XX=1:GOTO 1000
- Wird ein Programm mittels RUN/STOP -Taste oder dem Befehl STOP unterbrochen und dann wieder fortgesetzt, werden alle Kollisionsabfragen abgeschaltet.
- COLLISION darf auch im Direktmodus aufgerufen werden, hat dann aber keinen Effekt.
Interna[Bearbeiten | Quelltext bearbeiten]
COLLISION verwendet folgende Adressen im RAM:
4726 ($1276) | Flag für Sprite-Sprite-Kollision |
4727 ($1277) | Flag für Sprite-Bildschirm-Kollision |
4728 ($1278) | Flag für Lightpen-Impuls |
4729-4731 ($1279-$127B) | Sprungziele Low-Byte |
4732-4734 ($127C-$127E) | Sprungziele High-Byte |
4735 ($127F) | Bitmaske für Kollisionsquelle |
Im Hauptrasterzeilen-IRQ wird das IRQ-Register des VIC (Register 25, Adresse $D019) ausgelesen und für jede aktive Interruptquelle, bei der das passende Bit in Adresse 4735 ($127F) gesetzt ist, das entsprechende Flag auf 255 ($FF) gesetzt.
In der BASIC-Hauptschleife wird vor dem Einlesen des nächsten BASIC-Befehls überprüft, ob eines der 3 Kollisionsflags gesetzt ist. Falls ja, wird das Kollisionsflag auf 0 gesetzt, Bit 7 der Bitmaske in 4735 ($127F) gesetzt, die Kollisionsbehandlungsroutine wie ein BASIC-Unterprogramm aufgerufen und anschließend Bit 7 der Bitmaske wieder gelöscht.
Beispiele[Bearbeiten | Quelltext bearbeiten]
Einfach[Bearbeiten | Quelltext bearbeiten]
100 COLLISION 1,1000
Das Programm verzweigt zur Zeile 1000, sobald mindestens 2 Sprites miteinander kollidieren.
200 COLLISION 3
Schaltet die Behandlung von Lightpen-Impulsen ab.
Komplex[Bearbeiten | Quelltext bearbeiten]
Ein kleines Spiel: Manövriere das "Raumschiff" (das gedrehte Quadrat) durch die sich bewegenden Bälle. Das Programm ist ähnlich dem Beispiel bei BUMP, verwendet aber COLLISION zusätzlich zu BUMP.
0 IF XX THEN RETURN: ELSE XX=1:GOTO 150: REM BEI XX<>0 UNERWUENSCHTE KOLLISIONSBEHANDLUNG 20 B=BUMP(2): IF B=0 THEN RETURN: REM BEI FEHLALARM SOFORT ZURUECK 30 DO 40 FOR I=1 TO 7 50 IF B AND BM(I) THEN BEGIN 60 Y=RSPPOS(I,1): IF Y<99 THEN MOVSPR I,180#SP(I): MOVSPR I,+0,60: ELSE MOVSPR I,0#SP(I): MOVSPR I,+0,218 70 BEND 80 NEXT 90 GET K$: IN=INSTR(I$,K$): IF IN THEN MOVSPR 8,-(DX(IN)),-(DY(IN)): IF RSPPOS(8,0)<24 THEN GS=2: EXIT 100 B=BUMP(2) AND NOT B: REM NUR NEUE SPRITE-KOLLISIONEN BERUECKSICHTIGEN 110 LOOP WHILE B 120 RETURN 130 GS=1: REM GAMESTATUS = GAME OVER 140 RETURN 150 REM SPRITES UND VARIABLEN INITIALISIEREN 155 XX=1 160 GRAPHIC 1,1: CIRCLE 1,12,10,5: PAINT 1,12,10: SSHAPE S$,0,0,23,20 170 BOX 1,27,5,37,15,45: SSHAPE R$,24,0,47,20: SPRSAV R$,8 180 I$="{LINKS}{RECHTS}{RAUF}{RUNTER}": DIM DX(4),DY(4): DX(1)=5: DX(2)=-5: DY(3)=5: DY(4)=-5 190 DIM BM(8),SP(8): BM=1 200 FOR I=1 TO 7: BM(I)=BM: BM=BM2*2: SP(I)=1+(I AND 3): SPRSAV S$,I: NEXT 210 DO: REM GRAFIK AUFBAUEN UND SPRITES EINSCHALTEN 220 SCNCLR 1: WIDTH 1: COLOR 1,1 230 BOX 1,0,0,319,12,0,1:BOX 1,0,187,319,199,0,1 240 FOR I=1 TO 7: MOVSPR I,40*I+5,200: MOVSPR I,A(I)#SP(I): SPRITE I,1,I,1: NEXT 250 MOVSPR 8,320,150: SPRITE 8,1,1,0: REM "RAUMSCHIFF" EINSCHALTEN 260 B=BUMP(2): B=0: REM VERALTETE KOLLISIONEN LOESCHEN 270 GS=0 280 COLLISION 1,130: REM SPRITE-SPRITE-KOLLISIONEN 290 COLLISION 2,20: REM SPRITE-BILDSCHIRM-KOLLISIONEN 300 REM HAUPTTEIL 310 DO 320 GET K$: IN=INSTR(I$,K$): IF IN THEN MOVSPR 8,-(DX(IN)),-(DY(IN)) 330 IF RSPPOS(8,0)<24 THEN GS=2: EXIT: REM GS (GAMESTATUS) = SIEG 340 LOOP UNTIL GS 350 REM SPRITES AUSSCHALTEN 360 COLLISION 1: COLLISION 2 370 FOR I=1 TO 8: SPRITE I,0: MOVSPR I,0#0: NEXT 380 IF GS=1 THEN CHAR 1,18,8,"GAME": CHAR 1,18,10,"OVER!": ELSE CHAR 1,15,8,"GESCHAFFT!" 390 CHAR 1,10,13,"NOCHMAL SPIELEN (J/N)?" 400 DO: GETKEY K$: LOOP UNTIL K$="J" OR K$="N" 410 LOOP WHILE K$="J" 420 GRAPHIC 0
Alarmfunktion/BASIC-Hintergrundverarbeitung[Bearbeiten | Quelltext bearbeiten]
An sich verläuft der Programmablauf in BASIC strikt durchgehend ohne Unterbrechung. Mit COLLISION und sich selbst bewegenden Sprites lässt sich eine zeitlich gesteuerte Unterbrechung eines Programms zu einer BASIC-Routine konstruieren, um etwa einen Alarm oder sonstige im "Hintergrund" laufende Tätigkeiten quasiparallel zum Hauptprogramm abarbeiten zu lassen. Eine Unterbrechung wird dabei erst nach Abarbeitung des aktuellen Kommandos verarbeitet. Somit kann etwa auch nicht eine INPUT-Eingabe per Timeout abgebrochen werden.
Das folgende Programm befindet sich in einer Eingabeschleife und bricht diese ab, sobald der Alarm abgelaufen ist. Etwaige Eingabe setzen den Alarm wieder zurück (eine Art Totmann-Funktion). Der Ablauf des Alarms bewirkt hier nur, dass ein Flag gesetzt wird, das in der Hauptschleife abgefragt wird. In der Alarm-Routine können aber auch aufwändigere Dinge gemacht werden, wie etwa am Bildschirm etwas aktualisieren (siehe Nachfolgende Anpassung für eine "Hintergrunduhr"). Man müsste hier eventuell nur auf die aktuelle Cursorposition achten, die so im Hintergrund immer wieder "entführt" werden könnte, wenn das Hauptprogramm ebenso am Bildschirm Ausgaben tätigt.
Bei einem Timeout endet das Programm und gibt die abgelaufene Zeit (nur zur Kontrolle) aus.
100 GOTO 1000 START 110 S1=1: S2=2: VI=51*1: REM 0/1 UNSICHTBAR/SICHTBAR 120 GRAPHIC 1,1:DRAW 1,0,0: REM SPRITE IMAGE (PUNKT) 130 SSHAPE A$,0,0,23,20: REM AUS BITMAP ... 140 SPRSAV A$,S1:SPRSAV A$,S2:GRAPHIC 0: REM ... ZU SPRITES 150 SPRITE S1,1,RCLR(0)-(VI>0),0,0,0,0: REM HINTERGRUNDFARBE 160 SPRITE S2,1,RCLR(0)-(VI>0),0,0,0,0 170 MOVSPR S1,24,VI: REM VI AB 50 WAERE SICHTBARER BEREICH 180 MOVSPR S2,24+TT*25,VI 190 MOVSPR S1,90#1: REM 1 = 1/25 S PRO PIXEL 200 COLLISION S1,500 210 RETURN 220 : 230 COLLISION S1 240 MOVSPR S1,0#0: SPRITE S1,0: SPRITE S2,0 250 RETURN 498 : 499 REM HINTERGRUNDAKTION 500 GOSUB 230 ALARM DEAKTIVIEREN 510 AL=1: REM ALARMENDE-FLAG 599 RETURN 999 : 1000 REM TIMEOUT TT: >0 BIS 13 1010 TT=5: GOSUB 110: TI$="000000" 1020 PRINT CHR$(147)CHR$(17)CHR$(17)CHR$(17)"BITTE UM TASTENEINGABE..." 1030 PRINT "TIMEOUT ="TT"SEKUNDEN" 1040 DO 1050 GET A$: PRINT A$"."; 1060 IF A$<>"" THEN TI$="000000": GOSUB 170 ALARM ZURUECKSETZEN 1070 IF AL THEN PRINT: PRINT"TIMEOUT "TI$" S,"TI"TICKS": END 1080 LOOP
- Einsprungstellen:
- 110: Alarmumgebung initialisieren und gemäß Variable TT den Alarm setzen
- 170: Alarm reaktivieren gemäß Zeit in Variable TT
- 230: Alarm deaktivieren
- 500: Alarmroutine
- 1000: Hauptprogramm
- Parametrisierung:
- 110: kann bei der VI-Zuweisung mit einer 1 die Sprites sichtbar gemacht werden. Im 2-Pixelabstand unterhalb des oberen Rahmenrandes bewegt sich das 1×1-Pixel-Sprite
- 190: Das MOVSPR-Kommando gibt die Geschwindigkeit vor. #1 entspricht 1/25 s/Pixel , #2 wäre 1/50. Je größer dieser Geschwindigkeitsparameter, desto geringer die maximal möglich Alarmzeit (das Limit ergibt sich aus der maximalen X-Position eines Sprites).
- Verwendete Variablen:
- S1, S2: Sprite-Nummern
- VI: Vertikale Position der Sprites
- A$: temporär: Sprite-Image-Daten
- Parametervariable:
- TT: Timeout-Wert in Sekunden, > 0, in 1/25-Auflösung (auch nichtganze Zahlen)
- Anwendungsvariablen:
- AL: Flag, =1 wenn der Alarm abgelaufen ist.
- A$: eingelesene Taste
Variante "Hintergrunduhr":
Ab Zeile 499 durch folgenden Teil ersetzt, wird während der Eingabe die TI$-Zeit rechts oben am Schirm dargestellt (im 1-Sekunden-Intervall aktualisiert).
499 REM HINTERGRUNDAKTION 500 GOSUB 170 ALARM NEU 510 FOR I=1 TO 6: POKE 1056+I,ASC(MID$(TI$,I,1)): NEXT 599 RETURN 999 : 1000 REM TIMEOUT TT: >0 BIS 13 1010 TT=1: GOSUB 110 1020 PRINT CHR$(147)CHR$(17)CHR$(17)CHR$(17)"BITTE UM TASTENEINGABE..." 1030 DO 1040 GET A$: PRINT A$; 1050 LOOP
APPEND | BANK | BEGIN | BEND | BLOAD | BOOT | BSAVE | BUMP | CATALOG | COLLISION | COLOR | CONCAT | DCLEAR | DCLOSE | DOPEN | DVERIFY | ENVELOPE | FAST | FETCH | FILTER | GO64 | MOVSPR | (OFF) | PEN | PLAY | POINTER | POT | (QUIT) | RECORD | RREG | RSPCOLOR | RSPPOS | RSPRITE | RWINDOW | SLEEP | SLOW | SOUND | SPRCOLOR | SPRDEF | SPRITE | SPRSAV | STASH | SWAP | TEMPO | WIDTH | WINDOW | XOR