Grafik

Sprites und Shapes auf dem C 128

Grafik und C 128: Das heißt optimales Zusammenspiel von Computer und Anwendung. Wie einfach Shapes und Sprites in der Handhabung sind, werden wir Ihnen auf den nächsten Seiten zeigen.

Airbrush-Grafik mit schwarz-weiß gekacheltem Boden, überlappenden roten Kreisscheiben, einem gelben Dreieck und einem helllila Viereck vor dunklem Hintergrund

Um die Programmierung der Sprites auf dem C 64 zu erklären, ist schon viel Druckerschwärze verbraucht worden. Fast schien es eher die Aufgabe von Assembler-Programmierern zu sein, durch die POKE-Wüsten und Zahlensysteme zu gelangen um schließlich das Ziel - ein bewegtes Sprite auf dem Bildschirm - zu erreichen. Im C 128-Modus erspart uns das Basic 7.0 all diese Strapazen: Sprites zu erstellen und zu verwalten wird zum Vergnügen. Nachfolgend lernen wir die dazu nötigen Befehle bis in ihre Feinheiten kennen. Außerdem wird uns eine neue Gruppe von Grafikobjekten beschäftigen: die Shapes.

Sprites

Sollten Sie Ihnen noch nicht begegnet sein, die kleinen Kobolde (»sprite« ist englisch und heißt auf deutsch »Kobold« oder »Gespenst«), dann seien sie hiermit kurz vorgestellt. Es handelt sich um bewegliche grafische Objekte (daher auch der Ausdruck MOB=movable objects, der manchmal verwendet wird), die sowohl als mehr- als auch als einfarbige (dann hochaufgelöste) Figuren ohne Rücksicht auf den gerade eingeschalteten Grafikmodus munter über Text- und Grafikbildschirm huschen können. Die gesamte Verwaltung der Sprites geschieht durch den VIC-Chip, was ihr Auftreten auf den 40-Zeichen-Bildschirm beschränkt. Bevor Sie die folgenden Beispielprogramme ausprobieren, sollten Sie Listing 1 »Alle Sprites« abgetippt und gestartet haben.

10 rem ***** data-lader fuer alle sprites *****
15 fast
20 gosub100:bsave"sprites1",onb0,p3584top4095
30 gosub100:bsave"sprites2",onb0,p3584top4095
40 gosub100:bsave"scene1",onb0,p3584top4095
50 gosub100:bsave"scene2",onb0,p3584top4095
60 gosub100:bsave"scene3",onb0,p3584top4095
65 slow
70 printchr$(147)"alle sprite-files sind gespeichert"
80 end
100 rem *** daten in sprite-speicher schreiben ***
110 fori=3584to4095:reada:pokei,a:nexti
120 return
63000 rem ******* sprite-daten *********
63010 rem *** datas von file sprites1 ***
63020 data000,000,000,000,000,000,000,170,000,001,254,000,002,001,000,004,000,128,004,204,128,004,000,128,060,048,240,036,000,144,036,132
63021 data144,036,120,144,034,001,016,001,254,000,000,132,000,000,132,000,000,132,000,000,132,000,000,132,000,003,135,000,000,000,000,000
63022 data000,000,000,000,000,000,000,170,000,001,254,000,002,001,000,004,000,128,004,204,128,004,000,128,060,048,224,036,000,160,036,132
63023 data160,036,120,160,034,001,032,001,254,032,000,132,032,000,130,000,000,129,000,000,128,128,000,128,096,003,128,000,000,000,000,000
63024 data000,000,000,000,000,000,000,170,000,001,254,000,002,001,000,004,000,128,132,204,128,132,000,128,252,048,224,004,000,160,004,132
63025 data160,004,120,160,002,001,032,001,254,034,000,132,034,000,067,254,000,064,000,000,064,000,000,064,000,001,192,000,000,000,000,000
63026 data000,000,000,000,000,000,000,170,000,001,254,000,002,001,008,004,000,136,004,204,136,132,000,136,252,048,248,132,000,136,004,132
63027 data136,004,120,142,002,001,000,001,254,000,000,128,000,000,064,000,000,032,000,000,032,000,000,032,000,000,224,000,000,000,000,000
63028 data000,000,000,000,000,192,000,170,096,001,254,048,002,001,024,004,000,140,132,204,139,132,000,136,252,048,248,004,000,128,004,132
63029 data128,004,120,128,002,001,000,001,254,000,000,128,000,000,064,000,000,032,000,000,032,000,000,032,000,000,224,000,000,000,000,000
63030 data000,000,000,000,000,000,255,170,000,161,254,000,162,001,000,036,000,192,036,204,160,036,000,144,060,048,248,004,000,128,004,132
63031 data128,004,120,128,002,001,000,001,254,000,000,128,000,000,064,000,000,032,000,000,032,000,000,032,000,000,224,000,000,000,000,000
63032 data000,000,000,000,000,000,000,170,000,001,254,000,002,001,000,004,000,192,004,204,160,004,000,144,060,048,248,036,000,128,036,132
63033 data128,164,120,128,098,001,000,033,254,000,016,128,000,008,064,000,004,032,000,002,032,000,004,032,000,008,224,000,000,000,000,000
63034 data000,000,000,000,000,000,000,170,000,001,254,000,002,001,000,004,000,128,004,204,128,004,000,128,028,048,224,020,000,160,020,132
63035 data160,020,120,160,018,001,032,017,254,032,016,132,032,031,252,032,000,039,224,000,036,000,000,036,000,000,231,000,000,000,000,000
63039 rem *** datas von file sprites2 ***
63040 data085,085,085,106,170,169,111,255,249,111,255,249,111,255,249,109,085,121,109,170,121,109,190,121,109,190,121,109,190,121,109,190
63041 data121,109,190,121,109,190,121,109,190,121,109,170,121,109,085,121,111,255,249,111,255,249,111,255,249,106,170,169,085,085,085,000
63042 data255,255,255,148,081,069,170,170,139,213,021,085,162,138,041,213,085,081,168,170,169,148,081,069,170,170,163,197,085,085,162,138
63043 data041,149,085,021,138,170,171,148,081,069,170,168,171,209,085,085,162,138,041,213,069,085,170,042,171,148,017,069,255,255,255,000
63044 data000,000,001,000,000,003,000,000,007,000,000,013,000,000,025,000,000,049,000,000,097,000,000,193,000,001,129,000,003,001,000,006
63045 data001,000,012,001,000,024,129,000,048,129,000,096,129,000,192,129,001,128,001,003,000,001,006,000,001,012,000,001,031,255,255,000
63046 data128,000,000,192,000,000,224,000,000,176,000,000,152,000,000,140,000,000,134,000,000,131,000,000,129,128,000,128,192,000,128,096
63047 data000,148,048,000,148,024,000,148,012,000,148,006,000,148,003,000,128,001,128,128,000,192,128,000,096,128,000,048,255,255,248,000
63048 data031,255,255,012,000,001,006,000,001,003,002,161,001,130,161,000,194,161,000,098,161,000,050,161,000,024,001,000,012,001,000,006
63049 data001,000,003,001,000,001,129,000,000,193,000,000,097,000,000,049,000,000,025,000,000,013,000,000,007,000,000,003,000,000,001,000
63050 data255,255,248,128,000,048,128,000,096,168,128,192,168,129,128,165,003,000,165,006,000,162,012,000,128,024,000,128,048,000,128,096
63051 data000,128,192,000,129,128,000,131,000,000,134,000,000,140,000,000,152,000,000,176,000,000,224,000,000,192,000,000,128,000,000,000
63052 data125,245,087,109,181,086,109,182,166,109,182,246,109,182,246,109,182,246,109,182,246,109,182,246,109,182,246,085,181,086,085,181
63053 data086,105,182,170,109,182,255,109,182,255,109,182,255,109,182,255,109,182,255,109,182,255,109,182,255,109,182,255,174,186,255,000
63054 data095,255,214,103,255,102,105,253,166,110,118,182,111,154,246,111,235,246,111,255,246,111,255,246,111,219,250,111,219,255,111,085
63055 data085,111,154,106,111,219,111,111,235,111,111,255,111,111,255,111,111,255,111,111,255,111,111,255,111,111,255,111,111,255,111,000
63059 rem *** datas von file scene1 ***
63060 data170,170,170,170,170,170,170,170,170,170,170,170,165,085,090,165,085,090,165,085,090,165,085,090,165,255,090,165,255,090,165,255
63061 data090,165,255,090,165,255,090,165,255,090,165,255,090,165,085,090,165,085,090,165,085,090,165,085,090,170,170,170,170,170,170,000
63062 data170,170,170,170,170,170,154,170,166,154,170,166,165,085,090,165,085,090,167,085,218,167,085,218,165,255,090,165,255,090,165,235
63063 data090,165,235,090,165,235,090,165,255,090,165,255,090,167,085,218,167,085,218,165,085,090,165,085,090,154,170,166,154,170,166,000
63064 data106,170,169,106,170,169,154,170,166,154,170,166,173,085,122,173,085,122,167,085,218,167,085,218,165,190,090,165,190,090,165,235
63065 data090,165,235,090,165,235,090,165,190,090,165,190,090,167,085,218,167,085,218,173,085,122,173,085,122,154,170,166,090,170,165,000
63066 data106,170,169,106,170,169,154,170,166,149,085,086,173,085,122,173,085,122,167,085,218,167,255,218,165,190,090,165,170,090,165,235
63067 data090,165,195,090,165,235,090,165,170,090,165,190,090,167,255,218,167,085,218,173,085,122,173,085,122,149,085,086,090,170,165,000
63068 data106,170,169,106,170,169,149,085,086,149,085,086,157,085,118,157,085,118,151,255,214,151,255,214,151,170,214,151,170,214,151,130
63069 data214,151,130,214,151,130,214,151,170,214,151,170,214,151,255,214,151,255,214,157,085,118,157,085,118,149,085,086,090,170,165,000
63070 data106,170,169,106,170,169,181,085,094,181,085,094,157,085,118,158,255,182,150,255,150,151,170,214,151,040,214,151,040,214,151,130
63071 data214,151,130,214,151,130,214,151,040,214,151,040,214,151,170,214,150,255,150,158,255,182,157,085,118,181,085,094,090,170,165,000
63072 data106,170,169,085,085,085,181,085,094,181,085,094,159,255,246,158,255,182,150,170,150,151,170,214,151,040,214,151,000,214,151,130
63073 data214,151,130,214,151,130,214,151,040,214,151,040,214,151,170,214,150,255,150,158,255,182,157,085,118,181,085,094,090,170,165,000
63074 data085,085,085,085,085,085,117,085,093,127,255,253,095,255,245,094,170,181,094,170,181,094,000,181,094,000,181,094,020,181,094,020
63075 data181,094,020,181,094,000,181,094,000,181,094,170,181,094,170,181,095,255,245,127,255,253,117,085,093,085,085,085,085,085,085,000
63079 rem *** datas von file scene2 ***
63080 data213,085,087,213,085,087,127,255,253,123,255,237,123,255,237,124,170,061,124,170,061,126,065,189,126,065,189,126,020,189,126,020
63081 data189,126,020,189,126,065,189,126,065,189,124,170,061,124,170,061,123,255,237,123,255,237,127,255,253,213,085,087,213,085,087,000
63082 data213,085,087,239,255,251,111,255,249,123,255,237,120,170,045,124,170,061,124,065,061,126,065,189,126,085,189,126,020,189,126,020
63083 data189,126,020,189,126,085,189,126,065,189,124,065,061,124,170,061,120,170,045,123,255,237,111,255,249,239,255,251,213,085,087,000
63084 data255,255,255,239,255,251,239,255,251,250,170,175,250,170,175,248,000,047,248,000,047,248,085,047,248,085,047,248,125,047,248,125
63085 data047,248,125,047,248,085,047,248,085,047,248,000,047,248,000,047,250,170,175,250,170,175,239,255,251,239,255,251,255,255,255,000
63086 data191,255,254,239,255,251,239,255,251,242,170,143,242,170,143,249,000,111,249,000,111,248,215,047,248,215,047,248,125,047,248,125
63087 data047,248,125,047,248,215,047,248,215,047,249,000,111,249,000,111,242,170,143,242,170,143,239,255,251,239,255,251,191,255,254,000
63088 data191,255,254,239,255,251,234,170,171,242,170,143,240,000,015,249,000,111,249,085,111,248,215,047,248,255,047,248,125,047,248,125
63089 data047,248,125,047,248,255,047,248,215,047,249,085,111,249,000,111,240,000,015,242,170,143,234,170,171,239,255,251,191,255,254,000
63090 data191,255,254,234,170,171,234,170,171,224,000,011,224,000,011,225,085,075,225,085,075,225,255,075,225,255,075,225,255,075,225,255
63091 data075,225,255,075,225,255,075,225,255,075,225,085,075,225,085,075,224,000,011,224,000,011,234,170,171,234,170,171,191,255,254,000
63092 data191,255,254,202,170,163,202,170,163,228,000,027,228,000,027,227,085,203,227,085,203,225,255,075,225,255,075,225,235,075,225,235
63093 data075,225,235,075,225,255,075,225,255,075,227,085,203,227,085,203,228,000,027,228,000,027,202,170,163,202,170,163,191,255,254,000
63094 data170,170,170,138,170,162,128,000,002,164,000,026,165,085,090,163,085,202,163,255,202,161,255,074,161,235,074,161,235,074,161,235
63095 data074,161,235,074,161,235,074,161,255,074,163,255,202,163,085,202,165,085,090,164,000,026,128,000,002,138,170,162,170,170,170,000
63099 rem *** datas von file scene3 ***
63100 data170,170,170,128,000,002,128,000,002,133,085,082,133,085,082,135,255,210,135,255,210,135,170,210,135,170,210,135,170,210,135,170
63101 data210,135,170,210,135,170,210,135,170,210,135,255,210,135,255,210,133,085,082,133,085,082,128,000,002,128,000,002,170,170,170,000
63102 data128,000,002,133,085,082,135,255,210,135,170,210,135,170,210,135,170,210,135,170,210,135,170,210,135,170,210,135,170,210,135,170
63103 data210,135,170,210,135,170,210,135,170,210,135,170,210,135,170,210,135,170,210,135,170,210,135,255,210,133,085,082,128,000,002,000
63104 data000,000,000,021,085,084,031,255,244,030,170,180,030,170,180,030,170,180,030,170,180,030,170,180,030,170,180,030,170,180,030,170
63105 data180,030,170,180,030,170,180,030,170,180,030,170,180,030,170,180,030,170,180,030,170,180,031,255,244,021,085,084,000,000,000,000
63106 data085,085,085,127,255,253,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,150
63107 data173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,127,255,253,085,085,085,000
63108 data085,085,085,111,255,249,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,150,173,122,150,173,122,085
63109 data173,122,150,173,122,150,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,122,170,173,111,255,249,085,085,085,000
63110 data169,085,106,175,255,250,191,170,254,190,170,190,186,170,174,122,170,173,122,150,173,122,150,173,122,150,173,122,085,173,121,125
63111 data109,122,085,173,122,150,173,122,150,173,122,150,173,122,170,173,186,170,174,190,170,190,191,170,254,175,255,250,169,085,106,000
63112 data170,170,170,175,255,250,191,255,254,191,255,254,190,150,190,190,150,190,190,150,190,190,150,190,189,085,126,189,125,126,189,255
63113 data126,189,125,126,189,085,126,190,150,190,190,150,190,190,150,190,190,150,190,191,255,254,191,255,254,175,255,250,170,170,170,000
63114 data170,170,170,175,255,250,191,255,254,191,255,254,191,085,254,189,085,126,189,125,126,189,255,126,189,195,126,189,195,126,189,195
63115 data126,189,195,126,189,255,126,189,125,126,189,085,126,189,085,126,191,085,254,191,255,254,191,255,254,175,255,250,170,170,170,000
Listing 1. Alle »ALLE SPRITES« Dieser DATA-Lader erzeugt auf der Diskette die in den Beispielprogrammen benötigten Sprite-Files.

