
ASSEMBLERKURS - LEKTION 7

In  dieser  Lektion  werden  wir  über  die  Sprites, den Joystick und den
logischen Operationen des 68000ers wie  AND, OR, EOR, NOT, LSR, ROL,   etc
sprechen.

Erinnert  euch,  "V LISTINGS3" zu tippen, um die .raw - Files, die sich in
dieser Directory befinden, laden zu können. Dort befinden  sich  auch  die
Listings aus dieser Lektion.

Die  Sprites  sind  grafische Objekte mit einer präzisen Größe, maximal 16
Pixel breit, die sich unabhängig von den  Bitplanes  bewegen  lassen.  Der
Mauspointer  z.B.  ist  ein  solcher  Sprite,  er  wird vom Betriebssystem
verwaltet. Er kann sich überall  bewegen,  ohne  sich  um  die  "darunter"
liegenden Bitplanes Gedanken machen zu müssen.
Die Sprites könnte man als "Geister"-Bilder auffassen, die sich "über" den
Bitplanes  bewegen,  aber  Achtung:  nicht  alles,  was  sich bewegt, sind
Sprites! Denn es können maximal 8 davon dargestellt werden, da  es  nur  8
Pointer in der Copperlist für sie gibt:

COPPERLIST:
SpritePointers:
	dc.w	$120,0,$122,0	; Pointer für Sprite 0
	dc.w	$124,0,$126,0	; Pointer für Sprite 1
	dc.w	$128,0,$12a,0	; ""	""	""   2
	dc.w	$12c,0,$12e,0	; ""	""	""   3
	dc.w	$130,0,$132,0	; ""	""	""   4
	dc.w	$134,0,$136,0	; ""	""	""   5
	dc.w	$138,0,$13a,0	; ""	""	""   6
	dc.w	$13c,0,$13e,0	; ""	""	""   7

Die Pointer auf die  Sprites  heißen  SPRxPT  (an  Stelle  der  "x"  kommt
natürlich  die  Nummer  des  Sprites:  wir haben also SPR0PT, SPR1PT, ...,
SPR7PT, und wenn wir von SPRxPT  sprechen,  meinen  wir  generell  alle  8
Pointer).  Bis  jetzt  haben  wir  sie  in  der  Copperlist immer auf NULL
gesetzt, damit sie uns nicht stören, denn wenn sie "frei rumlaufen"  haben
wir sie immer auf unseren Bildern sitzen.
Die Sprites sind vom Rest des Screens isoliert, fast so, als wären sie  in
einem  durchsichtigen  Couvert  über  dem  Bildschirm,  sie  sind immer in
Lowres, auch wenn der Screen in HiRes oder Interlace arbeitet. Ein  Beweis
dafür,  daß  sie  mit  den Bitplanes nichts zu tun haben ist, daß man sie,
wenn wir sie bewegen wollen, nicht löschen und weiter  hinten  neuzeichnen
müssen,  wie es der Fall wäre, wenn wir ein Stück Grafik in einer Bitplane
bewegen möchten.
Um einen Sprite zu bewegen, brauchen wir  nur  seine  Koordinaten  ändern,
indem  wir  mit wenigen und schnellen Befehlen auf einige dafür bestimmten
Bytes am Anfang der Spritestruktur  selbst  zugreifen.  Wenn  die  Sprites
nicht  ausreichen, um Raumschiffe und Figuren in einem Spiel darzustellen,
dann verwenden wir den Blitter, um Grafikblöcke  (Bob)  zu  kopieren.  Wir
werden  später  darauf  zurückkommen.  Wie schon erwähnt, ist die maximale
Breite eines Sprite 16 Pixel, während die Höhe beliebig  sein  kann,  auch
den  ganzen  Bildschirm, 256 Zeilen. Um z.B. das Monster am Ende des Level
darzustellen, könnten wir z.B. alle 8  Sprites  zusammenkleben  und  somit
16*8=128  Pixel  erreichen. Dieses Monster wäre aber recht farblos, da zur
Zeit die Sprites nur 3 Farben haben. Die vierte  ist  der  "durchsichtige"
Teil,   wo   also  der  Hintergrund  durchscheint,  die  darunterliegenden
Bitplanes.

Die Charakteristik der Sprites ist, daß sie einfach  herzustellen  und  zu
animieren  sind.  Denn  man  kann sie einfach mit einem Malprogramm malen,
Hauptsache, sie sind nicht breiter als 16 Pixel und sind  in  drei  Farben
plus  Hintergrund  gehalten.  Danach einfach durch den IFF-Konverter jagen
und in SPRITE konvertieren.
Oder sie können direkt in binär gezeichnet werden, wie  wir  es  schon bei 
den 8x8 Fonts gesehen haben:
  
- Plane 1 - - Plane 2 -		; Die Überlagerung dieser
						    ; zwei "Planes" aus Bits
	dc.w	%0111110000000000,%0111110000000000 ; bestimmt die Farbe. Das
	dc.w	%1000001000000000,%1111111000000000 ; ist der Default - Maus-
	dc.w	%1111010000000000,%1000110000000000 ; pointer des Kickstart 1.3
	dc.w	%1111101000000000,%1000011000000000 ; Erkennt ihr ihn wieder??
	dc.w	%1111110100000000,%1001001100000000
	dc.w	%1110111010000000,%1010100110000000
	dc.w	%0100011101000000,%0100010011000000
	dc.w	%0000001110100000,%0000001001100000
	dc.w	%0000000111100000,%0000000100100000
	dc.w	%0000000011000000,%0000000011000000
	dc.w	%0000000000000000,%0000000000000000

	dc.w	0,0	; Zwei auf NULL gesetzte Word signalisieren das
				; Ende des Sprite.

In diesem Fall ist die Breite 16 Pixel, und nicht 8  wie  bei  den  Fonts,
weil  wir  ihn  in  einem  Word  (dc.w)  und nicht in einem Byte zeichnen.
Weiters hat er 3 Farben plus die Durchsichtige, also insgesamt 4, wie  ein
Bild mit 2 Bitplanes, es braucht also ein Paar von "Planes", genau wie bei
den Bitplanes. Ihre Überlagerung bestimmt die Farbe eines  jeden  Punktes.
Sie kann wie folgt sein:

	Plane 1 - Plane 2

Binär:	 0	-	0	= COLOR 0 (Durchsichtig)
Binär:	 1	-	0	= COLOR 1
Binär:	 0	-	1	= COLOR 2
Binär:	 1	-	1	= COLOR 3

Denn mit 2 Planes ergeben sich vier Überlagerungsmuster:  %00,  %01,  %10,
%11.

Um die Position des Sprite zu bestimmen, müssen wir nichts anderes tun als
die X und Y-Koordinate in den ersten Bytes des Sprite  selbst  einzufügen.
Der  Sprite  besteht nämlich vor den Daten des Bildes aus vier Bytes, oder
zwei Words, den  sogenannten  KONTROLLWORDS,  und  da  hinein  kommen  die
Positionskoordinaten auf dem Bildschirm. Um genauer  zu  sein,  das  erste
Byte, VSTART genannt, beinhaltet die vertikale Position des Spriteanfangs;
das zweite Byte hingegen die horizontale  Position  (HSTART).  Das  Dritte
bekommt  das Ende des Sprites, vertikal gesehen: um diesen Wert zu finden,
ganz einfach die Höhe des Sprites mit  der  Anfangskoordinate  des  selben
addieren  und  rein  damit.  Das Resultat ist nach Adam Riese das Ende des
Sprites.
Im vierten Byte kommen die Spezialfunktionen, wie immer verweise  ich  auf
später.
VSTART und HSTART (Vertical Start und  Horizontal  Start)  sind  also  die
Koordinaten der linken, oberen Ecke des Sprites:

	#....
	.....
	.....
	.....
	.....


VSTOP hingegen ist die vertikale Position des Endes des Sprite:


	.....
	.....
	.....
	.....
	#####	-> Zeile, in der der Sprite aufhört.


Um z.B. einen Sprite an Position XX=$90  und  YY=$50  anzuzeigen,  der  20
Pixel lang ist, werden wir so vorgehen:


		;AYAX  EY - AY=Anfang Y, AX=Anfang X, EY=Ende Y
SPRITE:
	dc.w	$5090,$6400	;Y=$50, X=$90, Höhe= $50+20, alos $64
; hier beginnen die Daten der 2 Plaenes des Sprite:

	dc.w	%0000000000000000,%0000110000110000
	dc.w	%0000000000000000,%0000011001100000
	...
	dc.w	0,0	; Ende des Sprite

Das erste Byte, VSTART, ist auf $50, das Zweite, HSTART, auf $90, und  das
Dritte,  die  vertikale  Position des Spriteendes, auf $64, also $50 + 20.
Also die Anfangsposition + Länge des Sprite. Das vierte  Byte  lassen  wir
vorerst  auf 0. Ich sage euch gleich schon, daß das HSTART einen Sprite um
jeweils 2 Pixel verstellt, wenn wir also $51 eingeben, werden wir auf  $52
gelangen.  Es  sind nur Zweierschritte möglich. Wir werden aber sehen, wie
unter Verwendung des SpeizialBytes Nr. 4 diese Situation in den  Griff  zu
bekommen  ist,  und  das  ein  Scroll von einem Pixel möglich ist. Was den
vertikalen Scroll angeht,  VSTART  und  VSTOP  besorgen  uns  schon  einen
schönen 1-Pixel-Schritt. Das einzige Limit ist die Videozeile $FF, darüber
hinaus kommen wir nur, wenn wir ein Bit  im  vierten  Byte  verwenden.  Am
Anfang  werden wir aus Gründen der Einfachheit nur die Bytes VSTART, VSTOP
und HSTART verwenden, und die Zeierschritte in der Horizontalen hinnehmen.
Erst  später  werden  wir  sehen, wie wir "flüssigere" Scrolls hinkriegen.
Erinnert euch also an die Eigenschaft, das z.B. mit einem:

	ADDQ.B	#1,HSTART

der Sprite um 2 Pixel, und nicht um einen, verstellt wird.

Um auf die 3 Bytes VSTART/HSTART/VSTOP zuzugreifen,  könnte  man  etwa  so
tun:

	MOVE.B	#$50,SPRITE		; VSTART = $50
	MOVE.B	#$90,SPRITE+1	; HSTART = $90
	MOVE.B	#$64,SPRITE+2	; VSTOP  = $64 ($50+20)

Oder man kann ein Label für jedes Byte definieren, und somit alles  klarer
gestalten:


SPRITE:
VSTART:			; Beginn Anfangsposition VERTIKAL
	dc.b $50
HSTART:			; Beginn Anfangsposition HORIZONTAL
	dc.b $90
VSTOP:
	dc.b	$64	; Endposition VERTIKAL
	dc.b	$00	; Byte für Spezialanwendungen, im Moment auf 0

; hier beginnen die Daten für die Planes des Sprite:

	dc.w	%0000000000000000,%0000110000110000
	dc.w	%0000000000000000,%0000011001100000
	...
	dc.w	0,0	; Ende des Sprite

In diesem Fall würden wir auf die Label VSTART, VSTOP und HSTART agieren:

	ADDQ.B  #1,HSTART	; bewegt den Sprite um 2 Pixel nach rechts
						; (2 Pixel und nicht 1, wie oben erklärt)

	SUBQ.B  #1,HSTART	; bewegt den Sprite um 2 Pixel nach links

Um den Sprite nach  Oben  oder  Unten  zu  bewegen  müssen  wir  uns  aber
erinnern, beide Bytes VSTART und VSTOP zu verändern, denn es ist klar, daß
in diesem Fall das erste Pixel wie auch das Letzte seine Position ändert:

	ADDQ.B  #1,VSTART	; \ Bewegt den Sprite um 1 Pixel nach Unten
	ADDQ.B  #1,VSTOP	; /

	SUBQ.B  #1,VSTART	; \ Bewegt den Sprite um 1 Pixel nach Oben
	SUBQ.B  #1,VSTOP	; /


Zur Wiederholung, das ist die Struktur des Sprite:


	Erstes Kontrollword,			zweites Kontrollword
	erste   Zeile (.w) des Plane 1,  erste   Zeile (.w) des Plane 2
	zweite  Zeile (.w) des Plane 1,  zweite  Zeile (.w) des Plane 2
	dritte  Zeile (.w) des Plane 1,  dritte  Zeile (.w) des Plane 2
	vierte  Zeile (.w) des Plane 1,  vierte  Zeile (.w) des Plane 2
	fünfte  Zeile (.w) des Plane 1,  fünfte  Zeile (.w) des Plane 2
	...
	DC.W	0,0			; die letzte Zeile muß zwei Nullen enthalten

Die Daten des Sprite sind in Plane 1 und Plane 2  unterteilt,  einzig  und
alleine,  um  anzuzeigen,  daß  bei  deren  Überlagerung die 3 Farben plus
Transparent zu Stande kommen, analog wie bei den Bitplanes,  es  ist  aber
nicht damit zu verwechseln!


DIE FARBEN DER SPRITE

Um die Farben der Sprites  zu  definieren  müssen  die  gleichen  Register
verwendet  werden  wie bei den Bitplanes, da der Amiga nur 32 Farbregister
besitzt. Die Ingeneure haben gedacht, den Sprites die Farben  vom  16  bis
zum  31  zuzuteilen, somit können die Sprites, wenn das Bild nicht in in 5
Bitplanes -oder 32 Farben - ist, andere  benutzen  als  das  Bild  selbst.
Ansonsten  haben  sie  16 Farben gemeinsam mit dem darunterliegenden Bild.
Schauen wir uns mal an, wie wir die Farben des ersten Sprite hinbekommen:


(Die Sprites sind von 0 bis 7 durchnumeriert)

	COLOR 0 des Sprite 0 = TRANSPARENZ, wird nicht definiert
	COLOR 1 des Sprite 0 = COLOR17 ($dff1a2)
	COLOR 2 des Sprite 0 = COLOR18 ($dff1a4)
	COLOR 3 des Sprite 0 = COLOR19 ($dff1a6)

Color 0, oder die vierte, ist die Transparenz, sie wird nicht definiert.

Sehen wir vor dem weitermachen, das erste  Beispiel  einer  Anzeige  eines
Sprite   in   Listing7a.s   In  diesem  Beispiel  wird  der  erste  Sprite
angepointet,  die  anderen  sieben  beliben  auf  NULL.  Um  einen  Sprite
anzupointen  wird  gleich  vorgegangen  wie  bei den Bitplanes, da sie die
Pointer gleich funktionieren wie bei den Bitplanes:

	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)

