home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
assembler-kurs
/
listings3
/
listing7w2.s
< prev
next >
Wrap
Text File
|
1977-12-31
|
10KB
|
347 lines
; Listing7w2.s KOLLISIONEN ZWISCHEN UNGERADEN SPRITES
;
; In diesem Beispiel sehen wir, wie wir die Kollisionen zwischen ungeraden
; Sprites registrieren können. Diesmal sind zwei Raketen auf der Jagt nach
; dem Flugzeug, und einer der beiden ist ein ungerader Sprite.
; Wenn ihr das Programm startet, werdet ihr aber sehen, daß die Rakete
; ganz rechts nicht funktioniert.
; Ihr wollt sie repairieren? Dann lest den Kommentar am Ende des Listings.
SECTION CiriCop,CODE
Anfang:
move.l 4.w,a6 ; Execbase
jsr -$78(a6) ; Disable
lea GfxName(PC),a1 ; Name lib
jsr -$198(a6) ; OpenLibrary
move.l d0,GfxBase
move.l d0,a6
move.l $26(a6),OldCop ; speichern die alte COP
; Pointen das PIC auf die übliche Art
MOVE.L #PIC,d0
LEA BPLPOINTERS,A1
MOVEQ #2-1,D1
POINTBP:
move.w d0,6(a1)
swap d0
move.w d0,2(a1)
swap d0
ADD.L #40*256,d0
addq.w #8,a1
dbra d1,POINTBP
; Pointen auf die Sprites
LEA SpritePointers,a1 ; Pointer in der Copperlist
MOVE.L #MEINSPRITE0,d0 ; Adresse des Sprite in d0
move.w d0,6(a1)
swap d0
move.w d0,2(a1)
add.l #16,a1 ; Spritepointer 2
MOVE.L #MEINSPRITE2,d0 ; Adresse des Sprite in d0
move.w d0,6(a1)
swap d0
move.w d0,2(a1)
add.l #8,a1 ; Spritepointer 3
MOVE.L #MEINSPRITE3,d0 ; Adresse des Sprite in d0
move.w d0,6(a1)
swap d0
move.w d0,2(a1)
move.l #COPPERLIST,$dff080 ; unsere COP
move.w d0,$dff088 ; START COP
move.w #0,$dff1fc ; NO AGA!
move.w #$c00,$dff106 ; NO AGA!
mouse:
cmpi.b #$ff,$dff006 ; Zeile 255?
bne.s mouse
bsr.s BewegeSprite0 ; Bewege das Flugzeug
bsr.s BewegeSprite2 ; Bewege Rakete 1 gegen das Flugzeug
bsr.s BewegeSprite3 ; Bewege Rakete 2 gegen das Flugzeug
bsr.w CheckColl ; Kontrolliert Kollisionen und greift ein
Warte:
cmpi.b #$ff,$dff006 ; Zeile 255?
beq.s Warte
btst #6,$bfe001 ; Mouse gedrückt?
bne.s mouse
move.l OldCop(PC),$dff080 ; Pointen auf die SystemCOP
move.w d0,$dff088 ; Starten die alte COP
move.l 4.w,a6
jsr -$7e(a6) ; Enable
move.l gfxbase(PC),a1
jsr -$19e(a6) ; Closelibrary
rts
; Daten
GfxName:
dc.b "graphics.library",0,0
GfxBase:
dc.l 0
OldCop:
dc.l 0
; Diese Routine bewegt das Flugzeug um 2 Pixel pro Durchgang nach links
BewegeSprite0:
subq.b #1,HSTART0
rts
; Diese Routine steuert die Rakete. Sie tut es nur, wenn das Flugzeug nah
; genug dran ist, um getroffen zu werden.
BewegeSprite2:
cmp.b #$b0,HSTART0
bhi.s nicht_in_Schusslinie2 ; nicht starten, wenn das Flugzeug
subq.b #1,VSTART2 ; zu weit rechts ist
subq.b #1,VSTOP2
nicht_in_Schusslinie2:
rts
; Diese Routine steuert die Rakete. Sie tut es nur, wenn das Flugzeug nah
; genug dran ist, um getroffen zu werden.
BewegeSprite3:
cmp.b #$d0,HSTART0
bhi.s nicht_in_Schusslinie3 ; nicht starten, wenn das Flugzeug
subq.b #1,VSTART3 ; zu weit rechts ist
subq.b #1,VSTOP3
nicht_in_Schusslinie3:
rts
; Diese Routine kontrolliert, ob es eine Kollision gab. Wenn ja, löscht sie
; die beiden Sprites, die zusammengestoßen sind, indem sie die jeweiligen
; Spritepointer in der Copperlist löscht. Um unterscheiden zu können, welche
; der beiden Raketen ins Ziel gegangen ist, werden die Positionen abgefragt.
; In diesem Fall können die Raketen das Flugzeug nur von unten treffen; wenn
; sich eine Rakete also höher befindet als dieses, dann kann sie es nicht
; getroffen haben. Durch diese Methode können wir herausfinden, welche
; Rakete nun getroffen hat.
CheckColl:
move.w $dff00e,d0 ; liest CLXDAT ($dff00e)
; ein Lesevorgang dieses Register bewirkt
; auch dessen komplette Löschung, es ist deshalb
; ratsam, es sich in d0 zu kopieren, und dann
; dort die Tests durchzuführen
btst.l #9,d0
beq.s no_coll ; wenn keine Kollision, überspringe
MOVEQ #0,d0 ; ansonsten lösche die Sprites
LEA SpritePointers,a1 ; Pointer Sprite 0
move.w d0,6(a1) ; Lösche Spritepointer 0 in der Copperlist
move.w d0,2(a1)
; Nun müssen wir noch verstehen, welche der beiden Raketen getroffen hat.
; Wir kontrollieren die Höhe der Rakete, die weiter rechts steht: wenn
; sie höher ist als das Flugzeug, dann KANN sie es NICHT getroffen haben.
move.b VSTART0,d1 ; liest die Höhe des Flugzeuges
cmp.b VSTART3,d1 ; vergleicht mit der Höhe der Rakete rechts
bhi.s spr2_coll ; wenn das Flugzeug tiefer ist
; (also VSTART0 größer als VSTART3 ist)
; dann wurde die Kollision vom Sprite 2
; ausgelöst
LEA SpritePointer3,a1 ; ansonsten lösche Sprite 3
move.w d0,6(a1) ; Löscht Spritepointer 3 in der Copperlist
move.w d0,2(a1)
bra.s no_coll
spr2_coll:
LEA SpritePointer2,a1 ; Löscht Sprite 2
move.w d0,6(a1) ; löscht Spritepointer 2 in der Copperlist
move.w d0,2(a1)
no_coll:
rts
SECTION GRAPHIC,DATA_C
COPPERLIST:
SpritePointers:
dc.w $120,0,$122,0,$124,0,$126,0
SpritePointer2:
dc.w $128,0,$12a,0
SpritePointer3:
dc.w $12c,0,$12e,0,$130,0,$132,0
dc.w $134,0,$136,0,$138,0,$13a,0,$13c,0
dc.w $13e,0
; 5432109876543210
dc.w $98,%0000000000000000 ; CLXCON $dff098
dc.w $8E,$2c81 ; DiwStrt
dc.w $90,$2cc1 ; DiwStop
dc.w $92,$38 ; DdfStart
dc.w $94,$d0 ; DdfStop
dc.w $102,0 ; BplCon1
dc.w $104,$0024 ; BplCon2
dc.w $108,0 ; Bpl1Mod
dc.w $10a,0 ; Bpl2Mod
; 5432109876543210
dc.w $100,%0010001000000000 ; 2 Bitplane Lowres
BPLPOINTERS:
dc.w $e0,0,$e2,0 ;erstes Bitplane
dc.w $e4,0,$e6,0 ;zweites Bitplane
dc.w $180,$000 ; COLOR0 ; schwarzer Hintergrund
dc.w $182,$005 ; COLOR1 ; Farbe 1 del bitplane
dc.w $184,$a40 ; COLOR1 ; Farbe 2 del bitplane
dc.w $186,$f80 ; COLOR1 ; Farbe 3 del bitplane
dc.w $1A2,$06f ; COLOR17, also COLOR1 des Sprite0
dc.w $1A4,$0c0 ; COLOR18, also COLOR2 des Sprite0
dc.w $1A6,$0c0 ; COLOR19, also COLOR3 des Sprite0
dc.w $1AA,$444 ; COLOR21, also COLOR1 des Sprite2
dc.w $1AC,$888 ; COLOR22, also COLOR2 des Sprite2
dc.w $1AE,$0c0 ; COLOR23, also COLOR3 des Sprite2
dc.w $FFFF,$FFFE ; Ende der Copperlist
; ************ Hier ist der Sprite: KLARERWEISE in CHIP RAM! ************
MEINSPRITE0: ; Länge 6 Zeilen
VSTART0:
dc.b 180 ; Vertikale Anfangsposition des Sprite (da $2c a $f2)
HSTART0:
dc.b $d8 ; Horizontale Anfangsposition des Sprite (da $40 a $d8)
VSTOP0:
dc.b 186 ; 180+6=186
VHBITS:
dc.b $00
dc.w $0008,$0000
dc.w $1818,$0000
dc.w $2C28,$1010
dc.w $7FF8,$0000
dc.w $3FC0,$0000
dc.w $01F0,$0000
dc.w $0000,$0000
MEINSPRITE2: ; Länge 16 Zeilen
VSTART2:
dc.b 224 ; Vertikale Anfangsposition des Sprite (von $2c bis $f2)
HSTART2:
dc.b $86 ; Horizontale Anfangsposition des Sprite (von $40 bis $d8)
VSTOP2:
dc.b 240
dc.b 0
dc.w $0200,$0000
dc.w $0200,$0000
dc.w $0200,$0000
dc.w $0000,$0200
dc.w $0000,$0700
dc.w $0000,$0700
dc.w $0500,$0200
dc.w $0200,$0500
dc.w $0500,$0200
dc.w $0200,$0500
dc.w $1540,$0200
dc.w $0200,$1DC0
dc.w $0000,$1FC0
dc.w $0000,$1740
dc.w $0500,$0200
dc.w $0000,$0000
dc.w $0000,$0000
MEINSPRITE3: ; Länge 16 Zeilen
VSTART3:
dc.b 224 ; Vertikale Anfangsposition des Sprite (von $2c bis $f2)
HSTART3:
dc.b $a6 ; Horizontale Anfangsposition des Sprite (von $40 bis $d8)
VSTOP3:
dc.b 240
dc.b 0
dc.w $0200,$0000
dc.w $0200,$0000
dc.w $0200,$0000
dc.w $0000,$0200
dc.w $0000,$0700
dc.w $0000,$0700
dc.w $0500,$0200
dc.w $0200,$0500
dc.w $0500,$0200
dc.w $0200,$0500
dc.w $1540,$0200
dc.w $0200,$1DC0
dc.w $0000,$1FC0
dc.w $0000,$1740
dc.w $0500,$0200
dc.w $0000,$0000
dc.w $0000,$0000
; Bild der Startrampe der Raketen
PIC:
incbin "landschaft.raw"
end
Wie wir in der Lektion gesehen haben, erlaubt uns das Register CLXDAT nur
zu erkennen, ob eine Kollision zwischen Spritepaaren stattgefunden hat,
nicht zwischen den einzelnen Sprite. In diesem Beispiel sehen wir, wie
dieses Problem gelöst werden kann. Ich erinnere euch daran, daß die
Kollisionen der geraden Sprite (also 0,2,4,6) immer aktiviert sind, die
der ungeraden (1,3,5,7) aber erst aktivert werden müssen. Das geschieht
durch Kontrollbits im Register CLXCON ($dff098). Jeder ungerade Sprite hat
ein eigenes Kontrollbit und hann demzufolge unabhängig von den anderen
eingeschaltet werden. Wenn ihr versucht, das Listing auszuführen, dann
bemerkt ihr, daß die rechte Rakete nicht funktioniert. Das deshalb, weil
dieser Sprite ein ungerader ist (Sprite 3), und deaktiviert auch noch. In
der Copperlist findet ihr folgenden Befehl:
; 5432109876543210
dc.w $98,%0000000000000000
Er deaktiviert die Kollisionen für alle ungeraden Sprites (für die genaue
Beschreibung aller Bits seht euch die Lektion an). Um den Sprite 3 zu
aktivieren muß Bit 13 auf 1 gesetzt werden. Die Copperanweisung muß also
so aussehen:
; 5432109876543210
dc.w $98,%0010000000000000
Probiert das Listing nun aus, und ihr werdet sehen, daß die Rakete
funktioniert!
Ein weiteres Problem der Kollisionen ist, daß das Register CLXDAT nur
Kollisionen unter Spritepaaren aufspürt, nicht aber zwischen den einzelnen
Sprites. In unserem Beispiel gehören die Raketen beide zum selben Paar.
Wenn nun eine Kollision auftritt können wir nicht wissen, welche der
beiden Raktenen es gewesen ist, wenn wir nur das Register CLXDAT lesen. Um
das zu erfahren ist die meistens verwendete Methode das kontrollieren der
Spritepositionen. In diesem recht einfachem Beispiel braucht nur
verglichen werden, ob der Sprite rechts mehr oder weiniger ober dem
Flugzeug ist, es ist besser im Kommentar der Routine CheckColl erklärt. In
komplexeren Situationen, bei denen sich die Sprites in mehrere Richtungen
bewegen, sind aufwendigere Kontrollen notwendig, dort muß man sich dann
auf vertikale und horizontale Position berufen. Das Prinzip ist aber immer
das gleiche.
Ihr könnt überprüfen, daß unsere Routine immer die richtige Raktete
erwischt, indem ihr die Startpositionen der rechten Rakete verändert. Der
Anfangswert von HSTART3 ist auf $6a und garantiert der Rakete, daß sie das
Flugzeug treffen wird. Ersetzt $6a durch $6b. Wenn ihr das Beispiel nun
ausführt, werdet ihr sehen, daß sie nun das Flugzeug verfehlt. Aber keine
Angst! die zweite wird mitten rein dreschen!