Die Befehle zur Spriteprogrammierung

Zehn Basic-Befehle dienen zum Erstellen und Verwalten von Sprites:

SPRDEF

Damit ruft man den Sprite-Editor auf. Der Bildschirm wird gelöscht, links oben erscheint ein Raster mit 24 mal 21 möglichen Positionen, darunter fragt der Computer nach der gewünschten Sprite-Nummer. Wir haben nun die Wahl zwischen acht vorgesehenen Sprites. Sollten Sie schon ein MOB im Speicher haben, dann rufen Sie es nun mit seiner Nummer auf, ansonsten müssen Sie sich jetzt festlegen: Alle weiteren Sprite-Befehle beziehen sich immer auf diese Nummer. Nach deren Eingabe wird das Rasterfeld mit dem Inhalt eines speziellen Speicherbereiches (aus $0E00 bis $0FFF = dezimal 3584 bis 4095) gefüllt, der die Informationen des gewählten Sprites enthält. Falls noch kein Sprite definiert war, kann dabei auch allerlei Byte-Müll abgebildet werden, der uns aber vorläufig nicht erschüttern soll. In der linken oberen Ecke des Rasterbereiches meldet sich ein Kreuz: das ist der Spritecursor. Oben rechts neben dem Raster ist unser Sprite so abgebildet, wie es im Normalbetrieb später auf dem Bildschirm erscheinen wird.

Bevor wir auf die einzelnen Optionen des Sprite-Editors eingehen, noch eine Bemerkung. Alles bisher Beschriebene benutzt den Grafik-Bildschirm. Ebenso wie bei der Verwendung der hochauflösenden und der Mehrfarbengrafik wird dazu der Basic-Anfang nach $4000 verschoben, also über die Bit-Map.

Sehen wir uns nun die Möglichkeiten unseres Editors an:

CLR/HOME: Damit kann das Definitionsfeld gelöscht werden. Das befreit uns vom Byte-Müll.

HOME: Der Sprite-Cursor marschiert in die linke obere Ecke.

CURSOR-TASTEN

Damit wandert der Sprite-Cursor über das Rasterfeld.

RETURN: Der Cursor wird auf den Anfang der nächsten Zeile gesetzt.

A: Die Wiederholungsfunktion der Tasten 1 bis 4 kann durch einmaliges Drücken aus-, durch nochmaliges Drücken wieder eingeschaltet werden.

M: Einmal Drücken schaltet den Mehrfarbenmodus ein. Dadurch bekommen die Tasten 1 bis 4 eine neue Bedeutung.

Nochmaliges Drücken schaltet wieder auf den normalen Hochauflösungsmodus.

X: Ein Druck verdoppelt das Sprite in waagerechter Richtung, ein weiterer Tastendruck erzeugt wieder ein Sprite in normaler Breite.

Y: Mit dieser Taste passiert in der Senkrechten dasselbe wie in der Horizontalen bei der X-Taste.

ZIFFERNTASTEN 1 BIS 4 a) Im Normalmodus setzt 1: die aktuelle Hintergrundfarbe (0), 2-4: die aktuelle Vordergrundfarbe (M).

b)Im Mehrfarbenmodus setzt 1: die Hintergrundfarbe (00) 2: eine Multicolorfarbe (01) 3: die aktuelle Vordergrundfarbe (10) 4: die andere Multicolorfarbe (11) Zur Erläuterung:

CONTROL 1-8

Wählt die aktuelle Vordergrundfarben 1-8 aus.

COMMODORE 1-8

Leistet dasselbe mit den Farbcodes 9 bis 16.

Zwei Optionen werden merkwürdigerweise im Handbuch nicht erwähnt, die recht nützlich sind:

C: Das ist eine Kopierfunktion. Nach Tastendruck erscheint die Frage »Copy from?«. Nach Eingabe einer Spritenummer wird das dazugehörige Muster in das aktuelle Sprite kopiert und dieses dabei überschrieben. Das ist ganz sinnvoll, wenn man mehrere ähnliche Sprites erzeugen möchte.

Was nicht im Handbuch steht

Dasselbe passiert auch, wenn man die Funktionstaste F1 betätigt.

Ist man einmal versehentlich auf diese Tasten geraten, dann kann man durch RETURN wieder in den normalen Editorzustand gelangen.

CONTROL C: Erlaubt das Umschalten zwischen den Sprites. Nach Betätigen dieser Tastenkombination verschwindet die aktuelle Spritenummer. Gibt man nun die gewünschte Nummer ein, schaltet sich das dazugehörige Sprite an.

Zwei Möglichkeiten zum Verlassen des Sprite-Editors sind vorgesehen:

STOP-Taste: Nach dem Betätigen der Taste verliert man alle neuen Eingaben im Definitionsfeld.

Gibt man anschließend eine Spritenummer ein, wird das dazugehörige Muster eingeladen.

Ein anschließendes RETURN führt zum Verlassen des Editors. Mit READY meldet sich der Textbildschirm zurück.

SHIFT-RETURN

Speichern des aktuellen Sprites im Bereich $0E00 - 0FFF.

Ebenso wie bei der STOP-Taste kann man danach durch Eingabe einer neuen Spritenummer das nächste Sprite zur Bearbeitung in den Raster holen.

Ein RETURN führt zum Verlassen des Sprite-Editors.

Interessant an SPRDEF ist, daß man diesen Befehl auch im Programm-Modus verwenden kann. Auf diese Weise kann man im Programm ein oder mehrere Sprites erstellen und anschließend also nach Aussteigen mit STOP/RETURN oder SHIFT-RETURN/RETURN - läuft das Programm weiter.

Das also sind alle Möglichkeiten unseres Sprite-Editors: Leider fehlen einige nötige Optionen. So ist es nicht möglich, die frisch zusammengebauten Sprites in DATA-Zeilen abzulegen, die Multicolorregister müssen vor dem SPRDEF-Aufruf belegt werden, die Muster kann man nicht invertieren, drehen oder spiegeln.

SPRCOLOR

Im Normalmodus kann die Punktfarbe eines Sprites und auch die Farbe der Bitkombination 10 des Multicolormodus durch den SPRITE-Befehl bestimmt werden oder in SPRDEF durch die Kombinationen von Control- oder Commodoretaste mit einer Ziffer. Die Belegung der Multicolorregister mit Farbe -das entspricht den SPRDEF-Zifferntasten 2 und 4 -, also der Bitkombinationen 01 und 11 erfolgt durch den SPRCOLOR-Befehl. Die Verwendung von

SPRCOLOR A,B führt in Multicolorregister 1 (Bit-Kombination 01 oder SPRDEF-Taste 2) zur Farbe A, in Multicolorregister 2 (Bit-Kombination 11 oder SPRDEF-Taste 4) zur Farbe B. Somit ergibt der Befehl SPRCOLOR 3,6 die Farben ROT und GRUN, entsprechend den Bitkombinationen 01 und 11.

SPRITE