Ich erinnere daran, daß um ein Sprite anzuzeigen, mindestens ein  Bitplane
"eingeschaltet"  sein  muß, ohne Bitplane keine Sprites. Des Weiteren wird
ein Sprite "abgeschnitten", wenn er außerhalb des  Videofensters  gelangt,
das  zuvor mit DIWSTART und DIWSTOP definiert wurde, er kann nur innerhalb
angezeigt  werden.  Um  ihn  z.B.  in  der  Mitte  eines  320x256  Screens
anzuzeigen,  auf  Position 160x128, ist weiters zu beachten, daß die erste
Koordinate links oben nicht 0,0 ist, sondern $40, $2c,  deswegen  muß  $40
zur  X-Koordinate und $2c zur YKoordinate addiert werden. $40+160, $2c+128
entprechen also den Koordinaten 160, 128  in  einem  Screen  320x200  ohne
Overscan.
Da wir noch nicht die 1-Pixel-Kontrolle über die  Sprites  haben  was  die
horiziontale Positionierung angeht, müssen wir nicht 160 addieren, sondern
160/2, wenn wir die Mitte anpeilen wollen:


HSTART:
	dc.b $40+(160/2)	; Positionierung in der Mitte des Screen
	...


Hier  ein  Schema  des  Screens,  in  dem  der  sichtbare  Teil,  also das
Videofenster, hell dargestellt ist, und des  gesamten  Schirms,  außerhalb
des  Randes,  der  bei 0,0 beginnt, mit ###. Beachtet daß das Videofenster
bei $40 XX und $2c YY beginnt.

      (0,0) __
		      \
		       \
				+---------------------------+
				|###########################|
		/\		|###########################|
		||		|###+-------------------+###|
		||		|###| $40,$2c			|###|  __ Rand des sichtbaren
		||		|###|	 ______			|###| /   Teil (Videofenster)
		||		|###|	/Sprite\		|###|/
		||		|###|	|++XX++|		|###/
		||		|###|	\/\/\/\/		|##/|
				|###|					|#/#|
      Y-Achse	|###| 					|/##|
				|###|					|###|
		||		|###|					|###|
		||		|###|					|###|
		||		|###|					|###|
		||		|###|					|###|
		||		|###+-------------------+###|
		\/		|###########################|
				|###########################|
				+--------------------------+
					 <----- Y-Achse ----->


Die horizontale Position des Sprites kann von 0 bis 447 gehen, es ist aber
logisch, daß sie bei einem Screen zu 320 Pixel Breite von 64 bis 383 geht.
Die vertikale hingegen kann von  0  bis  262  gehen,  aber  um  auf  einem
PAL-Screen  sichtbar  zu  sein  (256 Zeilen), muß sie von 44 ($2c) bis zum
Ende des Screens reichen, also bis 44+256=300 (12c). Bis jetzt  haben  wir
nur  die  Zone bis $FF erreicht, wir werden später sehen, wie wir bis $12c
kommen.

In Listing7b.s wird ein Sprite am Bildschirm rauf und runter  gejagt,  das
geschieht mit ADD´s und SUB´s auf die zwei Kontrollword.

In  Listing7c.s  wird der Sprite horizontal bewegt, indem er die Werte aus
einer vordefinierten Tabelle liest anstatt  ADD  und  SUB  anzuwenden.  In
Listing7d.s  wird  er  in  Vertikal  zum Springen gebracht. In Listing7e.s
werden die zwei Koordinaten (XX und YY) von  zwei  verschiedenen  Tabellen
kontrolliert,  um eine Kreisbewegung, Ellipse, etc. zu erzeugen. In diesem
Beispiel wird auch erklärt, wie man sich eigene Tabellen erstellt!

Bevor ihr weitermacht, ladet die Beispiele in  einen  anderen  Buffer  und
führt sie aus, VERSTEHT sie und lest die Kommentare.

Bis  jetzt  haben  wir  nur einen Sprite angezeigt, sehen wir nun, was wir
wissen müssen, um alle 8 auf den Monitor zu bringen.
Zum Anfang mal festgehalten: jeder Sprite hat eine individuelle  Position,
er  ist  in  keiner  Weise  an  die anderen gebunden, da jeder ein eigenes
VSTART, VSTOP und HSTART in seinen zwei  AnfangsWord  hat.  Was  aber  die
Farben  angeht  (und  andere  Eigenschaften, wie etwa Kollisionen, die wir
später sehen werden), da sind die Sprites nicht ganz unabhängig, sie  sind
zu  Zweierpaaren  zusammengehängt.  Es  gibt  also  4 Paare von 2 Sprites:
Sprite0+Sprite1,  Sprite2+Sprite3,  Sprite4+Sprite5,   und   schlußendlich
Sprite6+Sprite7.  Wenn  ich  von  nun  an von "Spritepaar" sprechen werde,
meine ich nicht ein x-beliebiges Paar, aber genau eines von diesen vieren.
Bei  den Farben hängen sie zusammen, d.h. jeweils ein Paar hat die gleiche
Palette, die Paare untereinander können  verschiedene  Farben  haben.  Wir
wissen,  daß  die  3 Farben des Sprite0 mit den Registern COLOR17, COLOR18
und COLOR19 definiert werden. Diese 3 Farben gelten also auch  für  seinen
"Bruder", dem Sprite1.
Jedes Paar hat eine andere Palette, da  es  insgesamt  16  Register  dafür
gibt,  vom  16  bis  zum  31.  Wenn wir davon ausgehen, daß jeder Sprite 4
Farben hat ( 1 davon Transparent), dann bräuchten wir 8*4=32 Register. Wir
haben aber nur 16. Da wir nun aber 8 Sprites mit 4 Farben haben, hier eine
Tabelle, die angibt, welcher Sprite welche Farbe bekommt:

			Sprite     Binärwert	Farbregister:
			------  --------------  ------------------
Paar 1:		0 o 1	  	00			Nicht verwendet da  Transparent
						01			Color17 - $dff1a2
						10			Color18 - $dff1a4
						11			Color19 - $dff1a6

Paar 2:		2 o 3	 	00			Nicht verwendet da  Transparent
						01			Color21 - $dff1aa
						10			Color22 - $dff1ac
						11			Color23 - $dff1ae

Paar 3:		4 o 5		00			Nicht verwendet da  Transparent
						01			Color25 - $dff1b2
						10			Color26 - $dff1b4
						11			Color27 - $dff1b6

Paar 4:		6 o 7		00			Nicht verwendet da  Transparent
						01			Color29 - $dff1ba
						10			Color30 - $dff1bc
						11			Color31 - $dff1be

Machen wir ein praktisches Beispiel: um in der Copperlist die Farben der 8
Sprites zu definieren ist folgendes notwendig:


	dc.w	$1A2,$F00	; color17, - COLOR1 der sprite0/1 -ROT
	dc.w	$1A4,$0F0	; color18, - COLOR2 der sprite0/1 -GRÜN
	dc.w	$1A6,$FF0	; color19, - COLOR3 der sprite0/1 -GELB

	dc.w	$1AA,$FFF	; color21, - COLOR1 der sprite2/3 -WIEß
	dc.w	$1AC,$0BD	; color22, - COLOR2 der sprite2/3 -WASSER
	dc.w	$1AE,$D50	; color23, - COLOR3 der Sprite2/3 -ORANGE

	dc.w	$1B2,$00F	; color25, - COLOR1 der Sprite4/5 -BLAU
	dc.w	$1B4,$F0F	; color26, - COLOR2 der Sprite4/5 -VIOLETT
	dc.w	$1B6,$BBB	; color27, - COLOR3 der Sprite4/5 -GRAU

	dc.w	$1BA,$8E0	; color29, - COLOR1 der Sprite6/7 -HELLGRÜN
	dc.w	$1BC,$a70	; color30, - COLOR2 der Sprite6/7 -BRAUN
	dc.w	$1BE,$d00	; color31, - COLOR3 der Sprite6/7 -DUNKELROT

BEMERKUNG: Wenn ihr als Hintergrund ein Bild in 2,4,8 oder 16 Farben habt,
dann  gibt´s  keine Probleme, aber wenn ihr einen Bildschirm in 32 Farben,
also 5 Bitplanes, aktiviert, dann müßt ihr bedenken, daß  die  letzten  16
Farben  von Bild und Sprites geteilt werden. Die Farbe muß also für´s Bild
stimmen, genauso wie für die Sprites, die Farben müssen "Multifunktionell"
sein.

DIE VIDEOPRIORITÄT ZWISCHEN DEN SPRITES

Wenn zwei oder mehr Sprites am Bildschirm angezeigt werden, dann  kann  es
leicht  vorkommen, daß sie sich überlappen. In diesem Fall wird der Sprite
mit der niedrigeren Priorität überdeckt. Die Prioritäten  sind  immer  die
gleichen,  der Sprite mit der kleineren Nummer hat Vorrang gegenüber einem
mit Höhere. Daraus folgt, daß  Sprite0  alle  anderen  Sprites  überdecken
kann,  und  Sprite7  von  allen  anderen  überdeckt  werden kann. Hier ein
kleines Schema:
								     _______
								    |	    |
								 ___|___7   |
							    |	    |___|
							 ___|___6   |
							|	    |___|
						 ___|___5   |
						|       |___|
					 ___|___4   |
					|	    |___|
		         ___|___3   |
		        |       |___|
		     ___|___2   |
		    |	    |___|
		 ___|___1   |
		|		|___|
		|   0   |
		|_______|

Überprüft das, indem ihr Listing7f.s in einen  anderen  Buffer  ladet  und
ausführt.  Er  zeigt  8  Sprites  an,  und  nach  dem  Druck auf die linke
Maustaste werden sie übereinandergelegt, um die Prioritäten hervorzuheben.
Rechte Taste um auszusteigen.

"ATTACHED"-SPRITES

Es  existiert  auch  eine  Methode,  um  die   Sprites   in   Zweierpaaren
zusammenzuschweißen,  einen  über  dem  anderen.  Damit  halbiert sich die
Anzahl der verfügbaren Sprites, aber es sind als Trost 16  Farben  möglich
(na ja, 15 + Transparent). Sie können folgendermaßen kombiniert werden:

	SPRITE0+SPRITE1	- Sprite ATTACCHED Nummer 1
	SPRITE2+SPRITE3	- Sprite ATTACCHED Nummer 2
	SPRITE4+SPRITE5	- Sprite ATTACCHED Nummer 3
	SPRITE6+SPRITE7	- Sprite ATTACCHED Nummer 4

In  der  Praxis  werden  die  selben Sprites verbündet, die im Normalmodus
schon eine Verbindung eingegangen sind, die der selben Palette.  Die  vier
"Attached"-Sprites  besitzen  alle  die gleiche Palette, da ja nur mehr 16
Farben übrig sind, von COLOR16 bis COLOR31.
Die  ATTACHED-Sprites  funktionieren   auf   folgende   Art   und   Weise:
normalerweise hat ein Sprite maximal 4 Überlappungsmöglichkeiten, also %00
für die Transparenz, %01, %10, %11 für die drei Farben. Im  Attached-Modus
werden  die  Planes  des  Sprite  übereinandergelegt  und ergeben somit 16
mögliche Situationen, denn 2 Planes vom ersten Sprite plus 2 Planes vom  2
Sprite   ergeben  4  Planes,  oder  %0000  bis  %1111,  also  16  statt  4
Möglichkeiten.  In  der  folgenden  Tabelle  werden   die   16   möglichen
Überlappungsmuster aufgelistet, daneben die dazugehörige Farbe.

		Sprite  Binär   Nummer des
		Farbe	wert	Farbregisters
		-------	------	--------------
		0		0000	Color16 - NICHT VERWENDET, TRANSPARENT
		1		0001	Color17 - $dff1a2
		2		0010	Color18 - $dff1a4
		3		0011	Color19 - $dff1a6
		4		0100	Color20 - $dff1a8
		5		0101	Color21 - $dff1aa
		6		0110	Color22 - $dff1ac
		7		0111	Color23 - $dff1ae
		8		1000	Color24 - $dff1b0
		9		1001	Color25 - $dff1b2
		10		1010	Color26 - $dff1b4
		11		1011	Color27 - $dff1b6
		12		1100	Color28 - $dff1b8
		13		1101	Color29 - $dff1ba
		14		1110	Color30 - $dff1bc
		15		1111	Color31 - $dff1be

In der COPPERLIST müssen sie also so definiert werden:

	dc.w	$1A2,$F00	; color17, FARBE  1 für die Attached-Sprites
	dc.w	$1A4,$0F0	; color18, FARBE  2 für die Attached-Sprites
	dc.w	$1A6,$FF0	; color19, FARBE  3 für die Attached-Sprites
	dc.w	$1A8,$FF0	; color20, FARBE  4 für die Attached-Sprites
	dc.w	$1AA,$FFF	; color21, FARBE  5 für die Attached-Sprites
	dc.w	$1AC,$0BD	; color22, FARBE  6 für die Attached-Sprites
	dc.w	$1AE,$D50	; color23, FARBE  7 für die Attached-Sprites
	dc.w	$1B0,$D50	; color24, FARBE  7 für die Attached-Sprites
	dc.w	$1B2,$00F	; color25, FARBE  9 für die Attached-Sprites
	dc.w	$1B4,$F0F	; color26, FARBE 10 für die Attached-Sprites
	dc.w	$1B6,$BBB	; color27, FARBE 11 für die Attached-Sprites
	dc.w	$1B8,$BBB	; color28, FARBE 12 für die Attached-Sprites
	dc.w	$1BA,$8E0	; color29, FARBE 13 für die Attached-Sprites
	dc.w	$1BC,$a70	; color30, FARBE 14 für die Attached-Sprites
	dc.w	$1BE,$d00	; color31, FARBE 15 für die Attached-Sprites

Um zwei Sprites zu vermählen muß nur das Bit 7  des  zweiten  Kontrollword
des  ungeraden  Sprite  im  Paar  auf  1  gesetzt  werden  (also  Bit 7 im
berühmt-berüchtigten vierten Byte  der  Spezialfunktionen).  Um  z.B.  die
Sprites 0 und 1 zusammenzuschließen, einfach dieses Bit im Sprite1 setzen,
um Sprite 4 und 5 zu koppeln Bit 7 im Byte 4 des Sprite  5.  Es  ist  wohl
einleuchtend, daß die Sprites die gleichen Koordinaten haben müssen, damit
die vier Planes genau übereinanderliegen, sonst wird wohl  kein  richtiges
Überlagerungsmuster  entstehen!  Machen wir ein Beispiel: um die Sprites 0
und 1 zusammenzubringen, müssen wir das Bit 7 des vierten Words im Sprite1
auf High (1) setzen:


SPRITE0:
VSTART0:		; Anfangsposition VERTIKAL
	dc.b $50
HSTART0:		; Anfangsposition HORIZONTAL
	dc.b $90
VSTOP0:
	dc.b	$64	; Endposition VERTIKAL
	dc.b	$00	; Bei geraden Sprites muß Bit 7 nicht gesetzt werden.
; ab hier beginnen die Daten für die zwei Planes des Sprite
	dc.w	%0000000000000000,%0000110000110000
	dc.w	%0000000000000000,%0000011001100000
	...
	dc.w	0,0	; Ende Sprite0


SPRITE1:
VSTART1:			; Anfangsposition VERTIKAL
	dc.b $50
HSTART:				; Anfangsposition HORIZONTAL
	dc.b $90
VSTOP:
	dc.b	$64		; Endposition Vertikal

			;76543210
	dc.b	%10000000	; BIT 7 GESETZT! ATTACCHED MODE 
					; für Sprite 0/1

