home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga MA Magazine 1998 #6
/
amigamamagazinepolishissue1998.iso
/
coders
/
assembler-kurs
/
listings3
/
listing7m.s
< prev
next >
Wrap
Text File
|
1977-12-31
|
12KB
|
381 lines
; Listing7m.s Positionierung der Sprite mittels einer Universalroutine.
; Dieses Beispiel zeigt eine universelle Routine, die die Sprites bewegen
; kann, sie beachtet dabei alle Bits (horizontal und vertikal) des Sprites.
; Weiters zählt sie automatisch das Offset (128 für die X-Koordinaten,
; $2c für die Y-Koordinaten) dazu.
; Somit können die Koordinaten in der Tabelle die realen sein, also von
; 0 bis 320 für die horizontalen, und von 0 bis 256 für die vertikalen.
SECTION CipundCop,CODE
Anfang:
move.l 4.w,a6 ; Execbase
jsr -$78(a6) ; Disable
lea GfxName(PC),a1 ; Libname
jsr -$198(a6) ; OpenLibrary
move.l d0,GfxBase
move.l d0,a6
move.l $26(a6),OldCop ; speichern die alte COP
; Pointen auf das "leere" PIC
MOVE.L #BITPLANE,d0 ; wohin pointen
LEA BPLPOINTERS,A1 ; COP-Pointer
move.w d0,6(a1)
swap d0
move.w d0,2(a1)
; Pointen auf den Sprite
MOVE.L #MEINSPRITE,d0 ; Adresse des Sprite in d0
LEA SpritePointers,a1 ; Pointer in der Copperlist
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
mouse:
cmpi.b #$ff,$dff006 ; Zeile 255?
bne.s mouse
btst #2,$dff016
beq.s Warte
bsr.w BewegeSprite ; Bewege Sprite
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 SystemCOP
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
; Um den Sprite richtig zu bewegen lesen wir zuerst die Tabelle, um zu
; wissen, welche Positionen er einnehmen muß, dann übergeben wir diese
; mitsamt der Adresse und der Höhe des Sprites an die Routine UniMoveSprite.
; Das geschieht durch die Register a1,d0,d1,d2
BewegeSprite:
bsr.s LiesTabellen ; Liest die X-und Y-Koordinaten aus den Tabellen,
; gibt in das Register a1 die Adresse des
; Sprite, in d0 die Y-Pos, in d1 die X-Pos
; und in d2 die Höhe des Sprite.
;
; Eingangsparameter von UniMoveSprite:
;
; a1 = Adresse des Sprite
; d0 = Vertikale Position des Sprite auf dem Screen (0-255)
; d1 = Horizontale Position des Sprite auf dem Screen (0-320)
; d2 = Höhe des Sprite
bsr.w UniMoveSprite ; führt die Universalroutine aus, die den
; Sprite bewegt
rts
; Diese Routine liest aus den zwei Tabellen die realen Koordinaten der Sprite.
; Also die X-Koordinate, die von 0 bis 320 geht, und die Y, von 0 bis 256
; (ohne Overscan). Da wir in diesem Beispiel kein Overscan verwenden ist die
; Koordinatentabelle für die Y-Positionen aus Byte erstellt. Die Tabelle für
; die X-Koordinaten hingegen besteht aus Word, da sie Werte größer als 256
; enthaltne muß.
; Diese Routine positioniert den Sprite aber nicht direkt. Sie limitiert sich
; darauf, es die Universalroutine tun zu lassen, sie übermittelt ihr nur
; die Koordinaten über die Register d0 und d1.
LiesTabellen:
ADDQ.L #1,TABYPOINT ; Point auf das nächste Byte
MOVE.L TABYPOINT(PC),A0 ; Adresse aus Long TABXPOINT
; wird in a0 kopiert
CMP.L #ENDETABY-1,A0 ; Sind wir beim letzten Longword der TAB?
BNE.S NOBSTARTY ; noch nicht? dann weiter
MOVE.L #TABY-1,TABYPOINT ; Starte wieder beim ersten Byte (-1)
NOBSTARTY:
moveq #0,d0 ; Lösche d0
MOVE.b (A0),d0
ADDQ.L #2,TABXPOINT ; Pointe auf das nächste Word
MOVE.L TABXPOINT(PC),A0 ; Adresse aus Long TABXPOINT
; wird in a0 kopiert
CMP.L #ENDETABX-2,A0 ; sind wir beim letzten Word der TAB?
BNE.S NOBSTARTX ; noch nicht? dann weiter
MOVE.L #TABX-2,TABXPOINT ; beginne beim ersten Word-2
NOBSTARTX:
moveq #0,d1 ; löscht d1
MOVE.w (A0),d1 ; setzen den Wert der Tabelle in d1
lea MEINSPRITE,a1 ; Adresse des Sprite in a1
moveq #13,d2 ; Höhe des Sprite in d2
rts
TABYPOINT:
dc.l TABY-1 ; BEMERKE: Die Werte in der Tabelle sind hier
; Bytes, wir arbeiten also mit einem ADDQ.L #1,
; TABYPOINT, und nicht #2 wie bei den Words
; oder #4 bei den Longwords.
TABXPOINT:
dc.l TABX-2 ; Bemerke: die Werte in der Tabelle sind hier Word
; Tabelle mit vorausberechneten Y-Koordinaten.
; Zu Bemerken, daß die Y-Position des Sprites zwischen $2c und $f2 liegen muß,
; wenn wir ihn in das Videofenster bekommen wollen. In der Tabelle sind alles
; Werte enthalten, die innerhalb dieses Limits liegen.
; So macht man sich eine Tabelle:
; BEG> 0
; END> 360
; AMOUNT> 200
; AMPLITUDE> $f0/2
; YOFFSET> $f0/2
; SIZE (B/W/L)> b
; MULTIPLIER> 1
TABY:
incbin "ycoordinatok.tab" ; 200 .B Werte
ENDETABY:
; Tabelle mit vorausberechneten X-Koordinaten.
; Diese Tabelle enthält die REALEN Koordinaten des Bildschirmes, und nicht
; die "halbierten" Werte wie für den Scroll, beidem jedesmal 2 Pixel auf einmal
; genommen wurden. In der Tabelle kommen keine Bytes vor, die größer als
; 304 (320-16, wegen des Sprites) oder kleiner als 0 sind.
TABX:
incbin "xcoordinatok.tab" ; 150 .W Werte
ENDETABX:
; Universelle Sprite-Positionierungs-Routine.
; Diese Routine verändert die Position des Sprites, dessen Adresse
; sich in a1 befindet und dessen Höhe im Register d2 steht.
; Seine Koordinaten für X und Y stehen jeweils in den Registers
; d0 und d1.
; Vor dem Aufruf dieser Routine muß die Adresse des Sprites in a1
; gegeben werden, seine Höhe in d2, und die Koordinaten, auf die
; er gesetzt werden soll in d0 (X) und d1 (Y).
; Diese Prozedur wird "Parameterübergabe" genannt.
; Bemerke, diese Routine modifiziert die Register d0 und d1.
; Eingangsparameter von UniMoveSprite:
;
; a1 = Adresse des Sprite
; d0 = Vertikale Position des Sprite auf dem Screen (0-255)
; d1 = Horizontale Position des Sprite auf dem Screen (0-320)
; d2 = Höhe des Sprite
;
;
UniMoveSprite:
; Vertikale Positionierung
ADD.W #$2c,d0 ; zähle den Offset vom Anfang des Screens dazu
; a1 enthält die Adresse des Sprite
MOVE.b d0,(a1) ; kopiert das Byte in VSTART
btst.l #8,d0
beq.s NichtVSTARTSET
bset.b #2,3(a1) ; Setzt das Bit 8 von VSTART (Zahl > $FF)
bra.s ToVSTOP
NichtVSTARTSET:
bclr.b #2,3(a1) ; Löscht das Bit 8 von VSTART (Zahl < $FF)
ToVSTOP:
ADD.w D2,D0 ; Zähle die Höhe des Sprite dazu, um
; die Endposition zu errechnen (VSTOP)
move.b d0,2(a1) ; Setze den richtigen Wert in VSTOP
btst.l #8,d0
beq.s NichtVSTOPSET
bset.b #1,3(a1) ; Setzt Bit 8 von VSTOP (Zahl > $FF)
bra.w VVSTOPENDE
NichtVSTOPSET:
bclr.b #1,3(a1) ; Löscht Bit 8 von VSTOP (Zahl < $FF)
VVSTOPENDE:
; horizontale Positionierung
add.w #128,D1 ; 128 - um den Sprite zu zentrieren
btst #0,D1 ; niederwert. Bit der X-Koordinate auf 0?
beq.s NiederBitNull
bset #0,3(a1) ; Setzen das niederw. Bit von HSTART
bra.s PlaceCoords
NiederBitNull:
bclr #0,3(a1) ; Löschen das niederw. Bit von HSTART
PlaceCoords:
lsr.w #1,D1 ; SHIFTEN, verschieben den Wert von HSTART um
; 1 Bit nach Rechts, um es in den Wert zu
; "verwandeln", der dann in HSTART kommt, also
; ohne dem niederwertigen Bit.
move.b D1,1(a1) ; geben den Wert XX ins Byte HSTART
rts
SECTION GRAPHIC,DATA_C
COPPERLIST:
SpritePointers:
dc.w $120,0,$122,0,$124,0,$126,0,$128,0 ; SPRITE
dc.w $12a,0,$12c,0,$12e,0,$130,0,$132,0
dc.w $134,0,$136,0,$138,0,$13a,0,$13c,0
dc.w $13e,0
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,0 ; BplCon2
dc.w $108,0 ; Bpl1Mod
dc.w $10a,0 ; Bpl2Mod
; 5432109876543210
dc.w $100,%0001001000000000 ; Bit 12 an!! 1 Bitplane Lowres
BPLPOINTERS:
dc.w $e0,0,$e2,0 ;erstes Bitplane
dc.w $180,$000 ; Color0 ; Hintergrund Schwarz
dc.w $182,$123 ; Color1 ; Farbe 1 des Bitplane, die
; in diesem Fall leer ist,
; und deswegen nicht erscheint
dc.w $1A2,$F00 ; Color17, oder COLOR1 des Sprite0 - ROT
dc.w $1A4,$0F0 ; Color18, oder COLOR2 des Sprite0 - GRÜN
dc.w $1A6,$FF0 ; Color19, oder COLOR3 des Sprite0 - GELB
dc.w $FFFF,$FFFE ; Ende der Copperlist
; ************ Hier ist der Sprite: NATÜRLICH muß er in CHIP RAM sein! ********
MEINSPRITE: ; Länge 13 Zeilen
dc.b $50 ; Vertikale Anfangsposition des Sprite (von $2c bis $f2)
dc.b $90 ; Horizontale Anfangsposition des Sprite (von $40 bis $d8)
dc.b $5d ; $50+13=$5d ; Vertikale Endposition des Sprite
dc.b $00
dc.w %0000000000000000,%0000110000110000 ; Binäres Format für ev. Änderungen
dc.w %0000000000000000,%0000011001100000
dc.w %0000000000000000,%0000001001000000
dc.w %0000000110000000,%0011000110001100 ;BINÄR 00=COLOR 0 (DURCHSICHTIG)
dc.w %0000011111100000,%0110011111100110 ;BINÄR 10=COLOR 1 (ROT)
dc.w %0000011111100000,%1100100110010011 ;BINÄR 01=COLOR 2 (GRÜN)
dc.w %0000110110110000,%1111100110011111 ;BINÄR 11=COLOR 3 (GELB)
dc.w %0000011111100000,%0000011111100000
dc.w %0000011111100000,%0001111001111000
dc.w %0000001111000000,%0011101111011100
dc.w %0000000110000000,%0011000110001100
dc.w %0000000000000000,%1111000000001111
dc.w %0000000000000000,%1111000000001111
dc.w 0,0 ; 2 word auf NULL definieren das Ende des Sprite.
SECTION LEERESPLANE,BSS_C ; Ein auf 0 gesetztes Bitplane, wir
; müssen es verwenden, denn ohne Bitplane
; ist es nicht möglich, die Sprites
; zu aktivieren
BITPLANE:
ds.b 40*256 ; Bitplane auf 0 Lowres
end
In diesem Listing präsentieren wir eine Universalroutine, um die Sprites
zu verstellen, sie heißt "UniMoveSprite". Diese Routine übernimmt alle
Aspekte der Positionierung der Sprite, es verwaltet alle Bit richtig und
zählt den Offset dazu. Somit können die Werte direkt als "reale" Werte
übergeben werden, die Tabellen können also die Werte enthalten, auf denen
der Sprite sich am Bildschirm im Endeffekt befinden soll.
Diese Routine funktioniert mit jedem Sprite. Denn die Adresse des Sprite
ist nicht fix, sie wird aus dem Register a1 ausgelesen. Das bedeutet daß:
VSTART sich an der Adresse in a1 befindet
HSTART sich im nachfolgenden Byte befindet, also an der Adresse a1 + 1
VSTOP sich zwei Bytes danach befindet, oder a1 + 2
das vierte Byte drei Byte danach liegt, oder a1 + 3
UniMoveSprite greift auf diese Byte mittels indirekter Adressierung über
Register mit Offset zu:
um auf VSTART zuzugreifen verwendet man (a1)
um auf HSTART zuzugreifen verwendet man 1(a1)
um auf VSTOP zuzugreifen verwendet man 2(a1)
um auf das vierte Byte verwendet man 3(a1)
Auch die Höhe des Sprites ist nicht fix, sondern im Register d2 enthalten.
Damit kann die Routine dazu verwendet werden, um Sprites verschiedener
Höhe zu bewegen. Weiters holt sich die Routine die Daten nicht direkt aus
der Tabelle, sondern bekommt sie über d0 und d1 mitgeteilt.
Und wer gibt diese Daten in die Register? Eine andere Routine, die
"LiesTabellen" heißt, sie holt die Koordinaten aus den Tabellen, gibt sie
in die Register d0 und d1 und führt dann die Routine "UniMoveSprite" aus.
Praktisch haben wir die Aufgaben auf zwei Routinen aufgeteilt, so, als ob
es zwei Angestellte wären. Die Routine "LiesTabellen" macht ihre Aufgabe,
dann sagt sie: "Hey, Routine UniMoveSprite, hier kriegste ´nen Sprite zu
bewegen, ich schick´ dir die Adresse im Register a1. In d2 schick ich dir
die Höhe. Dann noch die Koordinaten, die bekommst du über die Register d0
und d1. Du weißt ja, wie man damit umgeht!"
Die Routine "UniMoveSprite" bekommt die Adresse des Sprite und die
Koordinaten und setzt diese dann in die richtigen Bytes des Sprites. Die
"Spedition" der Koordinaten über die Register heißt "Parameterübergabe".
Die Aufteilung der Arbeiten ist eine sehr bequeme Sache. Nehmen wir an,
wir möchten einen Sprite bewegen, der seine Y-Koordinaten aus einer
Tabelle bekommt, die X-Koordinaten hingegen mit ADDQ/SUBQ separat
berechnet werden, um praktisch einen Sprite zu schaffen, der dauernd links
und rechts geht, dabei aber auf- und abschwingt. Da die Routine die Daten
aus den Registern holt, insteressiert es sie nicht, ob sie aus einer
Tabelle kommen oder berechnet werden. Deshalb können wir die Routine
wiederverwenden, ohne etwas ändern zu müssen. Und da sie die Adresse und
die Höhe des Sprites auch über Register bekommt ist sie somit auch an
keinen bestimmten Sprite gebunden und universell einsetzbar.
Von nun an werden wir also für jedes Beispiel mit Sprites diese Routine
"UniMoveSprite" verwenden, ohne sie nur ein einziges Mal abändern zu
müssen.