Dies ist zweifellos der wichtigste Befehl für ein schon vorhandenes Spritemuster. Er schaltet ein Sprite ein und legt seine Eigenschaften fest. Syntax:

SPRITE A,B,C,D,E,F,G

Keine Angst vor den vielen Parametern: Sie müssen nicht immer alle angeben. Zur Bedeutung der einzelnen Buchstaben: A: Spritenummer (1 - 8) B= 0: Ausschalten des Sprites B= 1: Einschalten des Sprites C: Farbcode für die Vordergrundfarbe (das ist das Bitpaar 10 bei Multicolorsprites) (1 bis 16)

D: Priorität gegenüber Text:

0 = Sprite vor Text

1 = Text vor Sprite

Nebenbei: Die Priorität von Sprites untereinander wird durch die Sprite-Nummer geregelt: 1 vor 2 vor 3... vor 8.

E: X-Vergrößerung:

0 = normale Größe 1 = doppelte Größe

F: Y-Vergrößerung:

0 = normale Größe 1 = doppelte Größe

Sind sowohl E als auch F auf 1 gesetzt, dann erhält man ein vierfach ausgedehntes Sprite.

G: Modus.

0 = normales Hires-Sprite 1 = Multicolor-Sprite

Ein Beispiel soll die Wirkung des Befehls demonstrieren:

SPRITE 1,1,3,0,1,1,0

Dadurch wird Sprite 1 eingeschaltet. Es ist rot, erscheint vor Bildschirmzeichen und ist sowohl in horizontaler wie auch in vertikaler Richtung verdoppelt. Es handelt sich um ein normales (also Hires-Sprite). Nun soll das gleiche Sprite auf die normale Größe gebracht werden:

SPRITE 1,,,0,0

Es genügt, die Werte anzugeben, die zu ändern sind. Alle anderen werden so übernommen, wie sie vorher festgelegt wurden. Die Spritennummer und die Kommata vor dem zu ändernden Wert sind obligatorisch.

MOVSPR

Das ist ein recht vielgestaltiger Geselle. MOVSPR kommt von "move sprite", also hat dieser Befehl mit der Positionierung und Bewegung von MOBs zu tun. Drei Varianten sind möglich:

a: MOVSPR n,X,Y

Das Sprite mit der Nummer n wird an den Ort mit den Koordinaten X,Y gesetzt. Als Bezugspunkt beim Sprite dient die linke obere Ecke (auch wenn diese unsichtbar ist). Bild 1 zeigt Ihnen das normale Sprite-Koordinatensystem, das in allen Grafik-Modi gültig ist.

Diagramm eines Koordinatensystems mit X-Achse nach rechts und Y-Achse nach unten; ein gerastertes Rechteck ist mit »sichtbar« beschriftet, der Randbereich mit »scheinbares Spritekoordinatensystem«
Bild 1. Das normale Spritekoordinatensystem

Der sichtbare Bildschirm erstreckt sich von X=24 bis 344 und in der Vertikalen reicht er von 50 bis 250. Für X und Y dürfen Werte zwischen 0 und 65535 eingesetzt werden. Bild 1 skizziert auch, bei welchen Koordinatenangaben ein Sprite voll sichtbar ist:

Links oben müssen dazu die Koordinaten (24/50) gewählt werden. Ein normales Sprite ist bei X=320, ein in X-Richtung gedehntes bei X = 296 gerade noch voll sichtbar. Entsprechend gilt für die Y-Werte: Normales Sprite bis Y= 229, in Y-Richtung gedehntes bis Y= 208.

Größere Koordinatenwerte führen zum Herauswandern aus dem sichtbaren Bereich. Überschreiten die X- oder Y-Werte eine bestimmte Grenze, dann treten die MOBs auf der jeweils gegenüberliegenden Seite wieder ins Bild. Das ist ab X=513 (bei gedehnten Sprites ab 481) und ab Y=286 (bei gedehnten Sprites ab 265) der Fall. Eine weitere Erhöhung der Koordinaten führt dann zum Wandern über den Bildschirm, zum erneuten Verschwinden und schließlich Wiederauftauchen auf der anderen Seite und so weiter.

Vorhin war die Rede vom »normalen« Sprite-Koordinatensystem. Daraus kann messerscharf geschlossen werden, daß es auch noch ein anderes gibt, ein »nicht normales«. Das ist tatsächlich der Fall und es handelt sich nicht nur um eines, sondern um eine ganze Menge verschiedener Systeme. Haben Sie nämlich durch den SCALE-Befehl ein neues Hires- oder Multicolor-Bildschirmsystem definiert, dann beziehen sich X und Y auf dieses, was manchmal zu einiger Verwirrung führen kann. Sollte also die Gefahr bestehen, daß ungewollt aus einer früheren Programmphase ein anderes Bildschirmsystem gültig ist, dann kann durch SCALE 0 der normale Zustand hergestellt werden.

Hier noch ein Beispiel: MOVSPR 1,300,100 setzt Sprite 1 an die Stelle (300/100) im jeweils gültigen Koordinatensystem.

b: MOVSPR n,+/-X,+/-Y

Damit kann man Sprite n relativ um + oder -X (und/oder Y) zur aktuellen Position verschieben. X und Y dürfen wieder Werte bis 65535 annehmen, wobei durch das Vorzeichen nun sogar eine Skalenbreite von -65535 bis + 65535 möglich wird. Auch hier beziehen sich X und Y auf das jeweils durch SCALE definierte Koordinatensystem (ohne SCALE-Anwendung also auf das normale Sprite-System aus Bild 1).

Auf diese Weise kann - zum Beispiel in einer Schleife - das Sprite praktisch endlos über den Bildschirm wandern. Es tritt nämlich keine Fehlermeldung auf, wenn die Summe aus alter Position und Verschiebung größer als 65535 wird. Beispielsweise ist es ohne weiteres möglich (ob es sinnvoll ist, wäre eine andere Frage), folgende Kombination zu verwenden: MOVSPR 8,100,65000:MOVSPR 8, 100, + 65000

Auch ein Unterlauf unter Null ist auf diese Weise erlaubt.

Wie Sie aus dem Beispiel erkennen können, kann die MOVSPR-Anweisung auch kombiniert verwendet werden:

MOVSPR 1,+10,100 verschiebt Sprite 1 um +10 Einheiten relativ zum vorangegangenen X-Wert und auf die Y-Koordinate 100.

MOVSPR 2,50,-20 läßt Sprite 2 auf die X-Koordinate 50 wandern und gleichzeitig um 20 Y-Einheiten nach oben.

c: MOVSPR n,W # V

Diese Variante des Spritebewegungs-Befehls ist eine feine Sache: Unabhängig vom sonstigen Programmgeschehen wird das Sprite mit der Nummer n mit einem Richtungswinkel W und der Geschwindigkeit V über den Bildschirm gesteuert. Der Winkel W wird in Grad angegeben. Bild 2 zeigt die möglichen Richtungen, die der Kompaßrose entsprechen:

Kompaßrosen-Diagramm: ein Kreis mit acht sternförmigen Zacken, beschriftet mit 0, 45, 90, 135, 180, 225, 270 und 315
Bild 2. Die Kompaßrose: MOVSPR

Ohne Fehlermeldung sind Eingaben möglich zwischen -65535 und +65535. Sinnvoll scheint das aber allenfalls in einer Schleife, die ständige Richtungswechsel durchführt, zumal negative Werte und Angaben größer als 33024 keine vernünftige Reaktion ergeben.

Auch für die Geschwindigkeit V sind Angaben zwischen -65535 und 65535 möglich. Als sinnvoll erweisen sich hier nur Werte zwischen 0 und 15. 0 stoppt die Bewegung und 15 ist die höchste erreichbare Geschwindigkeit. Für höhere V-Werte ergibt sich die Geschwindigkeit dann zu modulo(16). (Damit ist der Rest gemeint, der bei Division der eingegebenen Zahl durch 16 verbleibt. So ergibt V=30 dieselbe Geschwindigkeit wie V=14)

Eine Eigenart dieser MOVSPR-Variante ist es, daß die Wirkung dieses Befehls anhält, bis die Bewegung ausdrücklich durch MOVSPR n,W # 0 auf Null gesetzt wird. Auch ein abgeschaltetes Sprite wandert weiter, was Sie leicht mal ausprobieren können.

Der Befehl

MOVSPR 1,90 #15 läßt Sprite 1 mit Höchstgeschwindigkeit horizontal nach rechts über den Bildschirm jagen.

SPRSAV

Das ist ein sehr interessanter Befehl, dessen Anwendung wir später noch detailliert untersuchen werden. Zwei mögliche Varianten sind vorgesehen:

a: SPRSAV n,A$

Einem String (hier also A$) wird das Bitmuster des Sprite n zugeordnet.

Mittels SPRSAV 1,A$(2) ordnet man das Bitmuster des Sprite mit der Nummer 1 dem Stringarrayelement A$(2) zu.

b. SPRSAV A$,n

Das ist der umgekehrte Weg: Das in A$ enthaltene Bitmuster definiert nun das Sprite mit der Nummer n.

Durch SPRSAV A$(2),8 wird das in A$(2) gespeicherte Muster in das Sprite Nummer 8 gelesen.

Anstelle von A$ kann jede Stringvariable - auch ein Array-Element - verwendet werden. Einige Möglichkeiten, die auf diese Weise gegeben sind: "Klonen" eines Sprites, Definieren von mehr als acht Sprites (jeweils acht sind gleichzeitig auf dem Bildschirm aktivierbar), schneller Austausch von Spritemustern.

COLLISION

Was im C 64-Modus dem Assembler-Programmierer vorbehalten bleibt oder nur durch aufwendige POKE- und PEEK-Operationen realisiert werden kann, ist im C 128-Modus mit diesem und dem folgenden Befehl möglich: COLLISION A,NNNN fängt drei Typen von Ereignissen ab und setzt die Programmbearbeitung in Zeile NNNN fort. A ist dabei eine Typkennung:

1: Sprite/Sprite-Kollision 2: Sprite/Text-Kollision

3: Lichtgriffelaktivierung

Das Serviceprogramm ab NNNN ist wie ein Basic-Unterprogramm zu behandeln, also auch durch RETURN abzuschließen. Die weitere Bearbeitung geschieht dann an der Stelle, wo bei dem auslösenden Ereignis unterbrochen worden ist.

COLLISION stellt lediglich fest, welcher Typ stattgefunden hat. Bei Spritezusammenstößen kann also damit nicht die Spritenummer identifiziert werden. Es ist erlaubt, mehrere Kollisionstypen gleichzeitig zu aktivieren. Eine Aktivierung innerhalb eines Unterbrechungs-Service-Unterprogrammes ist nicht möglich: Es findet nur die Bearbeitung eines Typs zur Zeit statt. Falls also mehrere aktiviert sind, sollte einer der ersten Befehle im Unterprogramm das Abschalten aller Kollisionsabfragen sein mittels COLLISION A (ohne Zeilennummer). Am Ende der Routine kann dann COLLISION A,NNNN wieder eingeschaltet werden.

Nicht immer ist es sinnvoll, so zu verfahren (also die Kollisionsabfrage am Ende der Routine wieder einzuschalten): Falls beispielsweise der Typ 1 (Sprite/Sprite-Zusammenstoß) als Auslöser definiert ist, muß bedacht werden, daß die Überlappung zweier Sprites einige Zeit andauert und deshalb das Unterprogramm mehrfach angesteuert wird. Im einem Testprogramm (Listing 2) ist dieser Effekt deutlich an den vielen Textwiederholungen zu erkennen.