; ab hier beginnen die Daten für die 2 Planes des Sprite
	dc.w	%0000000000000000,%0000110000110000
	dc.w	%0000000000000000,%0000011001100000
	...
	dc.w	0,0		; Ende Sprite1


Um also die Sprites "Attached" zu gestalten, einfach  das  siebte  Bit  im
vierten Byte der ungeraden Sprites auf 1 setzen, also in den sprites 1,3,5
und 7.

Um sich einen Sprite in 16 Farben zu schaffen muß man ihn zuerst mit einem
Malprogramm  zeichnen  und dann mit dem IFF-Konverter KefCon konvertieren,
denn es wäre recht schwierig, so über dem Daumen  gepeilt  die  16  Farben
richtig zu kalkulieren, da es 4 Planes sind, die zusammen 16 Möglichkeiten
ergeben!

Ladet und führt dann Listing7g.s aus. Es zeigt einen Sprite in  16  Farben
an,  im  Attached-Modus.  Darin ist auch beschrieben, wie man einen Sprite
mit dem KefCon herstell, sei er nun zu 4 oder 16 Farben.

Es ist möglich, gleichzeitig Sprites in 4 und in 16  Farben  darzustellen.
Z.B. könnten Sprite 0 und 1 Attached sein und die anderen nicht, oder jede
beliebige Kombination.

Im Beispiellisting Listing7h.s werden 4 Attached-Sprites angezeigt,  jeder
von ihnen in einer unabhängigen Bewegung.

Hier  angekommen werdet ihr euch sicher fragen, wieso immer noch nicht das
Problem der zwei Pixel pro Schritt nicht eliminiert wurde, und  wir  immer
noch  nicht Pixel für Pixel uber den Schirm gleiten können. Gut, es ist an
der Zeit, das in den Griff zu bekommen. Aber dazu müssen wir  vorher  noch
einen  neuen Befehl des 68000 lernen, welcher auf den einzelnen Bits einer
Zahl operiert: --- LSR ---
Dieses Kürzel steht für "LOGIC SHIFT RIGHT", oder  "LOGISCHER  SCROLL  DER
BITS  NACH  RECHTS".  Anders ausgedrückt, wenn eine Binärzahl in d0 %00111
ist, dann wird sie nach einem LSR #1,d0 folgendermaßen  aussehen:  %00011,
nach einem LSR #2,d0 so: %00001.
Auf die gleiche Art wird ein %00110010 nach einem LSR #1,d0 zu  %00011001,
und  nahc  einem  LSR#5,d0  wäre nur mehr ein %00000001 erhalten. Die Zahl
wird also binär betrachtet, es ist so, als wären sie auf einem  Tischtuch,
an  dem  wir ziehen: wenn wir um #1 ziehen, dann bewegen wir das Tischtuch
mitsamt seinen BitTellern darauf, und das erste in der Reihe wird zu Boden
fallen...  Wenn  man  zuviel  zieht,  dann  kommen alle BitTeller über den
Tischrand und man hat den Tisch abgeräumt (auf NULL gesetzt). Aber was hat
dieser Befehl mit dem Byte HSTART zu tun ???
Das Probelm ist folgendes: wie ihr wißt, gibt es weitaus mehr  horizontale
Positionen  als  nur $FF (255), man denke nur daran, daß ein LowRes-Screen
320 Pixel breit ist. Wenn wir eine Zahl erreichen wollen, die über dem 255
ist  (8  Bit,  vom  0 bis zum 7) dann müssen wir ein Bit mehr zu Verfügung
haben: somit kommen wir  nicht  mehr  nur  bis  maximal  %11111111  ($ff),
sondern  bis  %111111111, oder 511. Das wäre ja super für das HSTART! Aber
wohin geben wir dieses zusätzliche Bit?? Die  Scherzkekse  von  Ingeneuren
haben  gedacht, es wäre im famosen vierten KontrollByte gut aufgehoben, in
dem wir auch die Sprites zusammenpappen. Nun gut, das siebte Bit  ist  für
den  Attached-Modus  reserviert,  dann haben wir ja noch die sechs unteren
frei. Also nehmen wir Bit 0 für diese Aufgabe, und machen dieses  Bit  zum
NIEDERWERTIGSTEN  Bit  der horizontalen Koordinate, oder anders, zum Bit 9
der Koordinate. Damit wird das Kontrollbyte wie folgt aufgeteilt:

		;876543210	; Zahl mit 9 bit, für die HSTART - Koordinate
		%111111111
		 \_____/ \/
			|	  |
      8 hochwert. |
      Bits im	  |
      Byte HSTART |
				  |
				  |
				  |
				  |
				  |
				Bit 0 der
				Zahl zu 9 Bit,
				steht im Bit 0
				des vierten
				Kontrollbyte

Wenn ihr das niederwertige Bit einer 9 Bit  breiten  Zahl  entfernt,  dann
werdet ihr immer eine gerade Zahl erhalten, da dieses Bit immer auf 0 ist.
Denn eine Zahl ist immer dann ungerade, wenn dieses lezte Bit auf 1 steht,
testet  mal  mit  "?100"  und  "?101".  Ihr werdet feststellen, daß gerade
Zahlen immer eine NULL hinten stehen haben, ungerade eine Eins. Bis  jetzt
konntne  wir  also in Schritten zu zwei Pixel scrollen, und wir mußten aus
diesem Grund auch immer  nur  die  Hälfte  des  Effektivwertes  in  HSTART
einsetzen.  Um  auch  die ungeraden Adressen zu erreichen und um die reale
Adresse als Input zu geben müssen wir die Koordinate in niederwertiges Bit
und  hochwertiges Byte aufteilen. Danach dieses Bit in die richtige Stelle
und das Byte hineinschreiben. Um dies zu tun, stellt euch  vor,  ihr  habt
die ungerade Adresse 35: (%00100011). Als erstes müssen wir kontrollieren,
ob das Bit 0 des vierten Kontrollbytes  gesetzt  werden  muß  oder  nicht.
Dafür  müssen  wir  nur mit einem BTST kontrollieren, ab unsere Koordinate
das Bit 0 auf 1 hat oder nicht, und dann dementsprechend reagieren: nehmen
wir an, wir haben die Koordinate in d0:

	btst	#0,D0			; niederwertiges Bit der X-Koordinate =0?
	beq.s	BitNiederNULL
	bset	#0,MeinSprite+3	; Setzen das niederw. Bit von HSTART
	bra.s	PlaceCoords

BitNiederNull:
	bclr	#0,MeinSprite+3	; Löschen das niederw. Bit von HSTART
PlaceCoords:
	....

Nun haben wir das niederwertige Bit von HSTART  gesetzt  (oder  gelöscht),
nun kommt der Rest der Zahl an die Reihe, die höherwertigen 8 Bit. Aber es
gibt ein Problem: die Zahl hat 9 Bit, und wir brauchen  nur  8!  Und  hier
kommt  die Anweisung LSR ins Spiel!!! Denn sie läßt die Bits der Zahl alle
um eins nach rechts rutschen, somit verschwindet das 9. Bit und wir  haben
die  anderen  8 schon an der richtigen Stelle. Schauen wir uns an, wie die
Routine PlaceCoords weitergeht:

	lsr.w	#1,D0		; SHIFTEN 1 Bit nach rechts, oder "verschieben"
						; den Wert von HSTART, um ihn in den in das
						; Byte von HSTART geben zu können, ohne dem
						; niederwertigen, 9. Bit.
	move.b  D0,HSTART	; Setzen diesen Wert XX ins Byte HSTART
	rts

In diesem Fall hatten wir die Koordinate %00100011 (35), so sieht sie nach
dem  LSR #1,d0 aus: %00010001!!!! Das Byte ist so, wie es in HSTART kommen
muß.

In Listing7i.s wird diese Routine angewandt, um endlich einen Sprite schön
flüssig und  gleichmäßig  über  den Bildschirm zu schicken, wie es nur der
Amiga kann.

Jetzt ist es an der Zeit, auch noch das letzte Limit zu  eliminieren,  das
in  vertikaler  Richtung:  in  dieser  Richtung  konnten wir zwar schon in
Einerschritten gehen, aber nur bis Zeile $FF.  Um  dieses  zu  beseitigen,
haben  die  Erfinder  des  Amiga  bei  VSTART/VSTOP  eine  andere  Technik
angewandt, als bei HSTART: eigentlich braucht auch VSTART/VSTOP eine  Zahl
mit  neun  Bit,  aber  anstatt  das  niederwertigste  haben  sie  hier das
hochwertigste "herausgeführt". Somit ist in VSTART/VSTOP jede Zahl bis $FF
gültig, also bis 256, danach muß das neunte Bit gesetzt werden, um darüber
hinaus zu  kommen,  und  wo  wird  das  wohl  liegen?  Genau,  im  vierten
Kontrollbyte.  Nach  $FF  kommt  $100,  $101 usw., der Zählvorgang beginnt
wieder von vorne, nur mit dem neunten Bit auf High. Sehen wir nun, wie wir
eine  Routine  machen können, die im Grunde genommen gleich ist wie die im
horizontalen Sinn, die also mit der realen Koordinate startet (es ist  ein
Word  notwendig)  und sie dann in hochwertiges Bit und niederwertiges Byte
zerteilt. Achtung, hier haben wir auch  VSTOP  zu  modifizieren,  nur  mit
VSTART  ist  nix  getan!! Ach ja, habe fast vergessen: das hochwertige Bit
von VSTOP ist in Bit 1 des vierten Kontrollbytes zu finden, VSTART in  Bit 2:

	MOVE.w	(A0),d0		; kopiert das Word aus der Tabelle in d0
	ADD.W	#$2c,d0		; addiert den Offset vom Anfang des Screens
	MOVE.b	d0,VSTART	; kopiert das Byte in VSTART
	btst.l	#8,d0		; Zahl größer als $FF?
	beq.s	NichtVSTARTSET
	bset.b	#2,MeinSprite+3	; Setzt das Bit 8 von VSTART (Zahl > $FF)
	bra.s	ToVSTOP
NichtVSTARTSET:
	bclr.b	#2,MeinSprite+3	; Löscht das Bit 8 von VSTART (Zahl < $FF)
ToVSTOP:
	ADD.w	#13,D0		; Addiere die Länge des Sprite um die
						; Endposition festzulegen (VSTOP)
	move.b	d0,VSTOP	; Setze den richtigen Wert in VSTOP
	btst.l	#8,d0
	beq.s	NichtVSTOPSET
	bset.b	#1,MeinSprite+3 ; Setzt das Bit 8 von VSTOP (Zahl > $FF)
	bra.w	VstopFIN
NichtVSTOPSET:
	bclr.b	#1,MeinSprite+3 ; Löscht das Bit 8 von VSTOP (Zahl < $FF)
VstopFIN:
	rts

Diese Routine funktioniert auf die gleiche Weise wie  die  vorherige,  was
das  Setzen des "zusätzlichen" Bits angeht, unterscheidet sich aber darin,
daß sie auf VSTART wie auf VSTOP zugreifen muß, und daß das LSR fehlt (ist
hier überflüssig).

Ihr könnt sie testen, ladet dazu Listing7l.s.

Da  wir  nun  die volständige Kontrolle über die Sprites haben, werden wir
deren Kontrollroutinen etwas optimisieren:  als  erstes  werden  wir  eine
universelle  Kontrollroutine  für Sprites erstellen, so, daß wir nicht für
jeden der 8 Sprites  jedesmal  alles  neuschreiben  müssen.  Es  ist  eine
Routine  mit  Parametern  notwendig,  die  als  Eingang  die  Adresse  des
gewünschten Sprites und dessen X-Y-Koordinaten erhält. Damit brauchen  wir
für  jeden  Sprite nur mehr ein "BSR ROUTINE" machen, und nicht mehr alles
neuschreiben. Wir können dann diese Routine jedesmal  recyclen,  wenn  wir
Sprites  bewegen  wollen,  eventuell  nur kleine Änderungen anbringen. Ein
Beispiel  einer  solchen   Routine   findet   ihr   in   Listing7m.s   Die
Universalroutine heißt UniBewSprite, und damit sie funktioniert müssen wir
ihr, außer  der  Adresse  des  zu  bewegenden  Sprites  und  dessen  neuen
Koordinaten,  auch  die  Höhe des Sprites übermitteln. Damit errechnet die
Routine den Wert für VSTOP.
Diese Werte werden ihr mittels  einiger  Register  übermittelt:  Werte  in
Register  schreiben, Routine aufrufen, fertig. Um genau zu sein, kommt die
Adresse des Sprite in a1, seine Höhe ins Register d2, die Y-Koordinate  in
d0 und die X-Koordinate in d1. Die der Routine "übermittelten" Koordinaten
sind die Werte für einen Screen  in  320x256.  Die  Routine  kümmert  sich
selbst  um  das  "zentrieren"  des  Sprites  am Monitor, indem sie $40 zur
X-Koordinate und $2c zur Y-Koordinate dazuzählt. Weiters kümmert sie  sich
darum,  das  niederwertige  Bit  von  HSTART  und  das hochwertige Bit von
VSTART/VSTOP zu setzen.

Kurzum:

;
;	Eingangsparameter von UniBewSprite:
;
;	a1 = Adresse des Sprite
;	d0 = Vertikale Y-Position des Sprites auf dem Screen (0-255)
;	d1 = Horizontale X-Position des Sprites auf dem Screen (0-320)
;	d2 = Höhe des Sprite

Da  wir  nun diese Routine haben, die sich ein für alle Mal aller Probleme
annimmt, können wir uns daran machen,  sie  für  einige  Applikationen  zu
verwenden,  die  uns  mit  den  Sprites  vertrauter  macht. Bevor ihr aber
weitermacht,  ladet  Listing7m.s  und  wehe  dem,  wer   in   LEKTION7.TXT
weiterliest  oder  andere  Listings  ladet,  bevor er es nicht VOLLSTÄNDIG
verstanden hat. Da die Routine in  allen  folgenden  Beispielen  auftreten
wird,  wäre  es  sehr unwirtschaftlich, weiterzumachen, bevor eine Routine
verstanden wurde, die wir dauernd antreffen werden.

In Listing7n.s sehen wir einen Sprite auf dem Bildschirm, der  geradlinige
"Schußlinien" einschlägt. Die Koordinaten stammen nicht aus einer Tabelle,
sondern werden nach und nach berechnet. Dadurch bewegt sich der Sprite mit
einer  konstanten  Geschwindigkeit.  Ladet es und führt es aus, wir werden
sehen, wie man einen Sprite an den Ecken des Bildschirmes abprallen lassen
kann.

In  Listing7o.s  sehen  wir  hingegen  zwei  Sprites,  die  beide  von der
Universalroutine bewegt werden. Es ist ein ausgezeichnetes  Beispiel,  wie
unsere  Routine  verschieden Sprites, auch verschiedener Größe, problemlos
bewegen kann. Wenn wir keine Parameter verwenden würden, dann  müßten  wir
für   jeden   Sprite   alles   neu   schreiben,  eine  unnütze  Zeit-  und
Speichervergeudung.