10 rem ***** testprogramm 1 - collision *****
20 bload"sprites2",onb0
30 sprcolor3,6
40 movspr7,300,100:movspr8,300,200
50 sprite7,1,2,0,0,0,1:sprite8,1,1,1,1,1,1
60 collision1,90
70 movspr8,+0,+5
80 goto70
90 collision1
100 print"kollision erfolgt"
110 collision1,130
120 return
130 collision1
140 print"noch eine kollision"
150 collision1,130
160 return
Listing 2. Kollision von Sprites

Unter welchen Umständen wird eine Kollision erkannt? Immer dann, wenn sich sichtbare Teile von Sprites gegenseitig oder mit Bildschirmobjekten (bei Typ 2) überlagern. Abgeschaltete Sprites werden nicht berücksichtigt, wohl aber Zusammenstöße außerhalb des sichtbaren Bereiches (das Handbuch behauptet das Gegenteil).

Probieren Sie doch einmal, in Zeile 40 von Listing 1 die Spritepositionierung:

40 MOVSPR 7,345,100:MOVSPR 8,345,200

Nach dem Start ist keines der beiden Sprites mehr auf dem Bildschirm zu sehen, Kollisionen werden aber gemeldet.

Zwei Aspekte verdienen noch Erwähnung: Zum einen darf man ein Programm, in dem der COLLISION-Befehl verwendet wird, nicht durch STOP unterbrechen. Tut man es trotzdem, dann funktioniert nach einem CONT die Kollisionsabfrage nicht mehr. Zum anderen: Natürlich können alle Sprite-Befehle auch ohne 40-Zeichen-Bildschirm betrieben werden, man sieht nur nichts. Das kann bei COLLISION ganz rätselhafte Effekte erzeugen. So wären Spiele denkbar, die ein Sprite per Joystick durch Hindernisse hindurchbewegen. Das ganze geschieht im Dunkeln (also mit abgeschaltetem oder nicht vorhandenem 40-Zeichen-Bildschirm) und lediglich die Reaktion auf eine Kollision erfolgt auf dem 80-Zeichen-Bildschirm. Der Phantasie sind keine Grenzen gesetzt.

BUMP

Der Name sagt's bereits: Auch hier geht es um Zusammenstöße. Mit dem BUMP-Befehl können wir einfach feststellen, welche Sprites in eine Kollision verwickelt sind: BUMP(A) erschließt über die Typkennung A zwei Sorten von Zusammenstößen. A=1: Sprite/Sprite-Kollision

A=2: Sprite/Text-Kollision.

Der Befehl hat lediglich die Aufgabe, den Inhalt eines speziellen Kollisionsregisters auszulesen. Das allerdings macht er so gründlich, daß dieses Register hinterher gelöscht ist. Es empfiehlt sich daher, diesen Wert sogleich in eine Variable zu speichern:

V = BUMP(1)

Die Zahl, die auf diese Weise erhalten wird, muß allerdings erst entschlüsselt werden (siehe da, ein alter Bekannter aus dem C 64-Modus), denn jedem Sprite ist ein Bit zugeordnet: Sprite 1 hängt mit Bit 0, Sprite 2 mit Bit 1 zusammen und so weiter bis zu Sprite 8, welches mit Bit 7 geht. Findet nun die Kollision statt, dann schalten die Bits der kollidierten Sprites auf »1«. Bild 3 zeigt Ihnen diese Zusammenhänge und einige Rechenbeispiele.

Tabellendiagramm mit den Zeilen Bits, Bitwerte und Sprites sowie einer Beispieltabelle mit fünf Bitmustern und ihren Ergebnissen
Bild 3. Das Ergebnis der BUMP(A)-Abfrage

Ein Supercrash unter Beteiligung aller acht Sprites würde dann also die Zahl 255 ergeben. Ein kleines Testprogramm (Listing 3) soll das Vorgehen dabei illustrieren.

10 rem ***** testprogramm 2 bump-befehl *****
20 bload"sprites2",onb0
30 sprcolor3,6
40 movspr7,100,100:movspr8,150,200
50 sprite7,1,2,0,0,0,1:sprite8,1,1,1,1,1,1
60 v=bump(1):if v>0 then gosub85
70 movspr8,+1,+3
80 goto60
85 print:print"bump(1) ergibt den wert"v
90 fori=0to7:a=2^i:if a and v then print"sprite "i+1"kollidiert
100 nexti
110 return
Listing 3. Ein Programm zur BUMP-Abfrage

Besonders die Zeilen 90 und 100 sind sicherlich für Sie interessant, weil man mit ihnen die Nummern der beteiligten Sprites feststellen kann.

Auch hier gilt, was schon bei COLLISION bemerkt wurde: Auch Zusammenstöße außerhalb des sichtbaren Bildschirmes werden registriert und das auch ohne 40-Zeichen-Bildschirm. Ebenso wie dort muß beachtet werden, daß ein Zusammenstoß einige Zeit in Anspruch nimmt, also die Reaktion darauf meistens mehrfach erfolgt.

Im Gegensatz allerdings zu COLLISION, das interrupt-gesteuert abläuft, muß die Abfrage des BUMP-Wertes mehrfach erfolgen. Der Befehl ist sowohl ohne als auch mit COLLISION einsetzbar. Im letzteren Fall dient er als Ergänzung im Unterprogramm zur Feststellung der Spritenummern.

RSPCOLOR

Damit sind Informationen zu den aktuellen Multicolor-Register-Inhalten zu bekommen:

RSPCOLOR(A) liefert bei

A = 1: Farbcode in Multicolorregister 1 (das ist das, welches der Bitkombination 01 zugeordnet ist) A = 2: Hier wird der Inhalt des anderen Multicolorregisters ausgegeben, das zu der Bitkombination 11 gehört.

RSPPOS

Sollte uns die aktuelle Position oder Geschwindigkeit eines Sprites interessieren, dann können wir das durch

RSPPOS(n,A) erfahren. Dabei ist n die Spritenummer und A wieder eine Kennung mit folgender Zuordnung: A = 0: aktuelle X-Koordinate A = 1: Y-Koordinate

A = 2: gerade vorhandene Geschwindigkeit

Leider gibt es da eine kleine Unstimmigkeit gegenüber dem Befehl MOVSPR: Gleichgültig, welches Sprite-Koordinatensystem wir dort durch SCALE festgelegt haben, RSPPOS liefert immer die Werte des normalen Systems. RSPPOS(0) liegt daher immer zwischen 0 und 511, RSPPOS(1) immer zwischen 0 und 255. Sollten Sie bei normalem System mittels MOVSPR höhere Werte eingegeben haben, dann wird hier immer modulo(512) für die X- und modulo(256) für die Y-Koordinate ausgegeben.

Auch die Sache mit der aktuellen Geschwindigkeit hat einen Haken: Falls Sie nämlich den Sprite mal auf andere Weise als durch MOVSPR n,W #V bewegen, erhalten Sie den Wert 0 als Ausgabe von RSPPOS(2).

RSPRITE

Hier haben wir das Pendant zum SPRITE-Befehl vorliegen. Alle dort verwendeten Parameter können hier durch

RSPRITE(n,A) abgefragt werden. n ist wieder die Spritenummer, A eine Kennung mit den Zuordnungen:

A = 0: Sprite ein- (=0) oder ausgeschaltet (=1)

A = 1: Farbcode des Sprites (Im Multicolormodus Farbe der Bitkombination 10) A = 2: Sprite vor (=0) oder hinter

(=1) Text.

A = 3: In X-Richtung gedehnt (=1) oder nicht (=0). A = 4: In Y-Richtung gedehnt (=1) oder nicht (=0). A = 5: Multicolormodus (=1) oder normales Hires-Sprite (=0)

JOY

Dieser Befehl hat zwar nicht unbedingt etwas mit den Sprites zu tun, wird aber häufig zum Steuern der Sprites eingesetzt und kommt daher an diese Stelle. Man kann damit auf einfache Weise den Zustand der Joystickports abfragen:

JOY(A) fragt bei A = 1 den Port 1, und bei A = 2 den Port 2 ab.

Bevor wir uns die Bedeutung der Abfrageergebnisse ansehen, noch eine Warnung: Offensichtlich entspricht der Feuerknopf in Port 1 der Taste F8, so daß im Direktmodus immer der Maschinensprachemonitor angesprungen wird, wenn man den Feuerknopf drückt. Beim Port 2 gibt es dieses Problem nicht.

Die mittels JOY ausgelesenen Werte haben folgende Bedeutung: 0 = Ruhestellung 1-8 = Richtungen (siehe Bild 4) 128 = Ruhestellung, Feuerknopf gedrückt 129-136 = Richtungen mit gedrücktem Feuerknopf (siehe Bild 4)

Kreisdiagramm mit drei konzentrischen Ringen, den Achsenbeschriftungen UP, DOWN, LEFT und RIGHT und den Werten 1 bis 8 sowie 129 bis 136
Bild 4. Schema zur JOY-Abfrage

Auf diese Weise können wir bequem Sprites mit dem Joystick steuern:

100 ON JOY(2) GOSUB 300,310,320, 330...

Im Testprogramm (Listing 4) ist eine mögliche Variante dazu gezeigt.

10 rem ***** testprogramm 3  joy-befehl *****
20 bload"sprites2",onb0
30 sprcolor3,6
40 movspr1,100,100:movspr8,200,200
50 sprite1,1,2,0,0,0,1:sprite8,1,1,1,1,1,1
60 collision1,110
70 x=200:y=200
80 onjoy(2)gosub190,200,210,220,230,240,250,260
90 movspr8,x,y
100 goto80
110 collision1
120 print"kollision erfolgt"
130 collision1,150
140 return
150 collision1
160 print"noch eine kollision"
170 collision1,150
180 return
190 x=x:y=y-1:return
200 x=x+1:y=y-1:return
210 x=x+1:y=y:return
220 x=x+1:y=y+1:return
230 x=x:y=y+1:return
240 x=x-1:y=y+1:return
250 x=x-1:y=y:return
260 x=x-1:y=y-1:return
Listing 4. Steuern mittels JOY

Damit haben wir alle im Basic 7.0 enthaltenen Sprite-Befehle behandelt. Allerdings sind noch einige Fragen offen geblieben, die uns nun weiter beschäftigen werden.

Wie kann man Sprites der Nachwelt erhalten?

1. Sprites im Speicher

a. Sprite-Daten-Speicher

Schon beim SPRDEF-Befehl haben wir diesen Speicherbereich zwischen 3584 und 4095 ($0E00 bis 0FFF) erwähnt, in dem die Spritedaten landen, wenn ein Sprite durch Shift-Return gespeichert wird. Pro MOB befinden sich dort - in der Reihenfolge der Spritenummern - je 63 Byte und eine Endmarkierung (das ist ein 0-Byte). Verfügbar bleiben diese Daten, bis sie überschrieben oder der Computer abgeschaltet wird.

b. Sprite-Strings

Noch flüchtiger ist die Existenz der Daten im String, der durch SPRSAV gebildet wird. Schon ein CLR macht der Kunst den Garaus. In jeweils 67 Byte (die letzten vier enthalten immer die Werte 23, 0, 20, 0) finden sich dort die Bitmuster. Sollten Sie einmal versuchen, so einen String (z.B. A$) durch PRINT A$ auf dem Bildschirm zu zeigen, dann müssen Sie sich auf allerhand Überraschungen gefaßt machen: Alle Bytewerte von 0 bis 255 können auftreten und wirken so, als wären sie mittels CHR$(Wert) zur Ausgabe aufgerufen worden. Wenn also der Wert 147 zufällig dabei sein sollte, dann wird der Bildschirm gelöscht, etc. Jedes RUN führt übrigens ebenfalls ein CLR aus. Auch das ist daher nicht die richtige Methode, die mühselig konstruierten Sprites etwas länger am Leben zu erhalten.