In  Listing7p.s sehen wir, immer mit der Universalroutine, wie wir Objekte
kreiren  können,  die  größer  sind  als  16  Pixel,  indem  wir   Sprites
zusammenflicken. Achtung! Das ist was anderes als die "ATTACHED"- Sprites!
Bei denen werden zwei Sprites  genau  übereinandergelegt,  sie  haben  die
exakt  gleichen  Koordinaten,  und  das  Bit "attach" ist in den ungeraden
Sprites gesetzt. Bei "aneinandergereihten"  Sprites  hingegen  ahndelt  es
sich  um  einen  "Zusammenschluß"  von  zwei  oder  mehreren  Sprites, die
nebeneinander  oder  untereinander  auf  den  Screen  gezeichnet   werden.
Zusammen ergeben sie dann ein Gesamtbild. Sie müssen genau mit den Rändern
aneinandergereiht werden, wenn wir nicht wollen, daß es aussieht, daß  sie
"zerfallen".  Es  muß  kein spezielles Bit gesetzt werden, es handelt sich
nur um normale Sprites,  die  nebeneinander  aufgestellt  sind.  Hier  ein
Beispiel mit einem Raumschiff, das aus zwei Sprites besteht:
	
     (128,65)		     (128,65)	    (144,65)
	 |_ _ _ __ _ _ _	|_ _ _ _ _ _ __	|__ _ _ _ _ _ _
	 |     /  \		|	|			 /  |  \	       |
	    __/____\__				    /	    \
	 | |	      |	|	|		   /    |    \	       |
	   |	      |			  ____/__________ \____
	 | |__________| |	|    |	        |		   |   |
	      \	   /		     |		 			   |
	 |_ _ _\__/_ _ _|	|    |	        |		   |   |
							 |					   |
						|    |__________|__________|   |
								 \			  /
						|		  \     |    /		   |
								   \	    /
						|_ _ _ _ _ _\__ |__/_ _ _ _ _ _|

						   Sprite 0		Sprite 1

Mit dieser Technik lassen sich Ende-Level-Monster schaffen, die bis zu 128
Pixel  breit sind (16*8), wenn ihr die Sprites zu 3 Farben verwendet, oder
64 Pixel breit (16*4), wenn ihr Attached-Sprites mit 15  Farben  einsetzt.
Wenn  das  Monster  länger als breit ist, z.B. "Humanoid", dann könnt auch
die ganze Länge des Screens verwenden, denn dort gibt´s bekanntlich  keine
Limits. In der vertikalen Richtung können wir dann auch die Farben mit dem
Copper vertauschen, und ihm somit die Schuhe anders färben als die Jeans.


MOUSE UND JOYSTICK

Jetzt haben wir gesehen, wie wir den  Amiga  die  Spites  bewegen  lassen,
wieso  bewegen  nicht  wir sie? Natürlich unter Verwendung einer Maus oder
eines Joysticks. Bevor wir aber lernen, mit  diesen  Apparaten  umzugehen,
müssen  wir  einige  weitere  Befehle lernen, die uns Bitmanipulationen in
Registern erlauben: NOT, AND, OR, EOR.

Diese Befehle operieren auf den einzelnen Bits eines Registers (oder einer
Speicherzelle),  sei es für das Quellregister wir für das Zielregister. So
z.B. behandeln diese Anweisungen ein Byte nicht als eine Zahl, die  aus  8
Bit  besteht, sondern wie 8 Bits, die unabhängig voneinander in der Gegend
rumstehen. Das bedeutet, daß die Auswirkung, die ein Befehl  auf  ein  Bit
hat, unabhängig von den weiteren Bits im Register ist.

Als  erstes  sehen  wir  uns  das  NOT  an.  Es funktioniert nur auf einen
Operanden, dessen Effekt ist das vertauschen der  Bits  des  Operanden.  1
wird durch 0 ersetzt, und 0 durch 1. Wenn wir z.B. im Register d0 die Zahl
%01001100 haben, dann wird ein

	NOT.B	d0

folgendes Resultat bringen: %10110011.

Die 3 weiteren Instruktionen hingegen  arbeiten  mit  2  Operanden,  einem
Quelloperand  und einem Zieloperand. Sie führen die Operation zwischen den
beiden Operanden aus und schreiben das Ergebnis in  den  Zieloperand.  Die
Operationen   (die   sich   von   Befehl  zu  Befehl  unterscheiden)  sind
Bit-für-Bit, d.h., sie werden  zwischen  einem  Bit  im  QuellOP  und  dem
entsprechenden  ZielOP  durchgeführt.  Ein D0 AND D1 entspricht in etwa so
was:

(Bit 0 von D0) AND (Bit 0 von D1)
(Bit 1 von D0) AND (Bit 1 von D1)
(Bit 2 von D0) AND (Bit 2 von D1) und so weiter für alle Bit in D0 und D1

Schauen  wir, was das AND auf sich hat. Wir untersuchen seine Arbeitsweise
auf zwei einzelnen Bits. Da ein Bit entweder 0 oder 1  ist,  ergeben  sich
daraus 4 Fälle:

 0 AND 0 = 0
 0 AND 1 = 0
 1 AND 0 = 0
 1 AND 1 = 1

AND gibt als Resultat dann und nur dann 1, wenn das Bit des ersten UND des
zweiten  Operanden  1  ist. In allen anderen Fällen werden wir 0 erhalten.
Dreimal dürft ihr raten, was AND auf deutsch heißt: UND.  Man  könnte  die
Funktionsweise  auch so übersetzen: "SIND DAS ERSTE UND DAS ZWEITE BIT AUF
1? WENN JA, ANTWORTE MIT 1, ANSONSTEN MIT 0". Ein AND kann nützlich  sein,
um gewisse Bits in einer Zahl auf NULL zu setzen:

 AND.W #%1111111111111011,LABEL

Es wird das Bit 2 der Zahl in LABEL löschen, da es das  einzige  auf  NULL
gesetzte  Bit  im  Operand  ist,  und  somit das einzige sein wird, das im
Zieloperand geändert wird. Denn die anderen sind auf 1, und  werden  somit
nichts  am  Resultat ändern: Wenn das Zielbit 0 war, dann wird ein 0 AND 1
nichts ändern, es ergibt immer 0. Genauso wird eine 1 nichts ändern: 1 AND
1  =  1.  Dort,  wo  aber  0 steht, wird immer auf 0 gesetzt, egal, ob das
Zielbit 1 oder 0 war. Einige Beispiele:

   1111001111 AND 0011001100 = 0011001100 - Keine Änderung
   1101011011 AND 0001110001 = 0001010001 - 1 Bit gelöscht(auf 0 gesetzt)
   1111101101 AND 0011111111 = 0011101101 - 2 Bit gelöscht

Diese Operation des Löschens heißt MASKIERUNG:

 AND #%11110000,LABEL	(%11110000 ist die MASKE, denn es ist so, als
			würde man eine Schablone aus NULLEN über die Zahl
			in Label geben. In diesem Fall werden die ersten
			vier Bits rechts "verhüllt" wie bei einem Mädchen,
			das ein Muttermal mit Schminke "verhüllt". Dieses
			Mal ist wie eine 1, die vom Nuller wie von der
			Schminke überdeckt wird, also gelöscht wird.

Das OR hingegen verhält sich so:

 0 OR 0 = 0
 0 OR 1 = 1
 1 OR 0 = 1
 1 OR 1 = 1

In  diesem  Fall  reicht  es,  daß  eines  der zwei Bits auf 1 ist, um als
Resultat eine 1 zu geben. Das Resultat ist also immer 1, außer wenn  beide
Bits  auf  0 sind. Auch hier kann es helfen zu wissen, daß die Übersetzung
von OR aus dem englischen "ODER"  heißt.  "ENTWERDER  DAS  EINE  ODER  DAS
ANDERE  BIT  MUß  1 SEIN, UM ALS RESULTAT EINE 1 ZU LIEFERN. ANSONSTEN 0".
Dieses ist nützlich, im Gegensatz zum AND, um einige Bits in einem Byte zu
SETZEN, sie also auf 1 (High) setzen. Einige Beispiele:

	0000000001 OR 1101011101 = 1101010001 - Keine Änderung
	1000000000 OR 0010011000 = 1010011000 - 1 Bit gesetzt
	0001111000 OR 1111100000 = 1111111000 - 2 Bit gesetzt

In  diesem Fall ist es so, als würde sich das Mädchen von vorhin statt der
rosa Pinselei (den Nullen) über den schwarzen  Malen  (den  Einsen)  jetzt
einen schwarzen Punkt setzen, um ein falsches Mal zu bekommen, wie es z.B.
Marilyn Monroe über der Lippe hatte. Oder  als  würde  sich  ein  farbiges
Mädchen  (vollstandig  auf  1)  rosa  schminken,  um  weiß auszusehen (wie
Michael Jackson), also vollständig auf NULL zu sein,  und  nur  dort  eine
Stelle  freizulassen, wo die Zahl im OR auf 1 ist, und die schwarze Stelle
hervortreten lassen.

Das EOR, oder Exklusives OR, setzt nur dann auf 1, wenn entweder das erste
oder  das  zweite  Bit auf 1 sind, niemals aber wenn es beide sind, wie es
beim OR der Fall ist:

 0 EOR 0 = 0
 0 EOR 1 = 1
 1 EOR 0 = 1
 1 EOR 1 = 0	 ; Hier ist der Unterschied zum OR: denn 1 OR 1 = 1!

Einige Beispiele:

	0000000001 EOR 1101011101 = 1101010000 - 1 Bit gelöscht
	1000000000 EOR 0010011000 = 1010011000 - 1 Bit gesetzt

Dieser  letzte  Befehl  wird  uns  guten  Dienst  beim Lesen des Joysticks
erweisen. Wie ihr wißt besitzt der Amiga 2 Ports, an denen  Joystick  oder
Mouse  angeschlossen  werden  können.  An jeden der zwei können unabhängig
entweder  Mouse  oder  Joystick  angeschlossen  werden.  Für  jeden   Port
existiert  ein  Hardwareregister,  das gelesen werden kann, um den Zustand
der Mouse/Joystick zu erfähren. Port 0 (an  dem  normalerweise  die  Mouse
hängt)  wird  durch  Register JOY0DAT ausgelesen ($dff00a), Port 1 mittels
JOY1DAT ($dff00c). Als erstes sehen wir, wie wir  den  Joystick  abfragen.
Wir  beziehen  uns dabei auf das Register JOY1DAT, denn daran ist meistens
der Joystick angeschlossen. Es funktioniert  auf  JOY0DAT  auf  genau  die
gleiche Weise.
Wir können uns  einen  Joystick  wie  einen  Apparat  mit  vier  Schaltern
vorstellen  (einen  pro  Richtung), von denen jeder zwei Zustände annehmen
kann: geschlossen (1) oder offen (0),  jenachdem,  ob  der  Hebel  in  die
jeweilige  Richtung  gedrückt wird oder nicht. Um also zu wissen, wohin er
zeigt, müssen wir den Zustand  der  Schalter  abfragen.  Für  zwei  dieser
Schalter  ist die Abfrage sehr simpel, es wird einfach ein Bit im Register
JOY1DAT gesetzt:

- Das Bit 1 von JOY1DAT ist der Status des Schalters "Rechts"
- Das Bit 9 von JOY1DAT ist der Status des Schalters "Links"

Wenn das Bit auf 1 ist, dann ist  der  betroffenen  Schalter  geschlossen,
ansonsten ist er offen. Was die beiden anderen Richtungen angeht, sie sind
nicht direkt als einzelnes Bit eingetragen. Um sie zu erfahren, müssen wir
eine kleine Rechenoperation mit einem EOR durchführen:

-  Der Status des Schalters "Oben" ist das Resultat aus einem EOR zwischen
dem Bit 8 und Bit 9 des Registers

- Der Status des Schalters "Unten" ist das Resultat aus einem EOR zwischen
dem Bit 0 und Bit 1 des Registers.

Auch hier gilt, daß ein Bit 1 bedeutet, daß der Schalter geschlossen  ist,
ein  Bit  auf  0  daß  er  offen  ist. Da wir nun den Status des Joysticks
abfragen können, können wir auch Sprites auf dem Bildschirm bewegen.
Ladet Listing7q.s in einen anderen Textbuffer und führt es aus.

Nun kommen wir zur Maus.
Wenn wir an einen der zwei Ports eine  Maus  anschließen,  dann  verhalten
sich die Register anders als bei einem Joystick. Wenn wir nun das Register
JOY1DAT ansehen (genauso auch das Register JOY0DAT...), dann bemerken wir,
daß  das  hochwertige Byte dazu verwendet wird, um vertikale Bewegungen zu
registrieren, und das niederwertige Byte für horizontale Bewegungen. Jedes
Byte  stellt  eine Zahl dar (von 0 bis 255), die sich je nach Bewegung der
Mouse verändert.

- Das hochwertige Byte verringert die Zahl, wenn die Maus nach oben bewegt
wird und erhöht den Inhalt, wenn die Maus nach unten bewegt wird.

-  Das  niederwertige Byte verringert die dargestellte Zahl, wenn die Maus
nach links bewegt wird, und erhöht sie, wenn sie nach rechts bewegt wird.

Nun schauen wir, wie wir diese Informationen so ausnutzen können, um einen
Sprite  zu  bewegen.  Die  erste Methode, die einen in den Sinn kommt, ist
jene, einfach die Werte der zwei Bytes JOYxDAT  als  Koordinaten  für  den
Sprite  zu  verwenden.  Es  ist  eigentlich  sehr praktisch, denn auch die
Koordinaten der Sprites verringern sich nach Oben und nach Links hin,  und
erhöhen sich nach Rechts und nach Unten.
Diese  Methode  hat  aber den Nachteil, daß wir mit einem Byte bekanntlich
maximal bis 255 kommen, der Bildschirm aber 320  Pixel  breit  ist.  Ladet
Listing7r1.s und testet diese Methode. Eine ein bißchen komplexere Methode
wird in Listing7r2.s präsentiert. Sie eliminiert das Limit der 255  Pixel.
Die  Beschreibung  der  Methode  befindet sich im Listing selbst. Lest den
angehängten Kommentar.

Da wir nun wissen, wie wir einen Pfeil am Bildschirm bewegen  können,  ist
es nur mehr einfach, ein Intuition-System zu simulieren, man kann also ein
Kontrollpanel mit Knöpfen  und  Schaltern  machen,  die  mit  einem  Pfeil
(Sprite) an-und ausgeschalten werden können, wenn damit über einem solchen
ist. Durch Auslesen der Koordinaten des  Sprites  und  Vergleich  mit  den
Koordinaten  der Button ist das ein Kinderspiel. Versucht es mal selbst.
In fortgeschritteren Lektionen werden wir ein Listing dieser Art sehen.

WIEDERVERWENDUNG DER SPRITES

Die Technik der Wiederverwendung der Sprites erlaubt uns, mehr als  die  8
erlaubten Sprites gleichzeitig am Bildschirm anzuzeigen. Praktisch gesehen
wird ein Sprite dazu verwendet,  verschiedene  Objekte  auf  verschiedenen
Höhen  anzuzeigen. Wenn wir z.B. einen Sprite verwenden, um einen Alien im
oberen  Teil  des  Monitors  anzuzeigen,  dann  können  wir   den   selben
wiederverwenden,  um weiter unten das Raumschiff des Spielers zu zeichnen.
Das einzige Limit bei der Wiederwerwertung eines Sprites liegt darin,  daß
die  beiden  Objekte  auf  verschiedenen Höhen liegen müssen. Es ist nicht
möglich, auf der selben Zeile zwei Objekte anzuzeigen, die mit dem  selben
Sprite   gezeichnet   werden.   Des  Weiteren  muß  die  erste  Zeile  des
nachfolgenden Sprites mindestens eine Zeile Abstand von der letzten  Zeile
des vorigen Sprites haben. Horizontal gibt keine Einschränkungen. Das Bild
ilustriert die Situation vielleicht etwas besser:


	  Ausschnitt des Screens
	 ________________________
	|						 |		  Jedes Bild in diesem Ausschnitt
	|				  _		 |		  des Bildschirmes ist mit dem
	|				_|_|_	 |		  selben Sprite gezeichnet.
	|				\___/ _ _|_ _	  Jedes kann horizontal frei
	|		_ _ _ _ _ _ _ _ _|_ _ <-- positioniert werden, aber es muß
	|	 _/_\_				 |		  mindestens eine Bildschirmzeile
	|	|_____|				 |		  zwischen der letzten Zeile eines
	|	  \_/_ _ _ _ _ _ _ _ |_ _	  Sprites und der ersten Zeile
	|		    _ _ _ _ _ _ _|_ _ <-- des wiederverwendeten liegen.
	|		 /\				 |
	|		 \/				 |		  Die Pfeile zeigen die freie
	|						 |		  Zeilen zwischen den Objekten an.
	|						 |
	|________________________|


Wie schon gesagt, gibt es kein Limit was die horizontale Position  angeht,
weger  die  Anzahl,  wie oft man einen Sprite wiederverwendet. Hauptsache,
man hält sich  an  die  oben  genannte  Regel.  Ein  Sprite  kann  so  oft
wiederverwendet  werden, wie man will. Diese Technik kann bei jedem Sprite
angewandt werden, und unabhängig unter den verschiedenen Sprites: so  kann
Sprite  0,3 und 4 nur einmal verwendet werden, Sprite 1 drei mal, Sprite 2
vier mal, und die Sprites 56 und 7 überhaupt  nicht.  Spielt  alles  keine
Rolle.

Diese  Technik  anzuwenden ist recht einfach, es bedarf nur einer Änderung
in der Struktur des Sprites.

Normalerweise kommen am Ende eines Sprites, nach den Daten, aus  denen  er
besteht,  zwei Words mit Inhalt 0. Sie markieren das Ende der Struktur. Um
ihn wiederzuverwenden setzen wir statt dieser zwei Word eine neue Struktur
ein,  die  ein  weiteres Bild beschreibt, nur weiter unten im Screen. Wenn
man dann noch ein drittes Mal das Spiel wiederholen will, dann  noch  eine
Struktur angehängt, usw., bis dann am Ende die zwei Word mit 0 kommen. Sie
markieren dann das Ende der letzten Wiederverwendung:

					SPRITE-STRUKTUR
			  ___________________________ - -
      |		 |     VSTART_1, HSTART_1    |   |
			 |___________________________|
      |		 |     VSTOP_1 und bits	     |   |
			 |___________________________|
      |				  						 |
			  ___________________________
	  |		 |     plane 1, Zeile 1      |   |
			 |___________________________|
	  |		 |     plane 2, Zeile 1		 |   |
			 |___________________________|	 		Daten der ersten
      |				  						 |- - - Verwendung des
						------						sprite
      |					------				 |
						------
      |		 ___________________________     |
			|  plane 1, letzte Zeile    |
      |		|___________________________|    |
			|  plane 2, letzte Zeile    |
      |		|___________________________|    |
										  - -
			 ___________________________  - -
      |		|    VSTART_2, HSTART_2     |    |		Daten der zweiten
			|___________________________|			Wiederverwendung des Sprite.
      |		|    VSTOP_2 und bit		|    |- - -	Die vertikale Anfangs-
			|___________________________|			position muß mindestens
      |										 |		eine Zeile Abstand von
		     ___________________________			der letzten Zeile der
      |		|							|	 |		vorherigen Verwendung haben.
			|___________________________|
      |		|							|	 |
			|___________________________|
      |										 |
						------
      |					------				 |
						------
      |		 ___________________________	 |
			|							|
      |		|___________________________|	 |
			|							|
     \|/	|___________________________|	 |
										  - -
										  _ _
					_____					 |
					_____					 |- - - Weitere Verwendungen
					_____				  _ _|

			 ___________________________ _  _
			|			0				|	 |		Zwei auf 0 gesetzte
      		|___________________________|	 |_ _ _ Word, sie markieren
			|			0				|	 |		das Ende der letzten
     		|___________________________|_  _|		Wiederverwertung


Zu  bemerken,  daß  die  einzelnen  Wiederverwertungen  des   Sprites   in
Reihenfolge   eingesetzt   werden   müssen,  angefangen  vom  am  höchsten
positionierten Sprite bis hin zum  niedersten  am  Bildschirm.  Somit  muß
jedes VSTART größer sein als das VSTOP des Vorgängers.

Sehen  wir z.B. eine solche Struktur in der Praxis. Hier wird der Sprite 2
mal wiederverwertet.


MEINSPRITE:
VSTART_1:
	dc.b $50				; Position erste Verwendung
HSTART_1:
	dc.b $40+12
VSTOP_1:
	dc.b $58
	dc.b $00
 dc.w   %0000001111000000,%0111110000111110	; "Form"-Daten der ersten
 dc.w   %0000111111110000,%1111001110001111	; Verwendung
 dc.w   %0011111111111100,%1100010001000011
 dc.w   %0111111111111110,%1000010001000001
 dc.w   %0111111111111110,%1000010001000001
 dc.w   %0011111111111100,%1100010001000011
 dc.w   %0000111111110000,%1111001110001111
 dc.w   %0000001111000000,%0111110000111110
VSTART_2:					; Position zweite Verwendung
	dc.b $70				; BEMERKT, daß VSTART_2 > VSTOP_1
HSTART_2:
	dc.b $40+20
VSTOP_2:
	dc.b $78
	dc.b $00
 dc.w   %0000001111000000,%0111110000111110	; "Form"-Daten der zweiten
 dc.w   %0000111111110000,%1111001110001111	; Verwendung
 dc.w   %0011111111111100,%1100010001000011
 dc.w   %0111111111111110,%1000001110000001
 dc.w   %0111111111111110,%1000010001000001
 dc.w   %0011111111111100,%1100010001000011
 dc.w   %0000111111110000,%1111001110001111
 dc.w   %0000001111000000,%0111110000111110
 dc.w   0,0					; Ende der letzten Verwendung


Die  Technik  der  Wiederverwendung,  wenn  richtig  angewandt,  kann  zur
Vervielfachung  der bewegten Objekte in einem Shoot´em´up führen. In einem
Spiel, in dem sich die Feinde z.B. horizontal bewegen:


						/--___
						\--
	
							/--___
							\--
	
								/--___
	   ()-						\--
	   /\___o - - - - - -
	  ||||--o - - - - - -			/--___
	  ||||							\--
	  //\\
	 //  \\
------------------------------------------------------------

Da  dieses  feindliche Geschwader aus Objekten besteht, die eines über dem
anderen stehen, die sich nie überkreuzen,  haben  wir  noch  ganze  sieben
Sprites für Player 1 und eventuelle Bomben zur Verfügung.

Ein  Beispiel  davon  bekommt  ihr  in  Listing7s.s,  wo  wir "16" Sprites
gleichzeitig anzeigen. Ladet und studiert es euch.

In unserem Kurs konnte dann  auch  einer  der  klassischen  Effekte  nicht
fehlen,  der  vor  einigen  Jahren  sehr in Mode war: das "Starfield", die
Sterne, die sich horizontal bewegen.
Diese Sterne werden durch recycelte Sprites dargestellt. Wir stellen  euch
mit  Listing7t1.s, Listing7t2.s und Listing7t3.s drei Versionen davon vor.
Die Wiederverwendung  von  Sprites  kann  auch  auf  "Attached"  angewandt
werden,  genauso  wie  auf "normalen". In Listing7t4.s sehen wir zirca das
gleiche wie in den Starfields, nur  mit  farbigen  Bällen  an  Stelle  der
Sterne.

	-		-		-		-

DAS DUAL PLAYFIELD MODE

Bevor wir weitere Charakteristiken der Sprites aufzählen machen  wir  kurz
einen  Abstecher  und vertiefen das Kapitel des Dual Playfields. Wir haben
schon in Lektion 4 angedeutet, daß es sich dabei um einen Spezialmodus  in
der  Grafik  handelt,  der  es  uns  erlaubt,  zwei  Screens  übereinander
anzuzeigen.  Sie  heißen  jeweils  PLAYFIELD1  und  PLAYFIELD2.  Aber  was
bedeutet,  daß  zwei  Screens "übereinander" liegen? Praktisch gesehen hat
jedes Playfield eine "durchsichtige" Farbe,  durch  die  wir  durchschauen
können,  was  drunter  vor  sich  geht.  Es ist mit dem COLOR0 der Sprites
durchaus vergleichbar. Eigentlich ist das "durchsichtige" gar keine Farbe,
es  ist  eher wie ein "Loch" im Playfield zu verstehen. Die anderen Farben
des Playfields  hingegen  verhalten  sich  normal.  Eines  der  Playfields
erscheint  über  dem  anderen  (ist  nur auszuwählen, welches), und dessen
NICHT durchsichtigen Farben überdecken das darunterliegende Playfield. Das
Durchsichtige  hingegen  verhält sich wie gesagt wie ein Loch und läßt das
drunterliegende durchscheinen.
Die maximale Anzahl von Bitplanes, die ein Playfield haben kann, ist  drei
in  Lowres und 2 in Highres. Praktisch werden die 6 Bitplanes des Amiga in
zwei Gruppen zu 3 aufgeteilt, jede dieser Gruppen ist ein  Playfield.  Das
Playfield  1 besteht aus den ungeraden Bitplanes, also aus den Planes 1, 3
und 5, das Playfield 2 aus den geraden, also 2, 4 und 6.
Natürlich ist es nicht immer notwendig, alle Bitplanes zu  verwenden.  Wir
können  unabhängig voneinander den zwei Playfields die Bitplanes zuteilen,
die wir wollen. Die Anzahl der zu verwendenden Bitplanes geben wir auf die
gleiche  Art  und Weise an, wie bei den "normalen" Grafikmodi. In die Bits
14-12 des BPLCON0 ($dff100), BPU2, BPU1 und BPU0 genannt, kommt die Anzahl
der insgesamt verwendeten Bitplanes für die Playfields. Je nachdem, welche
Zahl wir hier eintragen, teilt die Hardware die  Bitplanes  folgendermaßen
auf:


Anzahl der verwendeten BPL. |   Bitplanes für	  |	Bitplanes für
 (bit BPU di BPLCON0)	    |   Playfield 1		  |	Playfield 2
----------------------------|---------------------|-------------------
							|					  |
	0						|	keines			  |	keines
							|					  |
	1						|	Plane 1			  |	keines
							|					  |
	2						|	Plane 1			  |	Plane 2
							|					  |
	3						|	Plane 1,3		  |	Plane 2
							|					  |
	4						|	Plane 1,3		  |	Plane 2,4
							|					  |
	5						|	Plane 1,3,5		  |	Plane 2,4
							|					  |
	6						|	Plane 1,3,5		  |	Plane 2,4,6

Wie ihr seht, hat Playfield 1 immer gleichviel oder mehr  Planes  als  das
Field  2,  und Playfield 2 maximal eines weniger als Field 1. Es ist nicht
möglich,  3  Planes  dem  Playfield1  und  ein  einziges  dem   Playfield2
zuzuordnen.

Analog  wie  bei  den  Standart-Grafikmodi  bestimmt  die Überlagerung der
Bitplane  die  Farbe  eines  jeden  Pixel.  Die  Übereinstimmung  zwischen
Bitplane-Kombination  und  Farbregistern  ist  aber etwas verschieden, die
Tabelle gibt genaueren Aufschluß darüber:

PLAYFIELD 1
    Wert	|   Wert	|   Wert	|  ausgewählte
	Plane 5 |	Plane 3 |	Plane 1 |  Farbe
----------------------------------------------------
			|			|			|
	0		|	0		|	0		|  durchsichtig
			|			|			|
	0		|	0		|	1		|  COLOR01
			|			|			|
	0		|	1		|	0		|  COLOR02
			|			|			|
	0		|	1		|	1		|  COLOR03
			|			|			|
	1		|	0		|	0		|  COLOR04
			|			|			|
	1		|	0		|	1		|  COLOR05
			|			|			|
	1		|	1		|	0		|  COLOR06
			|			|			|
	1		|	1		|	1		|  COLOR07


PLAYFIELD 2
    Wert	|   Wert	|   Wert	|  ausgewählte
	Plane 6 |	Plane 4 |	Plane 2 |  Farbe
----------------------------------------------------
			|			|			|
	0		|	0		|	0		|  durchsichtig
			|			|			|
	0		|	0		|	1		|  COLOR09
			|			|			|
	0		|	1		|	0		|  COLOR10
			|			|			|
	0		|	1		|	1		|  COLOR11
			|			|			|
	1		|	0		|	0		|  COLOR12
			|			|			|
	1		|	0		|	1		|  COLOR13
			|			|			|
	1		|	1		|	0		|  COLOR14
			|			|			|
	1		|	1		|	1		|  COLOR15

Nun wißt ihr, wie das Dual Playfield Mode funktioniert. Nur etwas wißt ihr
noch nicht... wie man dieses aktiviert!!
Ganz einfach, Bit 10 im Register BPLCON0  auf  1  setzen.  Wie  wir  schon
gesagt  haben,  ist  es  möglich,  auszuwählen, welches Playfield über dem
anderen erscheinen soll. Man sagt,  daß  ein  Playfield,  das  über  einem
anderen  erscheint,  höhere  Priorität  hat.  Es  gibt  ein Bit, das diese
Priorität bestimmt, es ist das Bit 6 des Registers BPLCON2 ($dff104): wenn
es auf 0 ist, dann erscheint Playfield 1 über dem 2, ansonsten Playfield 2
über dem ersten.

Ein Beispiel dafür gibt es in Listing7u.s


PRIOTITÄT ZWISCHEN SPRITES UND PLAYFIELDS