Sowohl im Speicher als auch im String haben die Sprite-Daten genau dasselbe Format (bis auf die letzten Bytes, die im einen Fall aus einer 0, im anderen aus den Zahlen 23,0,20,0 bestehen). Das können Sie selbst nachprüfen am Programm "VERGLEICH SPRDT" (Listing 5).

10 rem ***** vergleich spritedaten *****
20 rem in spritespeicher und im string
30 dima$(7)
40 bload"sprites1",onb0
50 forj=0to7
60 :printchr$(147)chr$(18)j+1".sprite"chr$(146):print:sprsavj+1,a$(j)
70 :bank0:print"datenspeicher:"
80 :fori=0to63
90 ::print(peek(3584+64*j+i));
100 :nexti:print:print"string:"
110 :fork=1tolen(a$(j))
120 ::printasc(mid$(a$(j),k,1));
130 :nextk:print:print"bitte taste druecken"
140 :getkeyb$
150 :print
160 nextj
Listing 5. »VERGLEICH SPRDT«. Programm zum Vergleichen von Spritemustern im Speicher und im String

Nach dem Start werden zunächst die Spritedaten von der Diskette geladen und dann in Strings eingelesen. Anschließend erscheinen auf dem Bildschirm Sprite für Sprite die Bytewerte sowohl aus dem Speicher als auch aus dem String.

2. Sprites auf Diskette und Kassette.

a. BSAVE

Eine elegante Methode zur Verewigung unserer Sprites ist das Speichern des Spritespeichers mittels des BSAVE-Befehls. Man schreibt dazu:

BSAVE"Name",ON B0,P3584 TO P4095

Damit sind dann alle acht Sprites erfaßt. Leider arbeitet dieser Befehl nicht mit der Kassettenstation, denn es sind nur Gerätenummern von 4 bis 15 zulässig. Das Wiedereinladen geschieht dann (wie in den hier vorgestellten Beispielprogrammen) mittels:

BLOAD"Name",ON B0

b. Vom Monitor aus

Damit ist es nun auch Benutzern der Datasette möglich, den Spritespeicher auf Kassette zu sichern. Der Monitor verfügt über ein Kommando S zum Speichern beliebiger Speicherbereiche. Mittels MONITOR oder der Funktionstaste F8 schalten Sie den Monitor an, dann verwenden Sie:

S"Name",01, + 3584, + 4095 (Kassette) oder

S"Name",08, + 3584, + 4995 (Diskette).

Mit Hilfe des L-Kommandos im Monitor kann solch ein File dann problemlos wieder geladen werden:

L"Name",01(oder 08), + 3584

c. Als sequentielles File

Hat man die Sprites in Strings abgelegt (das dürfen dann auch mehr als acht sein), dann kann man sich der üblichen Techniken zur Speicherung in sequentiellen Dateien bedienen. Allerdings kann es manchmal dabei Schwierigkeiten mit bestimmten Byte-Inhalten geben. So ist es durchaus möglich, daß ein Byte zufällig den Inhalt 13 (also einem RETURN entsprechend) hat, was zu Störungen beim Wiedereinlesen führen kann. In solchen Fällen könnte man die einzelnen Bytes (wie im Programm VERGLEICH SPRDT geschehen) in die ASCII-Zahlen wandeln und in dieser Form als SEQ-File speichern. Diese Möglichkeit werden wir nicht weiter beschreiben, weil die Speicherung per Monitor oder BSAVE schneller und effektiver erscheint.

3. Für ein Listing

Viele Programme werden nicht in Form von Disketten- oder Kassettenfiles, sondern einfach auf dem Papier weitergegeben. Dieses Problem lösen bessere Sprite-Editoren durch eine Funktion, die alle Werte in DATA-Zeilen an ein Programmende anhängt. In SPRDEF existiert diese Möglichkeit leider nicht, was uns dazu zwingt, selbst die Initiative zu übernehmen.

a. Aus dem Speicher in DATAs

Dazu haben wir ein kleines Programm »SPRITEDATAS« gestrickt (Listing 6), das Sie mit der MERGE-Funktion an Ihr eigenes fertiges Spriteprogramm anhängen können. Noch eine Warnung: Wenn Sie SPRITDATAS abgetippt haben, speichern Sie es unbedingt vor einem RUN ab, denn es verabschiedet sich am Ende des Programmlaufes aus Ihrem Basicspeicher. Nun also zur Verwendung des Programmes. Man startet es durch RUN63000. Das Auslesen des Sprite-Datenspeichers geschieht im FAST-Modus (der 40-Zeichen-Bildschirm verabschiedet sich vorübergehend), danach erscheinen jeweils zwei Programmzeilen (mit Zeilennummern ab 63020) und darunter ein GOTO 63009. Außerdem meldet sich ein BREAK und READY. Mittels der HOME-Taste und 3 aufeinanderfolgenden RETURNs übernehmen Sie die Zeilen ins Programm und erzeugen den nächsten Bildschirm, wo das Spielchen dann ebenso weitergeht. Insgesamt machen wir das achtmal (für 8 Sprites). Zu guter Letzt wird in Zeile 63040 noch eine Einleseschleife übernommen und es meldet sich der Befehl DELETE 63000-63011. Haben Sie auch das mit HOME und zwei RETURNs übernommen, dann ist der DATA-Generator gelöscht und an Ihr Programm wurde die gesamte DATA-Sequenz angehängt. Als letzte Zeile finden Sie beim Listen noch die Einleseschleife, zu der Sie nun nur noch an passender Stelle Ihres Programmes mittels GOSUB 63040 springen müssen.

62999 rem *** datas aus spritespeicher ***
63000 fast:bank0:forj=0to7
63001 a$(j)="":fori=0to62:a$=str$(peek(3584+64*j+i))
63002 a$=right$(a$,len(a$)-1):a$="000"+a$:a$=right$(a$,3)
63003 a$(j)=a$(j)+a$+",":nexti
63004 a$(j)=a$(j)+"000"
63005 nextj:slow
63006 forj=0to7:printchr$(147);
63007 print63020+2*j"data"left$(a$(j),127)
63008 print63021+2*j"data"right$(a$(j),127):print"goto63009":stop
63009 nextj:printchr$(147);
63010 print"63040 fori=3584to4095:reada:pokei,a:nexti:return"
63011 print"delete 63000-63011":stop
Listing 6. »SPRITEDATAS«. Erzeugen von DATA-Zeilen aus Spritedaten

Es gibt sicherlich elegantere Möglichkeiten, DATA-Zeilen zu generieren. So könnten wir auch den Tastaturpuffer verwenden. Das aber überlassen wir Ihrer Schöpferkraft.

b. Aus den Strings in DATAs

Auch das Übertragen der Stringinhalte in DATA-Zeilen ist eine Lösungsmöglichkeit unseres Problems. Sie ist sogar sehr verlockend, weil wir damit auf einen Streich mehr als acht Sprites ins Listing schreiben könnten. Die Programmierung wird aber etwas komplizierter, weil hier nicht mehr der ganze Inhalt des Sprite-Strings in einen Zeilen-String gelesen werden kann. Es gibt eine Reihe von Strategien um das Problem zu lösen (mehr oder weniger einfache, was teilweise mit dem Auslesen der DATAs zusammenhängt), auch hier sind Sie gefordert!

Koppeln von Sprites

Sollten Sie ein komplexeres grafisches Gebilde erzeugen wollen als es mit einem Sprite möglich ist, dann können Sie auch mehrere Sprites koppeln. Am Beispiel von vier Sprites zeigt Ihnen Bild 5 die dazu nötigen Koordinatenwerte:

Diagramm aus vier aneinandergrenzenden Rechtecken mit den Beschriftungen SPRITE 1 bis SPRITE 4 und den Koordinaten ihrer Eckpunkte
Bild 5. Koppeln von vier Sprites

Das Prinzip ist einfach: Weil jedes Sprite in X-Richtung 24 Bit breit ist, ergibt sich für die X-Koordinate des Nachbarsprites bei nahtloser Verbindung ein um 24 größerer Wert. 21 Bit mißt ein MOB in der Vertikalen, wodurch sich Y+21 für ein unterhalb des ersten gelegenes Sprite berechnet als Y-Koordinate. Das Programm »VIER SPRITES« (Listing 7) demonstriert die Verhältnisse.

10 rem ***** vier sprites *****
20 goto110
30 y=y-3:return
40 x=x+3:y=y-3:return
50 x=x+3:return
60 x=x+3:y=y+3:return
70 y=y+3:return
80 x=x-3:y=y+3:return
90 x=x-3:return
100 x=x-3:y=y-3:return
110 bload"sprites2",onb0
120 printchr$(147):color0,1:color4,1:color5,8
130 x=50:y=60
140 movspr3,x,y:movspr4,x+125,y:movspr5,x,y+122:movspr6,x+125,y+122
150 sprite3,1,8,1:sprite4,1,8,1:sprite5,1,8,1:sprite6,1,8,1
160 do until a=101
170 :movspr4,-1,y:movspr5,x,-1:movspr6,-1,-1
180 :a=a+1
190 loop
200 bank15:sys65520,10,20:a$="joystick in port2"
210 do until joy(2)=128
220 :color5,3
230 :gosub330
240 :color5,1
250 :gosub330
260 loop:x=rsppos(3,0):y=rsppos(3,1)
270 color5,8:printchr$(147):fori=1to50:next
280 do
290 :onjoy(2)gosub30,40,50,60,70,80,90,100
300 :movspr3,x,y:movspr4,x+24,y:movspr5,x,y+21:movspr6,x+24,y+21
310 loop until joy(2)=128
320 end
330 sys65520,10,20:printa$:fork=1to50:nextk:return
Listing 7. »VIER SPRITES«. Demonstration zum Koppeln von Sprites

Zunächst wächst ein grafisches Objekt aus vier Sprites zusammen. Dieses kann dann mit dem Joystick in Port 2 (nach Druck auf den Feuerknopf) über den Bildschirm gesteuert werden (Zeile 300). Ein weiterer Druck auf den Feuerknopf beendet das Programm. Wenn Sie bei bestimmten Richtungen genau hinsehen, werden Sie eine leichte Unstimmigkeit in der Bewegung feststellen. Bei noch größeren Objekten scheint Basic für diese Steuerung doch etwas zu langsam zu werden und man muß auf Maschinensprache umsteigen um eine flüssige Bewegung zu erreichen.

Mehr als acht Sprites

Hier soll nicht die Rede sein von trickreichen Anwendungen der Unterbrechungsprogrammierung per Assembler, die es tatsächlich zuläßt, mehr als acht Sprites GLEICHZEITIG auf dem Bildschirm zu zeigen. Vielmehr geht es uns um die schnelle, nacheinander ausgeführte Abbildung. Sehen Sie sich dazu zuerst einmal das Programm »SPRITE-TRICK« ( Listing 8) an. Hier liegen acht Spritemuster vor, die nacheinander - mit programmierter Verzögerung, weil's sonst zu schnell ginge - auf derselben Bildschirmstelle gezeigt werden. Es ergibt sich ein kleiner Trickfilm.

10 rem ***** ein sprite-trick *****
20 bload"sprites1",onb0
30 printchr$(147)
40 for i=1 to 8:movspri,200,100:nexti
50 for i=1 to 10:for j=1 to 8
60 if j=1 then sprite8,0:else spritej-1,0
70 spritej,1,i+1,1,1,1,0
80 for k=1 to 25:nextk:nextj
90 nexti
100 sprite8,0:sprite1,0
Listing 8. »SPRITE-TRICK«. Ein kleiner Trickfilm

Nun sind acht Teilbilder ein etwas ärmlicher Bewegungseffekt. Um wirklich längere Passagen zu zeigen, müßten wir anders verfahren. Das soll im Programm »24 SPRITES« demonstriert werden.

Das Geheimnis - Sie haben es sicherlich schon längst vermutet - liegt im SPRSAV-Befehl begründet. 24 Spritemuster wurden hier in ein Stringarray eingelesen (Zeilen 20 bis 80). Während die Sprites auf dem Bildschirm aktiv sind (die Aktivierung erfolgt schon in den Zeilen 130 bis 150), wechseln wir durch die Zuordnung anderer Spritemuster aus den Strings ihre Erscheinungsformen. Das geschieht in der DO...LOOP Schleife ab Zeile 170. Hier geschieht das - wegen des hübschen Mustereffektes - zyklisch (durch Drücken von »←« können Sie das Programm beenden), man kann sich aber ohne weiteres vorstellen, wie ein oder mehrere große Arrays gebildet und dann fortlaufend deren Spritemuster verwendet werden können. Gleichzeitig sind die sich ändernden Sprites noch beweglich...

Sie sehen, daß kaum Grenzen gesetzt scheinen, allerhand Interessantes auf dem Bildschirm ablaufen zu lassen.

Noch ein paar Sprite-Besonderheiten

1. Sprites und Splitscreens

Beim C 128 haben wir ja in den Grafik-Modi 2 und 4 die Möglichkeit, sowohl hochauflösende (oder aber Multicolor-) Grafik als auch Text auf einem Bildschirm gleichzeitig darzustellen. Damit ist nicht etwa der CHAR-Befehl gemeint, sondern durch eine spezielle Technik, die den Rasterzeileninterrupt ausnutzt, wird der Bildschirm tatsächlich in zwei verschiedenen Modi betrieben.

Wie verhalten sich nun die Sprites auf solch einem Bildschirm? Wie es Kobolden ansteht, scheren sie sich überhaupt nicht darum! Probieren Sie mal das Programm VIER SPRITES mit einer kleinen Änderung aus: In die Zeile 130 fügen Sie noch ein GRAPHIC 2,0,12 (oder für den Multicolormodus GRAPHIC 4,0,12) und starten dann. Ohne Reaktion von Seiten der Sprites können Sie diese über die in der Bildmitte liegende Modusgrenze hinwegsteuern. Allerdings reagiert der Bildschirm mit einem penetranten Flattern der Grenzlinie, wenn das Sprite genau darauf liegt.

Falls Sie dasselbe mit dem Grafik-Modus 4 (also GRAPHIC 4,0,12) probieren, würde es uns interessieren, ob auch Ihr Computer nach einiger Zeit mit irgendeiner Fehlermeldung aussteigt. Beim Modell des Autors hat er sich so verhalten. Wenn er sich dann die als fehlerhaft gemeldete Zeile listen ließ, befanden sich allerlei merkwürdige - anscheinend zufällig erzeugte - Fehler darin. Zuvor aber war die Zeile fehlerfrei gewesen! Man sollte offensichtlich diese Möglichkeit mit etwas Vorsicht gebrauchen.

2. Sprites und Windows.

Ebensowenig wie sich Sprites um den Splitscreen kümmern, scheren sie sich um Windows. Probieren Sie es mal aus, indem Sie in Zeile 130 des Programmes »VIER SPRITES« noch ein Window definieren (zum Beispiel mit WINDOW 5,5,20,10). Unbeirrt von allen Einschränkungen, denen unser Text unterworfen ist (hier die Aufforderung zum Benutzen des Port 2), läßt sich unser Spritegebilde kreuz und quer verschieben.

Die Sprites an sich sind damit zunächst einmal durchleuchtet. Legen wir sie also für eine Weile beiseite und wenden wir uns den anderen Grafikobjekten des C 128 zu, den Shapes.

Was sind Shapes?

Wie so vieles aus der Computerkultur stammt auch dieses Wort aus dem angelsächsischen: Shape heißt ins Deutsche übersetzt soviel wie Form, Gestalt, Umriß. Hier bezeichnet Shape einen genau definierten Bildschirmausschnitt, der gespeichert und wiederverwendet werden kann. Wie das mit dem C 128 geschieht, soll nun erklärt werden.

SSHAPE

Dies ist der Befehl, mit dem ein Bildschirmbereich in einen String eingelesen werden kann. Seine Syntax ist

SSHAPE A$,X1,Y1,X2,Y2

A$ ist hier dann eine beliebige Stringvariable, auch ein Array kann Verwendung finden. X1 bis Y2 bezeichnet die Eckkoordinaten des Rechteckes, dessen Inhalt als Shape definiert werden soll. Bild 6 soll das etwas verdeutlichen:

Diagramm eines Rechtecks, dessen linke obere Ecke mit (X1, Y1) und dessen rechte untere Ecke mit (X2, Y2) beschriftet ist
Bild 6. Zur Syntax des SSHAPE-Befehls

(X1,Y1) gehören zum linken oberen und (X2,Y2) zum rechten unteren Eckpunkt. Es ist auch möglich, X2 und Y2 wegzulassen. In diesem Fall werden durch den SSHAPE-Befehl einfach die aktuellen Koordinaten des Grafik-Cursors eingesetzt.

Falls es noch unklar sein sollte: Im Gegensatz zu Sprites, die jedem Bildschirm-Modus trotzen (also sowohl als Hires- oder Multicolorsprites im Text, als auch im Hochauflösungs- und im Multicolormodus auftauchen können), sind Shapes fest mit dem aktuellen Modus verbunden.

Ein Shape ist ein Grafikobjekt, kann daher auch nur in den Grafikmodi auftreten und definiert werden. Also in denen, die durch GRAPHICn erzeugt werden, wobei n von 1 bis 4 geht. Außerdem ist ein Multicolorshape auch nur im Multicolormodus ein solches. Schaltet man beispielsweise mittels GRAPHIC1 um in den normalen Hochauflösungsmodus, wird auch unser Shape nur als hochaufgelöstes sichtbar.

Wie wir uns aus all dem schon fast denken können, ist das Koordinatensystem, auf das sich die Angaben X1 bis Y2 beziehen, das im jeweiligen Modus gültige. Im Normalfall also im Hires-Modus X von 0 bis 319 und Y von 0 bis 199. Im Multicolormodus geht X nur von 0 bis 159.

A$ ist ein String. Für Strings gilt beim C 128 die Begrenzung auf maximal 255 Byte. Ein durch SSHAPE in einen String zu schreibendes Gebiet darf also eine gewisse Größe nicht überschreiten. Bezeichnen wir als

DX = X2 - X1

und als

DY = Y2 - Y1

dann gilt für die Bytemenge im String im Hochauflösungsmodus die Formel:

Lh = INT((ABS(DX) + 1)/8 + .99)*(ABS(DY) + 1) + 4

Im Multicolormodus gilt stattdessen die Gleichung:

Lm = INT((ABS(DX) + 1)/4 + .99)*(ABS(DY) + 1) + 4

Die Addition von 4 am Ende der Formeln ergibt sich durch vier Byte, die den Schluß des Shape-String bilden und Steuergrößen enthalten.

Natürlich können Sie jedesmal, wenn Sie ein Shape erstellen, von dem Sie argwöhnen, es könne zu groß sein für den String, unsere Formeln anwenden. Eine Hilfe soll Ihnen Listing 9 »SSHAPE-TABELLE« geben. In der vorliegenden Form druckt es eine Liste aus, in deren linker Spalte Werte für eine Y-Differenz stehen. Rechts daneben sind die maximal zulässigen DX-Werte angegeben sowie die sich ergebende Stringlänge. Auf diese Weise können Sie - ausgehend von DY - mit einem Blick erkennen, wie groß DX sein darf. Es empfiehlt sich, noch drei weitere Tabellen auszudrucken. Da ist zunächst einmal interessant, wie der Maximalwert von DY bei gegebenem DX aussieht. Zu diesem Zweck ist lediglich die Reihenfolge des Ausdruckes und der Rechenoperationen zu ändern:

10 rem ***** sshape tabelle *****
20 fast:open1,4:print#1,"y-diff.","x-diff.","stringlaenge"
30 deffnh(x)=int((abs(x)+1)/8+.99)*(abs(y)+1)+4
40 y=0
50 do until y=200
60 :y=y+1:x=0
70 :do until x=320
80 ::x=x+1
90 ::z=fnh(x):ifz>255thenprint#1,y1,x1,z1:exit
100 ::x1=x:y1=y:z1=z
110 :loop
120 loop
130 close1:slow:end
Listing 9. »SSHAPE-TABELLE«. Eine Hilfe für Shapes: Eine Tabelle wird gedruckt

In Zeile 20 kommt dann X-DIFF vor Y-DIFF, Zeile 40 enthält X=0, in Zeile 50 schreiben wir DO UNTIL X=320, in der nächsten Zeile 60 steht: X=X+1:Y=0. Zeile 70 wird zu DO UNTIL Y=200 und Zeile 80 zu Y=Y+1. Schließlich wird auch in Zeile 90 noch die Reihenfolge des Ausdruckes umgestellt zu PRINT #1,X1,Y1,Z.

Diese beiden Tabellen beziehen sich auf Shapes im Hochauflösungsmodus. Zwei weitere Tabellen für den Multicolormodus bekommen Sie, wenn Sie in Zeile 30 die vorhin angegebene Berechnungsfunktion zu diesem Modus einfügen. Nur die Zahl 8 muß dazu in eine 4 verändert werden.

Sollte dann, trotz all dieser Berechnungsmöglichkeiten - man sieht ja nicht jedesmal in die Tabellen - der zu speichernde Shape größer werden als 255 Byte, dann meldet unser Computer einen STRING TOO LONG ERROR.

Einen Aspekt zum SSHAPE-Befehl müssen wir noch besprechen, weil es da einige Verwirrung geben kann: Wie reagiert SSHAPE auf ein durch SCALE verändertes Bildschirmsystem? Die Koordinatenangabe bei SSHAPE muß dann ebenfalls in den aktuell gültigen Werten geschehen. Man muß sich also nicht um die Organisation des Koordinatensystems kümmern, denn durch SSHAPE wird automatisch die Umrechnung auf den normalen Bildschirm vorgenommen. Lediglich bei der Berechnung der Stringlänge müssen einige Korrekturen eingefügt werden.

Nehmen wir an, wir hätten durch SCALE 1,XM,YM ein System definiert, dann liegen (im Hochauflösungsmodus) die Vergrößerungsfaktoren

FX = XM/320

FY = YM/200

vor und die Beziehungen für die Stringlänge lauten dann:

Hochauflösungsmodus:

Lh = INT((ABS(DX*320/XM) + 1)/8 + .99)* (ABS(DY*200/YM) + 1) + 4

Multicolormodus:

Lm = INT((ABS(DX*160/XM) + 1)/4 + .99)* (ABS(DY*200/YM) + 1) + 4