Wir  haben  schon   die   Priorität   zwischen   den   einzelnen   Sprites
kennengelernt.  Wenn  sich zwei Sprites also überlappen, dann wird der mit
der kleineren Zahl über dem anderen erscheinen.  Des  weiteren  haben  wir
gerade  gesehen,  wie  man  die Priorität der Playfields im Dual Playfield
Mode untereinander  bestimmt.  Nun  bleibt  uns  nur  noch  die  Priorität
zwischen Playfield und Sprites zu besprechen. Als erstes vermerke ich, daß
die Sprites immer über der Farbe 0 erscheinen. Für die anderen Farben wird
die  Priorität  im  Register  BPLCON2  kontrolliert. Es ist möglich, diese
unabhängig für die geraden und ungeraden Planes  zu  setzen.  Das  ist  im
Dual-Playfield-Modus  sehr  nützlich,  da  es  uns damit ermöglicht, jedem
Playfield eine verschiedene Priorität gegenüber den Sprites zu  geben.  Im
Standartmodus  hingegen  ist  es  vorteilhafter, den geraden und ungeraden
Planes die gleiche Priorität gegenüber den Sprites zu geben. Das  Register
BPLCON2  enthält einige Bits, in denen der Prioritätslevel der geraden und
ungeraden Planes gesetzt werden kann. Die Bits 0 bis  zwei  enthalten  den
Prioritätslevel   für   die  ungeraden  Bitplanes  (Playfield  1  im  Dual
Playfieldmode), die Bits 3 bis  5  hingegen  den  Level  für  die  geraden
Bitplanes (Playfield2). Und so werden die Prioritäten verteilt:
Wir beziehen uns dabei auf ein beliebiges Playfield, da sie  untereinander
gleich  funktionieren.  Was  die  Priorität  Sprites-Playfield  angeht, da
werden die Sprites als Paare betrachtet (0-1,2-3,4-5  und  6-7).  Wie  wir
wissen,  ist  die Priorität unter den Sprites (und deswegen auch unter den
Paaren) fix:


MAXIMALE PRIORITÄT	PAAR 1 (SPRITES 0 UND 1)
			PAAR 2 (SPRITES 2 UND 3)
			PAAR 3 (SPRITES 4 UND 5)
MINIMALE PRIORITÄT	PAAR 4 (SPRITES 6 UND 7)

Wir können nun unseren Prioritätslevel für die Playfields innerhalb diesen
Grenzen  einfügen:  entweder  über  der  maximalen  Priorität der Sprites,
unterhalb der minimalen oder zwischen zwei Paaren. Es ist somit aber nicht
möglich, ein Playfield unter dem Paar 4 und über dem Paar 2 anzuzeigen, da
das zweite Paar über dem vierten ist. Das Gegenteil ist aber möglich. Hier
eine  Tabelle  mit  allen  Möglichkeiten, die uns in der Prioritätsvergabe
gebotren sind: (Durch die Einstellungen in BPLCON2 )

CODE	  |  000      |	 001	  |  010      |	 011	  |  100      |
----------------------------------------------------------------------------
PRI. MAX  | PLAYFIELD | PAAR 1	  | PAAR 1    | PAAR 1	  | PAAR 1    |
		  | PAAR 1    | PLAYFIELD | PAAR 2    | PAAR 2	  | PAAR 2    |
		  | PAAR 2    | PAAR 2	  | PLAYFIELD | PAAR 3	  | PAAR 3    |
		  | PAAR 3    | PAAR 3	  | PAAR 3    | PLAYFIELD | PAAR 4    |
PRI. MIN  | PAAR 4    | PAAR 4	  | PAAR 4    | PAAR 4	  | PLAYFIELD |

Wie aus der Tabelle ersichtlich, wenn wir z.B. die  Sprites  0,1,2  und  3
(also  Paar  1  und  2)  übder  dem  Playfield  anzeigen  wollen,  und die
restlichen Paare unterhalb, dann werden  wir  in  BPLCON2  den  Code  %010
setzen.  Dieser  Code kommt dann im BPLCON2 entweder in die Bits 0-2, wenn
wir uns auf das Playfield1 im Dual-Playfield-Mode beziehen,  oder  in  die
Bits  3  bis 5 für Playfield2. Wenn wir einen "normalen" Screen verwenden,
ohne Dual Playfield, dann müssen wir diesen Code zweimal schreiben, einmal
in Bit 0-2 und einmal in 3-5.

In  Listing7v1.s  sehen  wir,  wie  wir  die Priorität in einem "normalen"
Screen setzen.

In Listing7v2.s hingegen wird ein Dual Playfield verwendet.


KOLLISIONEN

Die Hardware des Amiga stellt dem Programmierer ein System zur  Verfügung,
das  es  erlaubt,  Kollisionen (Zusammenstöße) zwischen Sprite und Sprite,
Sprite und Playfield  und  zwei  Playfields  zu  registrieren.  All  diese
Kollisionstypen werden mit nur zwei Registern verwaltet: CLXDAT ($dff00e),
das ein Nur-Lese-Register ist, in dem die Kollisionen signalisiert werden,
und  CLXCON  ($dff098),  das ein Kontrollregister ist, mit dem die Art der
Registrierung der Kollisionen verändert werden kann. Beginnen  wir  damit,
die Struktur dieser Register zu beschreiben.
Die Bit von CLXDAR verhalten sich  wie  Kollisionsmelder.  Jedes  Bit  ist
einer  ganz  bestimmten  Kollision  zugeteilt.  Wenn  sich nun eine solche
bestimmte Kollision zuträgt, dann nimmt dieses jeweilige Bit  den  Wert  1
an.  Wenn  die Kollision nicht mehr besteht, dann springt es auf 0 zurück.
In der folgenden Tabelle werden die einzelnen Bit von CLXDAT genauer unter
die Lupe genommen:

VERWENDUNG DER BIT VON CLXDAT

Bit 15  nicht verwendet
Bit 14  Kollision zwischen PAAR 3 und PAAR 4
Bit 13  Kollision zwischen PAAR 2 und PAAR 4
Bit 12  Kollision zwischen PAAR 2 und PAAR 3
Bit 11  Kollision zwischen PAAR 1 und PAAR 4
Bit 10  Kollision zwischen PAAR 1 und PAAR 3
Bit 9   Kollision zwischen PAAR 1 und PAAR 2
Bit 8   Kollision zwischen Playfield 2 und PAAR 4
Bit 7   Kollision zwischen Playfield 2 und PAAR 3
Bit 6   Kollision zwischen Playfield 2 und PAAR 2
Bit 5   Kollision zwischen Playfield 2 und PAAR 1
Bit 4   Kollision zwischen Playfield 1 und PAAR 4
Bit 3   Kollision zwischen Playfield 1 und PAAR 3
Bit 2   Kollision zwischen Playfield 1 und PAAR 2
Bit 1   Kollision zwischen Playfield 1 und PAAR 1
Bit 0   Kollision zwischen Playfield 1 und Playfield 2

Das Register CLXCON hat folgende Struktur:

VERWENDUNG DER BIT VON CLXCON

Bit 15  aktiviert Sprite 7
Bit 14  aktiviert Sprite 5
Bit 13  aktiviert Sprite 3
Bit 12  aktiviert Sprite 1
Bit 11  aktiviert Bit-plane 6
Bit 10  aktiviert Bit-plane 5
Bit 9   aktiviert Bit-plane 4
Bit 8   aktiviert Bit-plane 3
Bit 7   aktiviert Bit-plane 2
Bit 6   aktiviert Bit-plane 1
Bit 5   Kollisionswert Bit-plane 6
Bit 4   Kollisionswert Bit-plane 5
Bit 3   Kollisionswert Bit-plane 4
Bit 2   Kollisionswert Bit-plane 3
Bit 1   Kollisionswert Bit-plane 2
Bit 0   Kollisionswert Bit-plane 1

(Bemerkung: wo "aktiviert" steht ist gemeint, daß  die  REGISTRIERUNG  DER
KOLLISIONEN  aktiviert  wurde:  wenn z.B. das Bit 15 von CLXCON den Wert 0
hat, dann heißt es nicht, daß Sprite  7  nicht  am  Bildschirm  erscheinen
kann,  sondern  nur,  daß  die Kollisionen, die mit Sprite 7 zu tun haben,
nicht registriert, vermerkt werden)


Wir werden die Bedeutung dieser Bits nach und nach erklären. Beginnen  wir
mit  den  Kollisionen  zwischen  Sprite und Sprite. Sofort vorweggenommen,
auch bei den Sprite-kollisionen werden die Sprites in Paaren behandelt. Es
ist  nur  möglich,  einen  Zusammenstoß zwischen Sprites aus verschiedenen
Paaren zu registrieren, und nicht zwischen zwei aus dem  selben  Paar.  Es
ist  z.B.  unmöglich,  eine Kollision zwischen Sprite 0 und 1 zu erkennen.
Wenn die Sprites aber verschiedenen Paaren  angehören,  dann  ändert  sich
alles:  bei einem Überlappen der Sprites 0 und 2 wird Bit 9 von CLXDAT auf
High (1) gesetzt (Kollision zwischen Paar 1 und 2). Auch  wenn  sich  eine
Kollision  zwischen Sprite 1 und 2 ereignet, wird Bit 9 auf 1 springen, da
Sprite 1 ja auch zum selben Paar wie Sprite 0 gehört, dem Paar 1. Das  muß
aber nicht immer so sein.
Denn die Zusammenstöße zwischen Sprites mit geradem Index (Sprite 0,2,4,6)
werden  immer  registriert,  bei  ungeraden  Sprites  hingegen  können wir
entscheiden ob ja oder nein. Um auch die ungeraden zu signalisieren müssen
wir das dementsprechende Bit in CLXCON aktivieren. Ihr könnt in der obigen
Tabelle sehen, welche es sind. Die  ungeraden  Sprites  können  unabhängig
voneinander  aktiviert werden. Einen oder mehrere ungerade Sprites einzeln
aktivieren zu können bringt Vor- und Nachteile mit  sich.  Betrachten  wir
z.B. nur das Paar 1 und 2 und nehmen wir an, wir haben weder Sprite 1 noch
Sprite 3 aktiviert. Wenn sich nun eine Kollision zwischen Sprite 0  und  2
ergibt,  wird  Bit  9  in  CLXDAT  auf  1 gehen. Wenn diese Kollision aber
zwischen Sprite 1 und 2, zwischen 0 und 3 oder zwischen 1 und 3  ereignet,
dann  passiert  nichts,  und  wir  können  nicht  sagen, ob eine Kollision
stattgefunden hat.
Nehmen wir hingegen an, einen der ungeraden Sprites  aktiviert  zu  haben,
den Sprite 1 zum Beispiel. In diesem Fall ergeben die Kollisionen zwischen
Sprite 0 und 2 und zwischen 1 und 2 einen High-Pegel im Bit 9 von  CLXDAT.
Eine  Kollision  zwischen  Sprite  0  und  3  oder  2  und 3 bleibt weiter
ergebnislos. In diesem Fall ergibt sich ein Nachteil gegenüber der vorigen
Situation,  in  der  Sprite  1 nicht aktiviert war. Denn wenn vorhin Bit 9
gesetzt war, waren wir sicher, daß es einen Zusammenstoß zwischen Sprite 0
und  2  gegeben  hat. Im derzeitigen Fall hingegen kann es der 0 und der 2
oder der 1 und der 2 sein. Es gibt keine  Möglichkeit,  das  Rätsel  durch
lesen  des  Registers  CLXDAT  zu  lüften.  Wenn Sprite 1 deaktiviert ist,
Sprite 3 aber aktiviert, dann haben wir eine analoge Situation zur  gerade
besprochenen,  nur  anstatt  auf  Sprite  1  bezieht  sich  das  Bit 9 nun
zusätzlich auf das Sprite 3: Kollisionen zwischen  Sprite  0  und  2  bzw.
zwischen  0  und  3  werden  registriert,  aber  wir  haben  wieder  keine
Möglichkeit, sie zu unterscheiden.
Zum Schluß gibt es noch die letzte Kombination, in  sowohl  Sprite  1  wie
auch Sprite 3 aktiviert sind. Nun werden die Kollisionen 0-2, 0-3, 1-2 und
1-3 signalisiert, und wir haben wieder keine Unterscheidungsmöglichkeit.

Ein Beispiel  von  Spritekollisionen,  mit  den  ungeraden  ausgeschaltet,
gindet	ihr	in	Listing7w1.s.	Ladet	und	verifiziert	die
Funktionstüchtigkeit.

Ein Beispiel zwischen Sprites mit einem  ungeraden,  deaktiviertem  Sprite
gibt´s  in Listing7w2.s. Ihr werdet bemerken, daß das Beispiel, so wie ich
es vorsetze, nicht  funktioniert;  um  es  auszuführen  müßt  ihr  die  im
Kommentar	beschriebenen   Modifizierungen   anbringen.   Um   hier   zu
unterscheiden, ob es sich bei der Kollision um die  mit  dem  aktivierten,
ungeraden  Sprite  oder  dem geraden handelt, wird eine Technik angewandt,
die die Positionen der jeweiligen Sprites vergleicht.

Nun kommen wir  zur  Kollision  zwischen  Sprite  und  Playfield.  Es  ist
möglich,  einen  Zusammenstoß  zwischen  einem  Spritepaar  und einer oder
mehreren Farben des Playfields zu registrieren. Auch hier wird  wieder  in
Paaren  gearbeitet,  und  nicht mit den einzelnen Sprites. Die Aktivierung
der ungeraden Sprites mit den Bits im Register CLXCON hat auch hier  seine
Gültigkeit.
Die Registrierung der Kollisionen läuft aber jeweils anders ab, ob wir wir
nun  einen  normalen  Screen  oder ein Dual-Playfield verwenden. Bei einem
normalen Screen zeigen die Bits von 1  bis  4  von  CLXDAT  die  Kollision
zwischen einem Spritepaar und der Farbe (oder den Farben) an, die wir dazu
ausgewählt haben. Das Bit 1 zeigt die Kollision zwischen dem Playfield und
dem  Paar  1  an,  das Bit 2 zwischen Playfield und Paar 2, Bit 3 zwischen
Playfield und Paar 3 und Bit 4 zwischen Playfield und Paar 4. Die Bit  von
5 bis 8 werden nicht verwendet.
Im Dual-Playfield-Mode ist es möglich, einen Zusammenstoß  zwischen  einem
der  2  Playfields  und einem Spritepaar zu registrieren, und die Bits von
CLXDAT  werden  verwendet,  wie  in  der  Tabelle  des  Registers   CLXDAT
angeführt:  die Bit 1 bis 4 zeigen eine Kollision zwischen Playfield 1 und
einem Spritepaar an, während die Bits von 5 bis 8 für das Playfield 2  und
den  Spritepaaren  verantwortlich sind. Um die Farben auszuwählen, die ein
"Klingeln" in CLXDAT auslösen sollen, brauchen wir  das  Register  CLXCON.
Beginnen wir mit einer einzigen Farbe.
Die Bits von 6 bis 11 von CLXCON  zeigen  an,  welche  Bitplanes  für  die
Kollisionen  aktiviert  sind.  Im Falle, daß wir Kollisionen eines Sprites
mit einer einzigen Farbe registrieren wollen  müssen  wir  alle  Bitplanes
aktivieren,  die  angezeigt werden. Die Wahl der Farbe, die eine Kollision
auslösen soll, wird durch einsetzen der Zahl des Registers in die Bits von
0 bis 5 in CLXCON erziehlt, das die dementsprechende Farbe beinhaltet.
Nehmen wir z.B. an, wir haben einen  normalen  Screen  mit  16  Farben  (4
Bitplanes),   und   wir   dir  Kollisionen  der  ungeraden  Sprites  nicht
berücksichtigen. Wenn wir nun die Kollision zwischen einen Sprite und  der
Farbe 13 registrieren wollen, dann kommt in das Register CLXCON der Wert

		111111
		5432109876543210
 $03cb=%0000001111001101