DX und DY sind dabei im aktuellen Koordinatensystem geltende Werte.

Begnügen wir uns nun mit dem SSHAPE-Befehl (es gäbe noch einiges zu untersuchen) und wenden wir uns dem Gegenstück, nämlich dem GSHAPE-Befehl zu.

GSHAPE

Ein durch SSHAPE im String gespeichertes Bild kann durch diesen Befehl nun wieder auf dem Bildschirm dargestellt werden:

GSHAPE A$,X,Y,M

A$ ist der uns nun schon bekannte Speicherstring, der durch SSHAPE definiert wurde. Es kann jede Stringvariable oder ein String-Array-Element verwendet werden.

X,Y sind die Koordinaten im aktuellen System, an die die linke obere Ecke unseres Shapes gelegt werden soll.

Interessant ist die Angabe von M. Hier dreht es sich um einen Darstellungsmodus, von dem es hier vier Möglichkeiten gibt:

M = 0: Unser Shape wird genauso abgebildet, wie es definiert wurde. Schon an dieser Stelle auf dem Bildschirm vorhandene Objekte werden überdeckt. Dasselbe ergibt sich, wenn wir diesen Parameter einfach weglassen.

M = 1: Das Shape wird invertiert abgebildet. Auch hier überdeckt das Shape vorhandene Objekte.

M = 2: OR-Modus: Bildpunkte werden sichtbar, wenn sie zum Shape oder zu vorhandenen Objekten gehören. Beide Bilder überlagern sich so.

M = 3: AND-Modus:Bildpunkte werden nur dann gesetzt, wenn sie sowohl zum Shape als auch zum Bildschirmobjekt gehören.

M = 4: EOR-(oder XOR-) Modus: Bildpunkte werden nur dann gesetzt, wenn das entsprechende Bit für Shape und Bildschirmobjekt ungleich ist.

Die Modi 2, 3, 4 sind etwas schwer vorstellbar. Zur Verdeutlichung finden Sie hier ein kleines Demonstrationsprogramm namens »GSHAPE-MODI« (Listing 10). Hier wird zuerst ein Shape definiert, dann der gesamte Bildschirm quergestreift und schließlich das soeben erstellte Shape in allen fünf Modi darauf dargestellt. Die Wirkung ist auf diese Weise ganz gut zu erkennen, besonders bei den Modi 2, 3 und 4.

10 rem *** die gshape-modi ***
20 rem erstellen eines shape
30 color0,1:color1,6:color4,1:graphic1,1
40 circle1,10,10,10,10:box1,0,0,20,20:paint1,1,1:paint1,19,1:paint1,1,19
50 paint1,19,19:circle1,10,10,7,7:draw1,10,0to10,20:draw1,0,10to20,10
60 sshapea$,0,0,20,20
70 scnclr1
80 rem bildschirmhintergrund
90 dx=5:dy=5:x=0:y=0
100 do while x<511
110 :x=x+dx:y=y+dy
120 :draw1,0,ytox,0
130 loop
140 rem abbilden des shape
150 fori=0to4
160 :gshapea$,10+55*i,100,i
170 nexti
180 rem kommentar
190 color1,3
200 fori=0to4
210 :b$=right$(str$(i),1)
220 :char1,2+7*i,18,b$
230 nexti
240 char1,1,4,"die gshape-modi und ihre wirkungen:",1
250 char1,1,23,"bitte eine taste"
260 getkeya$
270 graphic0,1
280 end
Listing 10. »GSHAPE-MODI«. Die 5 Shape-Darstellungsformen

Der Modus 4 ist aufgrund der EOR-Behandlung interessant: Wird nämlich auf dieselbe Stelle noch einmal das Shape im Modus 4 gezeichnet, dann verschwindet es ganz und der Bildschirmhintergrund ist wieder vorhanden. Will man Shapes bewegen, ohne Bildschirmobjekte zu zerstören, dann ist diese Darstellungsweise ganz gut dazu geeignet.

Die Frage, wieviele Shapes man definieren und auch darstellen könne, erübrigt sich fast: Beliebig viele, solange der Speicherplatz für die Strings reicht. Und davon haben wir eine ganze Menge! Man könnte sich also eine ganze Bibliothek von Hochauflösungs- oder Multicolorobjekten zulegen und diese dann bei Bedarf abrufen. Sollte für ein Objekt der String zu kurz sein, können - ebenso wie wir es bei den Sprites schon praktiziert haben - mehrere Shapes gekoppelt werden. Sie erkennen schon: Auch hier sind die Möglichkeiten sehr breit.

Zusammenspiel von SSHAPE und GSHAPE.

Eine Frage haben wir noch offen gelassen, die eine recht verlockende Konsequenz in sich birgt: Wenn man mittels der SCALE-Anweisung die Systeme bei SSHAPE (also beim Aufbau des Shapes) und bei GSHAPE (bei der Abbildung) unterschiedlich wählt, kann man dann Shapes verkleinern oder vergrößern?

Die Antwort ist leider nein. Bei GSHAPE werden nur die Koordinaten eines (des linken oberen) Eckpunktes angegeben. Lediglich auf den Darstellungsort hat somit ein unterschiedliches Koordinatensystem eine Wirkung, nicht aber auf die Shape-Größe.

Bewegen von Shapes

Im Gegensatz zu den Sprites ist das Bewegen von Shapes eine langweilige Angelegenheit. Jedem Shape-Aufbau durch GSHAPE kann man ganz geruhsam zusehen. Zwar ist es durch Sequenzen wie: FOR I = 0 TO 200 GSHAPE A$,I,I,4 GSHAPE A$,I,I,4 NEXT I möglich, Shapes ohne Schaden für den Bildschirminhalt über den Sichtbereich ziehen zu lassen. Das ganze ähnelt aber bei weitem nicht der Sprite-Bewegung. Aus diesem Grund ist es anzuraten, bei der Bewegung von Bildschirmobjekten - wann immer möglich - Sprites zu wählen.

Shapes der Nachwelt erhalten

Wir stehen bei den Shapes demselben Problem gegenüber wie bei den Sprites. Auf welche Weise kann ein einmal erstelltes Shape für weiteren Gebrauch beiseitegelegt werden?

1. Shapes im Speicher

a. Der Shape-String

Durch SSHAPE wurde ein String geschaffen, der die gleiche Lebensdauer hat wie jede andere Variable: RUN und CLR löschen ihn.

b. Shape im Sprite-Speicher

Wir werden später eine Möglichkeit kennenlernen, die es unter gewissen Umständen erlaubt, ein Shape zum Sprite zu machen. Auf diese Weise gelangt das Muster dazu dann in den Speicherraum, der den Sprites vorbehalten ist und überlebt, bis der Computer abgeschaltet oder der Speicher überschrieben wird.

2. Shapes auf Diskette oder Kassette

Damit wird es nun wirklich interessant. Der Massenspeicher kann Shapes »auf ewig« festhalten.

a. Shape-Strings direkt

Im Grunde genommen sollte es möglich sein, den durch SSHAPE definierten String direkt als sequentiellen File auf Diskette oder Kassette abzulegen und zu lesen. Allerdings ergeben sich hier - wie auch schon bei den Sprite-Strings - Schwierigkeiten beim Lesen. Weil im Prinzip alle Bytewerte von 0 bis 255 auftreten können, also auch ein Wert, der einem RETURN oder einem Anführungszeichen entspricht, wird der String nicht immer vollständig und fehlerfrei gelesen. Dazu kommt das Problem, daß die Shape-Strings unterschiedliche Längen aufweisen können. Wie bestimmt man das Ende eines solchen Files?

b. Als ASCII-Werte speichern

Ebenfalls bei den Sprites wurde diese Möglichkeit schon angedeutet: den Shape-String auseinander zu nehmen und jedes Byte in Form seines ASCII-Wertes zu speichern. Eine Variante dieses Verfahrens zeigt Ihnen das Listing 11 »SHAPE SPEICHERN«. Hier wird zuerst ein Shape (einfach ein Kreis) erzeugt und in A$ abgelegt. Ein Unterprogramm druckt auf dem Textbildschirm (für Benutzer von 2 Bildschirmen sofort, für andere erst später sichtbar) die ASCII-Werte des Strings aus. In Zeile 40 wird der alte File SHAPE1 gelöscht und dann ab Zeile 50 der neue auf Diskette abgelegt. Benutzen Sie eine Datasette, dann sind lediglich in den Zeilen 60, 80, 120 und 180 die DOPEN und DCLOSE gegen OPEN und CLOSE mit den entsprechenden Gerätenummern auszutauschen. Nun sind wir eigentlich schon fertig: In Zeile 100 löschen wir alle Variablen, den Grafikbildschirm und starten den zweiten Teil des Programmes, der nur zur Kontrolle den File einliest und unser Shape abbildet. Zusätzlich werden auf dem Textbildschirm wieder die Stringlänge und die eingelesenen ASCII-Werte abgebildet. Beide Ausdrucke lassen sich gut vergleichen (Benutzer eines Bildschirmes kommen in diesen Genuß, wenn sie nach Ende des Programmes durch GRAPHIC0 den Textbildschirm einschalten). c. Eine unorthodoxe Lösung

10 rem***** shape erstellen *****
20 color0,1:color4,1:color1,6:graphic1,1:b$=chr$(13)
30 circle1,10,10,10,10:sshapea$,0,0,20,20:gosub230
40 scratch"shape1"
50 rem***** shapes auf diskette speichern *****
60 dopen#1,"shape1",w:print#1
70 fori=1tolen(a$):print#1,asc(mid$(a$,i,1))b$:nexti:print#1,"ende"b$
80 dclose#1
90 rem***** variable loeschen und neustart *****
100 clr:graphic1,1:sleep2:run120
110 rem***** shapes wieder von diskette holen *****
120 dopen#1,"shape1"
130 do
140 :input#1,b$
150 ::if b$="ende" then exit
160 :b=val(b$):b$=chr$(b):a$=a$+b$
170 loop
180 dclose#1:gosub230
190 rem***** shape zeichnen *****
200 gshapea$,100,100
210 end
220 rem***** kontrollunterprogramm *****
230 fori=1tolen(a$):printasc(mid$(a$,i,1));:nexti:print:printlen(a$):return
Listing 11. »SHAPE SPEICHERN«. Shapes retten auf Diskette oder Kassette

Etwas exotisch und daher hier nur kurz skizziert ist die folgende Vorgehensweise: Mittels des POINTER-Befehls (hier also POINTER(A$)) sucht man in BANK 1 den Stringdescriptor. Die dort genannte Adresse und Länge verhilft uns dazu, den Speicherbereich, in dem wir unseren String stehen haben, durch BSAVE abzuspeichern.

Beim Wiedereinladen müßte man zunächst einen String definieren, dann durch BLOAD dessen Inhalt an eine beliebige Speicherstelle packen und den Stringdesciptor darauf richten.

Das erscheint im ersten Moment ziemlich kompliziert zu sein, könnte aber - besonders bei Verwendung vieler Shapes - schneller funktionieren. Damit würde beispielsweise ein festgelegter Speicherbereich für alle Shapes en bloc ein- oder auslesbar werden. Probieren Sie's doch mal!

3. Shapes für ein Listing

a. Als Zeichenvorschrift