Schauen wir und die Bedeutung der Bits etwas genauer an. Die  Bit  von  12
bis  15 deaktivieren die ungeraden Sprites. Von den Bits von 6 bis 11 sind
nur Bit 6,7,8 und 9 auf eins. Das deutet an, daß nur die Bitplanes  von  1
bis  vier  aktiviert  sind.  Die  Bits  von  0  bis  5  enthalten die Zahl
%001101=13, also die Farbe 13 ist auserwählt. Im Dual-Playfield-Modus  ist
die  Situation  die  selbe,  nur  werden  dort  alle verwendeten Bitplanes
aktiviert und es werden Kollisionen mit 2 Farben  gleichzeitig  aktiviert:
Wenn  wir  z.B.  zwei  Playfileds  zu  jeweils  8  Farben  haben,  und die
Registrierung der Kollisionen mit Farbe 7 des Playfield 1 und Farbe 2  des
Playfield 2 wollen, dann werden wir in CLXCON folgende Zahl schreiben:

		111111
		5432109876543210
 $0fbb=%0000111111011101

Diese Kombination zeigt an,  daß  alle  Bitplanes  zum  kollisionsanzeigen
aktiviert  sind (alle Bit von 6 bis 11 sind auf 1). Weiters ist die "Zahl"
der Farbe für Playfield 1 aus den Bits 0, 2  und  4  zusammengesetzt,  die
zusammengeschoben  die  Zahl  %111=7  ergeben. Die Bits, die die Farbe für
Playfield 2 ergeben, sind 1,  3  und  5,  die  wiederum  zusammengeschoben
%010=2 ergeben.
Zu Bemerken ist, daß die Kollision  eines  Sprites  mit  einer  Farbe  des
Playfield 1 das Setzen eines anderne Bits in CLXDAT zur Folge hat als eine
eines Sprites mit einer Farbe von Playfield 2. Zum Beispiel, wie  ihr  aus
der  Tabelle  des  Registers  CLXDAT  lesen  könnt,  ergibt eine Kollision
Sprite0Playfield1 Bit 1 in CLXDAT einen High-Zustand auf Bit 1 in  CLXDAT,
eine Kollision Sprite0-Playfield2 hingegen einen High-Zustand auf Bit5 von
CLXDAT. Es ist auch möglich, die Kollision  eines  Sprites  mit  mehr  als
einer  Farbe zu registrieren, auch wenn nur in einigen Sonderfällen. Um zu
verstehen, wie das geht, muß man sich die Binärdarstellung der Zahlen  der
Farbregister vor Augen halten.
Es gibt, wie ihr wißt, 32 Farbregister, die die Numerierung von 0  bis  31
haben.  Die Möglichkeit, Kollisionen mit 2 Farben gleichzeitig erkennen zu
können, beruht darauf, daß die  Darstellung  einiger  Binärzahlen  ähnlich
ist.  Nehmen  wir  zum  Beispiel  die  Zahlen  2 und 21. Binär gesehen ist
2=%00010, 21 hingegen %10101 (wir betrachten  5  Bit,  um  Zahlen  bis  31
schreiben zu können). Wie ihr seht, sind sie total verschieden. Es besteht
also keine Möglichkeit, diese Farben gleichzeitig zu erkennen.
Betrachten wir nun 22 und 23. Wir erkennen, daß sie  in  binärer  Form  so
aussehen:  22=%010110  und 23=%010111. Sie unterscheiden sich nur in einem
Bit, dem niederwertigsten (ganz links). In diesem  Fall  ist  es  möglich,
Kollisionen   mit  beiden  Farben  zu  registrieren.  Denn  der  Wert  des
niederwertigsten Bit (das in diesem Fall die Farben unterscheidet) ist vom
Bitplane1  gegeben.  Wenn  wir  Bitplane  1  NICHT zur Kollisionserkennung
aktivieren, dann werden nur die Werte  der  Bitplanes  2,3,4  und  5  (wir
befinden  uns auf einem Screen zu 32 Farben, also 5 Bitplanes) betrachtet,
und der Wert, der durch Bitplane 1 angenommen wird,  hat  keinen  Einfluß.
Wir werden in CLXCON also folgenden Wert schreiben:

		 111111
		 5432109876543210
CLXCON= %0000011110010110

Das bedeutet, daß die Kollision basierend auf  den  aktivierten  Bitplanes
erkannt  wird  (also  den  Planes  2,3,4 und 5), genauer gesagt wenn unser
Sprite über einem Pixel mit

Bitplane 1=(0 oder 1), weil nicht aktiviert
Bitplane 2=1
Bitplane 3=1
Bitplane 4=0
Bitplane 5=1

steht.
Wie wir  gesehen  haben,  erfüllen  die  Darstellung  von  22=%010110  und
23=%010111  diese  bestimmte Forderung. Es werden also beide Farben in der
Kollisionsregistrierung einbezogen. Beachtet, daß das  Bitplane,  das  wir
NICHT  aktiviert haben (das erste) genau diesem ersten Bit entspricht, das
die Unterscheidung zwischen 22 und 23 ausmacht.

Diese Technik ist auf bei allen Farbpaaren anwendbar, bei denen  sich  die
Binärdarstellung  nur  in einem Bit unterscheiden. So z.B. auch die Zahlen
8=%001000 und 9=%001001, die sich im  niederwerigsten  Bit  unterscheiden.
Also  werden  wir  auch  hier  das Bitplane 1 deaktivieren, wenn wir diese
beiden Farben zur Erkennung verwenden wollen. Wenn wir hingegen die Farben
10=%001010  und  14=%001110  verwenden wollen, dann bemerken wir, daß sich
die beiden Zahlen im Bit 2 (wir notieren die Zahlen von rechts nach links,
bei  0  beginnend)  unterscheiden,  das  dem Bitplane 3 entspricht. Um nun
Kollisionen zwischen einem Sprite und diesen zwei Farben zu  registrieren,
müssen wir das Bitplane 3 deaktivieren, und dem CLXCON also folgenden Wert
zuspielen:

		 111111
		 5432109876543210
CLXCON= %0000011011001010   ; Bit 8=0 Bitplane 3 NICHT aktiviert

Wenn wir 2 Bitplanes ausschalten können wir 4 Farben  in  die  Kollisionen
einbeziehen.  Im Prinzip ist es immer das Gleiche. Nehmen wir zum Beispiel
die Farben:

1=%00001
3=%00011
5=%00101
7=%00111

Sie haben alle die Bit 0, 3 und 4 gleich, unterscheiden sich aber  in  der
Kombination  der  Bits  1  und  2.  Wollen wir nun eine Kollision zwischen
Sprites und diesen vier Farben wahrnehmen, dann werden wir Bitplane 2  und
3 deaktivieren.

Wenn  wir  3  Bitplanes  ausschalten,  können wir 8 Farben erkennen, bei 4
abgeschaltenen Bitplanes 16.

Auch im Dual-Playfield-Mode ist es möglich,  für  jedes  Playfield  einige
Bitplanes  zu  deaktivieren,  um somit die Kollision zwischen einem Sprite
und mehr als einer Farbe eines Playfields zu signalisieren.  Erinnern  wir
uns aber, daß wenn wir die Kollision zwischen einem Sprite und zwei Farben
erkennen müssen, bei der jedoch eine dem Playfield 1 gehört und die andere
dem  Playfield2, es nicht notwendig ist, dieses Spiel zu machen, da wir in
CLXDAT für jedes Playfield ein Bit haben, das  und  erlaubt,  gleichzeitig
eine Kollision mit beiden Playfields zu erkennen.

In  Listing7x1.s  sehen wir ein Beispiel von Kollision zwischen Sprite und
Playfield im "Standard-Modus".

In Listing7x2.s hingegen haben wir ein Beispiel  im  Dual-Playfield-Modus.
In  beiden  Lisitngs  sind im Kommentar Beispiele aufgezeigt, wie man mehr
als eine Farbe für die Kollisionen verwenden kann.

Der letzte Typ von Kollision ist der zwischen Playfield 1 und  Playfield2,
klarerweise  in  Dual-Playfield-Mode. Es ist möglich, Kollisionen zwischen
einer oder mehrerer Farben des Playfield1 und einer oder  mehrerer  Farben
des   Playfield  2  zu  erkennen,  indem  wir  nur  einige  der  Bitplanes
aktivieren, genauso wie wir es mit den Sprite-Playfield-Kollisionen  getan
haben.  Wenn  eine  Kollision  zwischen zwei Playfields stattgefunden hat,
dann wird Bit 0 in CLXDAT auf 1 gesetzt.

Ein Beispiel von dem Typ sehen wir in Listing7x3.s.


DIREKTE VERWENDUNG DER SPRITEREGISTER


Sehen  wir  nun eine andere Methode, mit der wir Sprites verwenden können.
Bis jetzt haben wir die Sprites generiert, indem wir die  Register  SPRxPT
verwendet haben, also Pointer auf unsere Datenstrukturen (Spritestruktur),
die alle  nötigen  Informationen  zum  Erstellen  des  gewünschten  Sprite
enthalten.  Es gibt aber eine alternative Methode, wir werden sie "Direkte
Verwendung der Sprite" nennen. Diese Art ist in den meisten  Fällen  nicht
von Vorteil, aber manchmal kann sie nützlich sein.
Um  zu  verstehen,  um  was  es  hier  geht  müssen  wir  das  Thema   der
Spritedarstellung  etwas  vertiefen.  Wenn  wir in ein SPRxPT-Register die
Adresse  einer  Spritestruktur  schreiben  setzen  wir  eine  automatische
Prozedur in Gang, die es uns erlaubt, diese Sprites effektiv zu sehen. Die
Daten, die Position und Form des Sprites  angeben,  werden  automatisch  -
mittels  eines  Hardwaremechanismus´ Namens DMAin eigene Register gegeben,
anderen als dir SPRxPT. Es ist genau dieses Schreiben der Daten  in  diese
Register,  die  es  ermöglichen,  die  Sprites WIRKLICH zu sehen. Vom DMA,
einem sehr wichtigen Instrument des Amiga, werden wir  in  einer  nächsten
Lektion  sprechen.  Im  Moment reicht uns zu wissen, was für eine Rolle er
bei den Sprites spielt. Er  verhält  sich  ähnlich  wir  ein  Briefträger.
Stellt  euch  vor,  die  Datenstruktur  eures Sprites, die ihr im Speicher
erstellt habt, ist wie ein Haufen Briefe, die  an  verschiedene  Empfänger
(Register)  kommen.  Der  DMA  übernimmt  nun  die  Aufgabe,  diese Briefe
zuzustellen, er sortiert sie  auch.  Die  direkte  Verwendung  der  Sprite
besteht  nun  genau  darin,  die Daten direkt in die richtigen Register zu
schreiben, oder anders ausgedrückt,  indem  wir  die  Briefe  selbst  beim
Empfänger abgeben, und so dem Briefträger DMA die Arbeit wegnehmen. Da der
DMA aber gratis arbeitet, werdet ihr euch nun fragen, für was das gut sein
soll. Wie schon gesagt, normalerweise
bringt es keine Vorteile. Aber manchmal schon.
Schauen wir uns an, wie diese Technik funktioniert. Wie schon gesagt,  die
Daten  werden direkt in einige Register geschrieben. Es gibt vier Register
pro Sprite, SPRxPOS, SPRxCTL, SPRxDATA und SPRxBATB genannt. Statt  dem  x
kommt  wie  immer  die  Nummer  des gewünschen Sprite. Die Adressen dieser
Register hängen vom Sprite ab, auf den wir uns beziehen.  Wir  können  sie
mit  einer  einfachen  Formel berechnen. Mit "x" geben wir eine Nummer des
Sprites an, sie liegt zwischen 0 und 7.


Adresse SPRxPOS  = $dff140+(x*8)
Adresse SPRxCTL  = $dff142+(x*8)
Adresse SPRxDATA = $dff144+(x*8)
Adresse SPRxDATB = $dff146+(x*8)

Ihr könnt sie aber auch mit dem Help des ASMONE ("=C") herausfinden.

Nun beschreiben wir die  Verwendung  dieser  Register.  Die  "Form"  eines
Sprites  kommt in die Register SPRxDATA und SPRxDATB, die die zwei kleinen
"Bitplanes" des Sprites darstellen.  SPRxDATB  ist  das  Plane  2).  Diese
Register haben die gleiche Aufgabe wie die Wordpaare, die eine Zeile eines
Sprites definieren. Bemerkt aber, daß für jeden Sprite  nur  Register  für
EINE  Zeile  zur  Verfügung stehen. Die horizontale Position eines Sprites
ist, wie ihr wißt, aus 9 Bit zusammengesetzt, H0,  H1,...  ,  H8  genannt.
Diese  9  Bit  sind  in  zwei  Register  unterteilt:  das Bit H0, also das
niederwertige, befindet sich im Bit 0 des Registers SPRxCTL. Die anderen 8
hingegen  im  niederwertigen  Byte  des Registers SPRxPOS. Kurzum, was die
horizontale Position angeht, so verhalten die  Register  prakitsch  gleich
wie  die  zwei  Kontrollword in der Spritestruktur. Die vertikale Position
wird mit dieser Technik aber nicht bestimmt, denn  die  Sprites  verhalten
sich recht eigenartig.
Um einen Sprite anzuzeigen muß er vorher aktiviert werden.  Das  passiert,
wenn man in das Register SPRxDATA schreibt.
Einmal aktivert wird der Sprite auf jeder Zeile angezeigt,  immer  in  der
von uns zugeteilten horizontalen Position. Die Form ist immer die gleiche,
also jene, die in SPRxDATA und SPRxDATB steht.
Wenn diese zwei Register also nicht ständig verändert werden, dann hat der
Sprite  in  jeder  Zeile  immer  das  gleiche  Aussehen.  Der  Sprite wird
angezeigt bis  er  nicht  deaktivert  wird,  indem  ins  Register  SPRxCTL
geschrieben wird.
Um einen Sprite anzuzeigen, der in jeder Zeile anders ist, müssen wir also
eine  Copperlist  schreiben, die ungefähr so aussieht: (Wir nehmen an, den
Sprite 0 bei VSTART=$40, VSTOP=$60 und HSTART=$160 anzeigen zu wollen)


	dc.w	$4007,$fffe	; WAIT - Warte auf Zeile VSTART
	dc.w	$140,$0080	; SPR0POS - horizontale Position
	dc.w	$142,$0000	; SPR0CTL
	dc.w	$146,$0e70	; SPR0DATB - Spriteform Zeile 1, Plane 2
	dc.w	$144,$03c0	; SPR0DATA - Spriteform Zeile 1, Plane 1
						; des Weiteren aktiviert es den Sprite,
						; deswegen wird es als letztes geschrieben

	dc.w	$4107,$fffe	; WAIT - Warte auf Zeile VSTART+1
	dc.w	$146,$0a70	; SPR0DATB - Spriteform Zeile 2, Plane 2
	dc.w	$144,$0300	; SPR0DATA - Spriteform Zeile 2, Plane 1

	dc.w	$4107,$fffe	; WAIT - Warte auf Zeile VSTART+2
	dc.w	$146,$0a7f	; SPR0DATB - Spriteform Zeile 3, Plane 2
	dc.w	$144,$030f	; SPR0DATA - Spriteform Zeile 3, Plane 1

; wiederhole für jede Zeile Y
;	dc.w	$40+Y07,$fffe   ; WAIT - Warte auf Zeile VSTART+Y
;	dc.w	$146,DATENY2	; SPR0DATB - Spriteform Zeile Y, Plane 2
;	dc.w	$144,DATENY1	; SPR0DATA - Spriteform Zeile Y, Plane 1
; an Stelle Von DATENY1 und DATENY2 kommen die Formdaten der Sprite.

	dc.w	$6007,$fffe	; WAIT - Warte auf Zeile VSTOP
	dc.w	$142,$0000	; SPR0CTL - deaktiviere Sprite

Wie ihr gesehen  habt,  ist  bei  längeren  Sprite  eine  sehr  lange  und
komplizierte  Copperlist  notwendig. Hier empfielt es sich auf jeden Fall,
den DMA zu verwenden.  Nehmen  wir  aber  an,  wir  möchten  einen  Sprite
anzeigen,  der  in  jeder  Zeile  gleich  ist.  Z.B. eine Säule. In dieser
Situation würde unsere Copperlist kurz und einfach:
(Wir nehmen an, den Sprite 0 bei  VSTART=$40,  VSTOP=$60  und  HSTART=$160
anzeigen zu wollen)


	dc.w	$4007,$fffe	; WAIT - Warte auf Zeile VSTART
	dc.w	$140,$0080	; SPR0POS - horizontale Position
	dc.w	$142,$0000	; SPR0CTL
	dc.w	$146,$0e70	; SPR0DATB - Spriteform Zeile 1, Plane 2
	dc.w	$144,$03c0	; SPR0DATA - Spriteform Zeile 1, Plane 1
						; des Weiteren aktiviert es den Sprite,
						; deswegen wird es als letztes geschrieben

	dc.w	$6007,$fffe	; WAIT - Warte auf Zeile VSTOP
	dc.w	$142,$0000	; SPR0CTL - deaktiviert Sprite

Ihr  bemerkt,  daß unsere Copperlist, außer daß sie kurz ist, mit der Höhe
des Sprite nicht verändert wird.
Wenn wir aber den DMA verwendet hätten, dann  hätten  wir  für  die  ganze
Länge  des  Sprite  die  gleichen Zeilen schreiben müssen. Das hätte unter
anderem auch mehr Speucher gekostet. Denkt zum Beispiel an den Fall,  eine
100  Zeilen  hohe  Säule  anzeigen  zu  müssen. Wenn wir den DMA verwenden
würden, dann sähe es so aus:

Spritestruktur:
		dc.b	VSTART,HSTART,VSTOP,0
		dc.w	$ffff,$0ff0	; Zeile 1
		dc.w	$ffff,$0ff0	; Zeile 2
		dc.w	$ffff,$0ff0	; Zeile 3
		dc.w	$ffff,$0ff0	; Zeile 4
		dc.w	$ffff,$0ff0	; Zeile 5
		dc.w	$ffff,$0ff0	; Zeile 6
		dc.w	$ffff,$0ff0	; Zeile 7
		dc.w	$ffff,$0ff0	; Zeile 8

.... und so weiter bis:

		dc.w	$ffff,$0ff0	; Zeile 99
		dc.w	$ffff,$0ff0	; Zeile 100
		dc.w	0,0			; Ende Sprite


Mit  der  direkten  Verwendung  der  Sprite  hingegen reicht eine einfache
Coperlist:

	dc.b	VSTART,7,$ff,$fe	; WAIT - Warte auf Zeile VSTART
	dc.w	$140
	dc.b	$00,HSTART	; SPR0POS - horizontale Position
	dc.w	$142,$0000	; SPR0CTL
	dc.w	$146,$ffff	; SPR0DATB - Spriteform Zeile 1, Plane 2
	dc.w	$144,$0ff0	; SPR0DATA - Spriteform Zeile 1, Plane 1
						; des Weiteren aktiviert es den Sprite,
						; deswegen wird es als letztes geschrieben

	dc.b	VSTOP,7,$ff,$fe ; Warte auf Zeile VSTOP
	dc.w	$142,$0000	; SPR0CTL - deaktivert Sprite


Ein einfaches Beispiel der direkten Verwendung der Sprites findet  ihr  in
Listing7y1.s.

Im  Programm  Listing7y2.s  hingegen  werden  durch die direkte Verwendung
Balken erzeugt, die gleich denen sind, die mit dem Copper gemacht wurden.

Mit der Technik der direkten Verwendung der Sprites ist es  auch  möglich,
den  selben  Sprite  mehrmals  auf  der  gleichen  Zeile zu verwenden. Die
Methode wird in Listing7y3.s besser erklärt und  angewandt.  Die  Sprites,
die   mehrmals   auf  der  selben  Zeile  angezeigt  werden,  heißen  auch
MULTIPLEXED, also "gemultiplext". Wie wir  also  gesehen  haben,  hat  der
Amiga  zwar  nur  8  Sprites,  aber  der  Assembler erlaubt es und, sie zu
vervielfachen und ihnen auch mehr Farben als standartmäßig  vorgesehen  zu
geben,  indem  wir die Palette mehrmals horizontal ändern. Es ergeben sich
damit zwar ziemlich lange Copperlisten, aber es rentiert sich sicherlich.

Eine  Entwicklung  dieser  Idee  bringt  und  dann  dazu,   einen   Screen
vollständig mit Sprites zu gestalten, ein Beispiel in Listing7y4.s.

Um  so  etwas  zu  gestalten  müssen  extrem  lange Copperlist geschrieben
werden, und um sie verständlicher zu machen werden  SYMBOLE  oder  EQUATES
verwendet,  es  ist eine Direktive des Assembler, die es uns gestattet, zu
einer  bestimmten  Zahl  einen   x-beliebigen   Namen   zuzuteilen.   Beim
Assemblieren  wird der Name dann durch die dementsprechenden Zahl ersetzt.
Machen wir ein Beispiel: wir wollen auf  das  Register  COLOR0  zugreifen,
das,  wie  wir  wissen, die Adresse $dff180 hat. Wir können es entweder so
schreiben:

	move.w	#$123,$dff180

Aber wenn wir möchten, dann auch auf diese Art:

COLOR0	EQU	$dff180	 ; Definition eines Symboles

	move.w	#$123,COLOR0

Wir haben praktisch definiert, daß  wenn  der  ASMONE  das  Symbol  COLOR0
findet,  er  es  mit $dff180 ersetzen soll. Es ist fast wie ein Label, wir
müssen  uns  einen  Namen  erfinden,  ihn  ganz  links   schreiben,   ohne
Leerzeichen,  aber es braucht keinen Doppelpunkt. Im Wahrheit kann man sie
auch setzen, genauso wie die Labels sie haben können oder nicht; es  hängt
vom  Assembler  ab.  EQU  bedeutet  ÄQUIVALENT  ZU.  Die meisten Assembler
akzeptieren auch das = an Stelle der EQU für die  Definition.  Machen  wir
ein weiteres Beispiel:

NUMERLOOP	=	10

	MOVEQ   #NUMERLOOP-1,d0
Loop:
	clr.l   (a0)+
	dbra	d0,NUMERLOOP
	rts

Mit diesem Mini-Listing haben wir 10 Longwords auf 0 gesetzt. Der  Vorteil
der  EQUATES  besteht  darin,  daß  wir  sie alle am Anfang des Programmes
setzen können, und somit einfaches Spiel haben,  wenn  wir  gewisse  Werte
verändern  wollen.  Es ist auch Möglich, mathematische Operationen mit den
Symbolen durchzuführen:


BytesProZeile	=	40
AnzahlZeilen	=	256
BitplanePlatz	=	BytesProZeile*AnzahlZeilen

	...

	section plane,bss_C

Bitplane:
	ds.b	BitplanePlatz

Im  Listing  gilt BitplanePlatz 10240, oder 40*256. In Listing7y4.s werden
Symbole für die Copperlist definiert.

Zum Schluß werden wir noch den Screen mit den Sprites scrollen lassen. Wir
nützen  das aus, um noch zwei weitere Befehle des 68000ers kennenzulernen:
ROR und ROL. Listing7y5.s


ANIMATION DER SPRITES


Wir  beenden  diese  Lektion  mit  der Beschreibung über die Animation der
Sprites. Wir betrachten nun wieder "normale" Sprites, also jene,  die  mit
den SPRxPT und dem DMA erzeugt werden. Um einen Sprite zu animieren müssen
wir ihn jedesmal neuzeichnen, wenn er angezeigt wird. Jede Form,  die  der
Sprite   annimmt,   wird   auch   "Fotogramm   der   Animation"   genannt.
Normalterweise wird eine Animation so gemacht, daß eine  Sequenz  abläuft,
die  immer  wiederholt wird. Denkt z.B. an ein Männchen, das am Bildschirm
läuft; ihr werdet bemerken, daß alle Schritte gleich sind.
Um ein  Männchen  zu  animieren  müssen  wir  eine  bestimmte  Anzahl  von
Fotogrammen  zeichnen,  die  in  Sequenz  (hintereinander)  gesehen  einen
kompletten Schritt ergeben. Wenn das Männchen einen Schritt  gemacht  hat,
beginnt  es  mit  einem neuen: jetzt werden wieder die gleichen Fotogramme
angezeigt wie vorhin. Durch wiederholen dieses Schrittes kann das Männchen
laufen, wie lange wir wollen, wir brauchen aber nur eine limitierte Anzahl
von Bildern (Es ist klar, daß Fotogramme ja im Endeffekt Bilder sind,  und
somit  Speicher  brauchen,  und  wir somit versuchen sollten, so wenig wie
möglich davon zu  brauchen).  Bis  hierher  gilt  des  Gesagte  für  jedes
animierte  Objekt,  es  ist  also  gut,  wenn  ihr es euch merkt, auch für
später, wenn wir Animationen mit dem Blitter erzeugen  werden.  Im  Moment
behandeln  wir  nur  Animationen  mittels  Sprite. Das bedeutet, wir haben
einen Sprite, der sich am Bildschirm  bewegt  und  jedesmal  neugezeichnet
wird,  wenn  er  Form wechselt. Man geht dabei so vor: für jedes Fotogramm
erzeugt  man  einen  Spritestruktur,  und   jedesmal   wenn   der   Sprite
neugezeichnet  wird,  pointen  wir mit dem Register SPRxPT auf ein anderes
Fotogramm (also auf eine andere Datenstruktur). Die Position  des  Sprites
wird  jedesmal in die Struktur des Fotogrammes geschrieben, auf das SPRxPT
dann zeigt.

Ein Beispiel davon gibt´s in Listing7z.s

Dieses Beispiel ist auch das Ende von Lektion7 und  somit  von  DISK1  des
Kurses.

*****************************************************************************

Die  Disketten  2  und  3  (in  Italienisch)  wurden  im Moment der
"Drucklegung"  (November  95)  fertiggestellt.  Sie  behandeln  die
folgenden Argumente:

- BLITTER (Copymode, Linemode und Fill)
- Interrupt, CIAA/CIAB, laden von Disk, Tastatur
- Audio
- Kompatibilität und Optimierung des 68000

Weiters  ist auch Disk 4 fast fertig, sie behandelt das AGA-Chipset
und den 68020.
Es  sind  auch  Lektionen  im  Bereich  3D  und   Demo   Style   in
Vorbereitung,  weiters  auch  die  Programmierung von Videospielen.
Aber wenn mir niemand hilft, werden sie  nie  das  Licht  der  Welt
erblicken.  Wenn  ihr  wollt,  daß  die  Disks  2/3/4  ins Deutsche
mutieren, dann kann  ich  euch  nur  sagen,  daß  desto  mehr  Mark
anschwirren,  desto  schneller sie übersetzt werden, hehehe :) Also
schickt mindestens 10 Märkli entweder  als  Postanweisung  oder  in
einem  verschlossenem  Brief  an  den  vertrauten  Übersetzer,  der
Halbe-Halbe mit dem Autor teilt:

        Martin De Tomaso
        Nicolodistr. 24/3
        39100 BOZEN
        ITALY                   ; internet: mdetomas@inf.unitn.it

Das  bedeutet  aber  nicht,  daß die Disks 2/3 automatisch bei euch
zuhause landen wenn sie fertig sind, es würde  uns  nur  ermutigen,
weiterzumachen.  Wenn  ihr euch registrieren wollt, dann schickt 25
Mark (wie immer mit einer Postanweisung  oder  flüssig),  und  fügt
auch noch folgende Infos hinzu:

Name, Nachname, Adresse, Amiga-Modell, das zuhause am Werk ist

Optional:  Alter, e-mail, Handle (Wenn ihr aus der Demo-Scene kommt).

Wie    schon    erwähnt,    wird    Hilfe    für    die     Kapitel
3D-Effekte/Fraktale/Warp/ Voxel/Zoom/etc, wie auch Games, benötigt.
Es betrifft sowohl Texte  wie  auch  Listings.  Es  braucht  nichts
Wundervolles, es reichen simple Dinge, die einfach zu kapieren sind
und gut kommentiert sein sollten. Egal wenn  sie  langsam  und  nix
Besonders  sind.  Ihr  könnt  sofort  loslegen, Kommentare bitte in
Deutsch oder Englisch!
Ein anderes Motiv, weswegen ihr uns  unserer  Ruhe  berauben  dürft
(nicht  so  ernst  nehmen..!), ist die Fähigkeit, GUT ins Englische
oder sonst irgend eine Sprache übersetzen zu können. In diesem Fall
habt  ihr Anrecht auf einen guten Prozentsatz des Profits (30%-50%,
das handeln wir uns dann aus) des Ertrages der von euch übersetzten
Version.  Unter GUT verstehe ich die Übersetzung des GANZEN Kurses,
auch der LABEL und der dummen Sprüche, und ohne Fehler. Weiter ohne
die  TABS  in  Spaces  zu  verwandeln  und  ohne die 79 Kolonnen zu
überschreiten.

	Fabio Ciucci (Randy/Ram Jam)   &   Martin De Tomaso

Hello's to all the German Amiga Scene groups!!! I hope to see much demos
out from EX-SWAPPERs, EX-GFX ARTISTs, EX-MUSICIANs!!!
Just read this tutorial between one swap and another, or between painting &
composing!!!!

A special hello to the R.O.M. editors (Touchstone, please write an article
about this tutorial!!!!)