Häufig werden Shapes durch einige wenige Grafik-Befehle erstellt. Die einfachste Methode - der wir uns auch bisher bedient haben in den Beispielprogrammen - ist es daher, die Zeichenvorschrift ins Programm einzuarbeiten. Manchmal stößt man damit aber an Grenzen: Wenn beispielsweise der Ausschnitt eines Multicolorbildes als Shape verwendet werden soll, das auf dem Grafiktablett erstellt wurde oder wenn es sich um ein Teil eines Fractals handelt, das 25 Stunden bis zur Fertigstellung dauert etc.

b. Shapes in DATA-Zeilen

Ähnlich wie wir bei Sprites einen DATA-Generator verwendet haben, der sich nach seiner Verwendung selbsttätig löscht, geschieht das nun hier auch. Im Programm »SHAPE DATA« (Listing 12) ist außerdem noch ein kleiner Testteil enthalten.

1 rem ****** erzeugung von data-zeilen aus shape-strings (hier a$) ******
2 rem
3 rem ****** probeshape erzeugen ******
4 rem
5 color0,1:color4,1:color1,6:graphic1,1:circle1,10,10,10,10:sshapea$,0,0,20,20
6 stop
7 rem ****** erzeugen der datazeilen ******
8 goto63000
9 rem ****** neues programm zur kontrolle der datas ******
10 color0,1:color4,1:color1,3:graphic1,1:gosub63015
15 gshapec$,100,100
20 end
62999 rem ****** es folgt der datagenerator bzw die datas ******
63000 printchr$(147)63020"data"len(a$)
63001 i=1:k=0
63002 do
63003 :z=0:print63021+k"data";
63004 :do while i<len(a$)
63005 ::printasc(mid$(a$,i,1))",";:i=i+1:z=z+1
63006 ::ifz=10thenexit
63007 :loop
63008 :printasc(mid$(a$,i,1)):i=i+1:k=k+1
63009 loop while i<len(a$)
63010 print63021+k"data"asc(mid$(a$,i,1))
63011 print"63015 reada:fori=1toa:readb:b$=chr$(b):c$=c$+b$:nexti:return"
63012 print"delete63000-63012"
Listing 12. »SHAPE DATA«. Shapes in DATA-Zeilen ablegen

Wie gehabt, wird hier zuerst ein Shape (ein Kreis) erzeugt, dann endet das Programm an einem STOP in Zeile 6. Wenn Sie mit dem 40-Zeichen-Bildschirm arbeiten, dann fügen Sie bitte vor das STOP-Kommando noch ein GRAPHIC 0 ein, denn alles, was nun folgt, ist Text. Das STOP-Kommando wurde eingebaut, um Ihnen die Möglichkeit zu geben, an dem Shape vor dem Aufruf des DATA-Generators noch etwas zu verändern. Ist alles in Ordnung, dann geben Sie bitte CONT ein. Der DATA-Generator erzeugt nun acht Zeilen mit DATAs und dazu noch das Einleseunterprogramm sowie die Löschanweisung DELETE 63000-63012.

Die erste Zahl in den DATAs ist die Stringlänge, die als A später beim Auslesen und Zusammenfügen des Shape-Strings eine wichtige Rolle spielt. Ist das Programm mit dem Ausdrucken der neuen Zeilen fertig, dann bricht es ab. Durch die HOME-Taste gelangen Sie in die erste Zeile. Mittels mehrfach wiederholtem RETURN können nun alle neuen Zeilen ins Programm übernommen und der Generator gelöscht werden. Hinterher sieht unser Programm dann aus wie in »SHAPE DATA 2« (Listing 13). Zur Kontrolle lassen Sie doch mal dieses Programm durch RUN 10 starten. RUN löscht ja auch die Strings, so daß das nunmehr gezeichnete Shape aus den DATA-Zeilen wiederauferstanden ist.

Die Vorgehensweise bei diesem Programm ist dieselbe wie beim DATA-Generator für die Sprites. Allerdings werden hier die Werte nicht aus dem Speicher, sondern aus einem String geholt, der deshalb auch schon durch einen - zumindest teilweisen - Programmlauf definiert worden sein muß.

Wenn Sie mehrere Shapes auf diese Weise festhalten wollen, ist das Programm relativ einfach umzubauen, am besten mittels eines String-Arrays und einer weiteren Schleife.

Wenden wir uns nun dem Zusammenspiel von Sprites und Shapes zu:

Shapes und Sprites

Erzeugen von Sprites aus Shapes.

Anstatt mit dem SPRDEF-Befehl können Sprites auch regelrecht gezeichnet werden durch Grafik-Befehle im Hochauflösungs- oder im Mehrfarbenmodus. Die Nahtstelle zwischen Sprite und Shape ist dabei der String, in den unsere Zeichnung zuerst als ein Shape (mittels SSHAPE) eingeschrieben wird. Von dort ist es dann durch SPRSAV in den Sprite-Speicher zu übertragen.

Eine Regel ist dabei zu beachten: Der Sprite-String liegt in seiner Länge fest. Im Normalmodus müssen wir immer von einem 24 mal 21 (das ist X mal Y) Raster ausgehen, im Mehrfarbenmodus vom 12 mal 21 Muster. Eine SSHAPE-Anweisung muß daher - falls wir ein Sprite konstruieren wollen - im Normalmodus lauten:

SSHAPE A$,X,Y,X+23,Y+20

und im Multicolormodus:

SSHAPE A$,X,Y,X+11,Y+20

X und Y sollen die Koordinaten der linken oberen Ecke des gewünschten Bildausschnittes sein.

Ist SSHAPE nicht in diesem Raster erstellt worden, kann sich allerlei Unsinn auf dem Bildschirm abspielen.

Ein kleines Demoprogramm (Listing 13) namens »SHAPE UND SPRITE« spielt diese Option durch. Zunächst wird ein Multicolorshape erzeugt und in Sprite 1 geschrieben. Eine Umstellung vom Multicolor- in den Hochauflösungsmodus zeigt, daß das Sprite seine Farben behält, das Shape dagegen nicht. Ein zweites Shape erzeugt Sprite 2, die beide über den Bildschirm bewegt werden. Falls Sie nach Programmende mittels GRAPHIC 0 noch auf den Textbildschirm (40 Zeichen) umschalten, sehen Sie noch einen Unterschied zwischen Shapes und Sprites: Letztere bleiben auch hier aktiv.

10 rem ***** shapes zu sprites umwandeln *****
15 rem********** multicolor-sprites **********
20 color0,1:color1,6:color2,2:color3,3:color4,1:color5,2
30 graphic3,1:circle1,5,10,5,10:box2,0,0,10,20:draw3,0,10to10,10
40 draw3,5,0to5,20
50 sshapea$,0,0,11,20
60 sprsava$,1:sprcolor6,3:movspr1,100,100:sprite1,1,2,0,0,0,1
65 sleep2
70 rem********** normaler hiressprite **********
80 graphic1,1:circle1,50,10,10,10:circle1,50,10,7,7:circle1,50,10,4,4
90 sshapeb$,40,0,63,20:gshapea$,0,0
100 sprsavb$,2:movspr2,200,200:sprite2,1,6
110 movspr1,0#4:movspr2,90#8
Listing 13. »SHAPE UND SPRITE«. Shapes werden zu Sprites

Shapes aus Sprites bauen

Natürlich ist auch der umgekehrte Weg möglich: Nämlich Shapes aus Sprites zu konstruieren. Fügen Sie einfach mal an unser letztes Programm aus Listing 13 »SHAPE UND SPRITE« folgende Zeilen an:

130 CLR :REM LOESCHEN DER STRINGS

150 SPRSAV 1,A$:SPRSAV 2,B$

160 GSHAPE A$,150,100:GSHAPE B$,200,100

Über den Sinngehalt solch einer Zuordnung läßt sich natürlich streiten. Denkbar wäre es, das anzuwenden bei Speicherung eines Shape-Musters im Spritespeicher und anschließendem Zurücklesen dieser Information. Darüber hatten wir oben bei Aufbewahrung von Shapes für die Nachwelt schon kurz nachgedacht.

Wenn Shapes und Sprites zusammenstoßen

Kollisionen von Sprites mit Shapes werden vom Computer ebenso registriert, als wären es Zusammenstöße mit Textbestandteilen. Sowohl der COLLISION- als auch der BUMP Befehl können verwendet werden. In einer erweiterten Version unseres Programmes »SHAPE UND SPRITE« namens »SHAPE/ SPR-KOLL« (Listing 14) werden alle Möglichkeiten, die wir in den letzten Abschnitten besprochen haben, ausprobiert. Dabei findet der COLLISION-Befehl Anwendung und Sprite 1 ist durch einen Joystick in Port 2 steuerbar. Bei jedem Zusammenstoß wechselt das Sprite die Farben.

10 rem ***** kollision von sprites und shapes *****
20 rem ***** shapes zu sprites umwandeln *****
30 rem********** multicolor-sprites **********
40 color0,1:color1,6:color2,2:color3,3:color4,1:color5,2
50 graphic3,1:circle1,5,10,5,10:box2,0,0,10,20:draw3,0,10to10,10
60 draw3,5,0to5,20
70 sshapea$,0,0,11,20
80 sprsava$,1:sprcolor6,3:movspr1,100,100:sprite1,1,2,0,0,0,1
90 sleep2
100 rem********** normaler hiressprite **********
110 graphic1,1:circle1,50,10,10,10:circle1,50,10,7,7:circle1,50,10,4,4
120 sshapeb$,40,0,63,20:gshapea$,0,0
130 sprsavb$,2:movspr2,200,200:sprite2,1,6
140 movspr1,0#4:movspr2,90#8
150 sleep2
160 rem********** loeschen der strings **********
170 clr
180 rem********** uebertragen von sprites in shapes **********
190 sprsav1,a$:sprsav2,b$
200 gshapea$,150,100:gshapeb$,200,100
210 rem********** steuern von sprite 1 **********
220 char1,20,0,"joystick port 2"
230 rem********** kollision m. shapes **********
240 movspr1,0#0
250 x=rsppos(1,0):y=rsppos(1,1):i=6:j=3
260 collision2,370
270 onjoy(2)gosub290,300,310,320,330,340,350,360
280 goto270
290 y=y-2:movspr1,x,y:return
300 x=x+1:y=y-1:movspr1,x,y:return
310 x=x+2:movspr1,x,y:return
320 x=x+1:y=y+1:movspr1,x,y:return
330 y=y+2:movspr1,x,y:return
340 x=x-1:y=y+1:movspr1,x,y:return
350 x=x-2:movspr1,x,y:return
360 x=x-1:y=y-1:movspr1,x,y:return
370 collision2
380 i=i+1:ifi>16theni=1
390 j=j+3:ifj>16thenj=1
400 sprcolori,j
410 collision2,370
420 return
Listing 14. »SHAPE/SPR-KOLL«. Zusammenspiel von Sprites und Shapes

Wann Shapes und wann Sprites?

Jeder von Ihnen kann eigentlich nun die Frage beantworten, wann welches der beiden Grafikobjekte sinnvoll einzusetzen ist: Shapes und Sprites.

Nun sind Ihrer Phantasie keine Grenzen gesetzt: Bauen Sie sich ein Menü, in dem mit einem Sprite in Pfeil- oder Handform auf Symbole (Shapes) gedeutet wird, oder basteln Sie sich Schaltpläne aus vorgefertigten Einzelteilen (Shapes) zusammen, die Sie mit einem Kran-Sprite aussuchen und plazieren oder, oder.

(H.Ponnath/og)
PDF Diesen Artikel als PDF herunterladen
Mastodon Diesen Artikel auf Mastodon teilen
← Vorheriger ArtikelNächster Artikel →