Home - Über mich - Bugastadt 2001 - Ausflüge & Reisen - Texte - Alles Kino - Theater & Kabarett - Gabi gucken - Credits |
Foto: Uwe Pirr Informatik |
Programmieren in HyperTalk, Teil VIIAbb.: 1: Im Kerker des Grauens
Die Spiel-IdeeDas Spielfeld ist in 16 x 10 Felder von je 32 Pixel Breite unterteilt. Der Spieler sieht nur die acht Felder um sich herum, alle anderen sind schwarz. Erst wenn er die anderen Felder besucht hat, werden sie für ihn sichtbar. Jeder Level besteht aus einigen Räumen, die miteinander verbunden sind (sich auch überschneiden können - das gibt dem Labyrinth einen verwinkelten Charakter). Auf dem Spielfeld sind Schätze verteilt, die es zu sammeln gilt. Daneben sind die Höhlen von Trollen bewohnt, die unseren Helden angreifen und ihn verfolgen, wenn er nahe genug an sie herangekommen ist, daß sie ihn "riechen". Wenn unser Hero die Trolle angreift oder von ihnen angegriffen wird, besteht eine 50%ige Wahrscheinlichkeit, daß er sie besiegt. Verliert er, bekommt er einen Lebenspunkt abgezogen.Das Spiel endet, wenn der Spieler keine Lebenspunkte mehr besitzt (oder wenn der Panic-Button gedrückt wird). Hat er dagegen "lebend" den Ausgang erreicht, erzeugt unser Programm ein neues zufälliges Labyrinth, indem sich unser Held erneut bewähren muß. Die GrafikWer den Kurs bis hierhin verfolgt hat, kann sich sicher denken, warum die einzelnen Spielfelder 32 x 32 Pixel groß sind. Das ist genau die Größe eines Icons für einen Button. Jedes Spielfeld ist daher als Button realisiert, daß bei entsprechenden Spielzügen mitset the icon of cd button <Name> to <Icon>sein Aussehen verändert. Die "Bewegungen" sind daher etwas sprunghaft. Außerdem habe ich für jeden Akteur nur ein Icon vorgesehen. Wenn Sie das Spiel etwas ausbauen wollen, können Sie weitere Icons erzeugen, die die Akteure in ihrer jeweiligen Bewegungsrichtung zeigen. Abb. 2 zeigt die verwendeten Icons (bis auf das blackTile, das ist einfach nur ein schwarzes Feld).:
Abb 2: Die verwendeten Icons
put 128 into kPlayerTileAus Performance-Gründen habe ich diesmal darauf verzichtet, Konstanten als Funktionen zu deklarieren. Um sie wenigstens ein bißchen sicherer zu machen, habe ich sie nach guter alter C-Sitte mit einem kleinen, vorangestellten "k" versehen. Globale Container sind ebenfalls mit einem vorangestellten "g" kenntlich gemacht. Der SoundEin Spiel ohne Sound ist nichts. In unserem Stack werden folgende Geräusche verwendet:IntroSound: Geheimnisvolle Musik zu Beginn des Spiels ExitSound: Triumphmarsch, wenn der Level verlassen wird GetMoney: Klirrend wird das Geld eingesackt HeroAttacks: Schwerter klirren beim Angriff unseres Helden MonsterAttacks: Ein Urschrei, den das Monster ausstößt. MonsterDied: Trolle sterben ziemlich geräuschvoll HeroDied: Und auch bei Helden geht der Tod nicht geräuschlos abAlle diese Geräusche habe ich von verschiedenen PD- und Shareware-CD's "geborgt" und ebenfalls mit Hilfe von ResEdit in den Stack kopiert. Der Stack wird erstelltEs ist ziemlich umständlich, 160 Buttons (16 x 10) per Hand zu erstellen und exakt zu positionieren. Daher lassen wir das HyperTalk erledigen. In einer doppelten Schleife berechnen wir mitput (i*kTileSize) - (kTileSize DIV 2) into item 1 of tileLoc put (j*kTileSize) - (kTileSize DIV 2) into item 2 of tileLocdie Koordinaten der einzelnen Felder. Anschließend rufen wir per Programm dein Menüeintrag New Button auf, setzen ihn auf seine richtige Größe, legen seinen Stil (transparent) fest und positionieren ihn. Mit set the name of card Button "New Button" to i & ", " & jgeben wir ihm auch gleich einen Namen, der seinen Koordinaten entspricht. Hier wird wieder der Umstand ausgenutzt, daß HyperTalk nur den Datentyp Text kennt. So können wir jedes Spielfeld ohne große Konvertierung über seine Koordinaten ansprechen. Ich habe im Text die Befehle lock Screen und unlock Screen auskommentiert. Sie beschleunigen den Bildaufbau beträchtlich (im eigentlichen Spielprogramm wird daher von ihnen Gebrauch gemacht), hier ist es jedoch ganz witzig, zu sehen, wie das Programm die Buttons nacheinander erstellt. Da die 160 Buttons den Standardstapel nicht komplett füllen, habe ich den unteren Rand (wo auch der Panic-Knopf liegt) einfach mit Hilfe des Zeichentools schwarz eingefärbt. Das SpielprogrammDas Spielprogramm besteht im Prinzip aus drei großen Handles, die sich nacheinander aufrufen (Abb. 3). Zuerst fängt ein mouseUp alle Klicks ein, die nicht vom Panic-Button absorbiert werden. Dies prüft dann auch sofort, in welchem Button der Klick stattgefunden hat und weist diesen Button-Namen als Koordinate an das Handle movePlayer weiter.
Abb 3: Flowchart unseres HyperTalk-Programmes
Dies fragt einfach alle Spielfelder ab, ob sich ein Troll auf ihm befindet. Wenn nicht, wird er bewegt. Hier entsteht eine Schwierigkeit. Da ein Troll von hier auf ein noch nicht abgefragtes Feld bewegt werden kann, wird er eventuell mehrmals bewegt. Um dem vorzubeugen, wird der neue Trollplatz erst einmal mit der Konstanten kTempTroll belegt, die von dieser Schleife über das Spielfeld ignoriert wird. Erst in einer zweiten Schleife werden alle "temporären" Trolle in "echte" Trolle zurückverwandelt. Auch dieser Programmteil prüft ab, ob unser Hero einen eventuellen Angriff der Trolle überlebt hat und beendet gegebenenfalls das Spiel. Dabei ist es fast wie im "richtigen Krieg". Das Programm läßt es ohne weiteres zu, daß mehrere Trolle (quasi) gleichzeitig angreifen, oder das ein Angriff unseres Helden auf einen Troll erfolgt, der seinerseits beschlossen hat, unseren Spieler anzugreifen. Während nun bei einem erfolgreichen Angriff des Spielers dieser seinen Platz auf dem des Trolls einnimmt, bleibt er bei einer erfolgreichen Abwehr eines Trollangriffs auf seinem Spielfeld. Wenn nun beides gleichzeitig erfolgt, kann es sein, daß der Zufallszahlengenerator beide Angriffe als mißlungen bezeichnet. Wenn nun unser Held dabei auch noch überlebt, ist der Troll zwar tot (Trolle haben - im Gegensatz zum Spieler - nur ein Leben), trotzdem bleibt er auf seinem Platz, obwohl wir ihm Angriff befohlen haben. Dieses Verhalten mag zwar zu verwirren, ist aber spielemäßig völlig korrekt. Ein neues Labyrinth wird erzeugtAbb 4: Im Halbdunkel
Dabei wird zuerst die Anzahl der Räume ausgewürfelt und deren obere Kante und Größe bestimmt. Dann werden diese Räume gezeichnet. In den meisten Fällen überlappen sie sich auf so einem kleinen Spielfeld wie dem unseren und sind daher schon miteinander verbunden. (Daher ist es etwas vermessen, von einem Labyrinth zu sprechen.) Unser Programm prüft dies jedoch nicht ab, sondern zeichnet einfach noch einen Weg von jedem Raum zum nächsten ein. Dabei wird zufällig ein Punkt im ersten Raum ausgewählt und ein Punkt im nächsten. Dann wird solange geradeaus gegangen (entweder von rechts nach links oder umgekehrt) bis die x-Koordinate des zweiten Raums erreicht ist. Dann wird in die vertikale gewechselt und das Programm wählt einen Weg auf- oder abwärts, bis auch die y-Koordinate erreicht wurde. So können, wie Abb. 4 zeigt, auch einmal Mauerstücke im Raum stehenbleiben und in den meisten Fällen werden die Räume verwinkelter und interessanter, als sie es ohne diesen zusätzlichen Weg wären. Das Erzeugen dieses neuen Labyrinthes ist für HyperCard schon ziemlich aufwendig und Sie sollten eine entsprechend lange Titel- und Übergangsmusik auswählen, um beim Spieler keine Ungeduld aufkommen zu lassen. Die HilfsroutinenNeben der Funktion numberOfRooms, die nur eine Zufallszahl zwischen drei und sechs zurückgibt, gibt es noch zwei größere Unterprogramme: showAroundPlayer prüft nach, ob die acht Spielfelder um den Spieler herum noch unsichtbar sind und macht sie gegebenenfalls sichtbar. drawTile übernimmt die eigentliche Zeichenfunktion der Spielfelder und ist vor allem deswegen ausgelagert, weil es nicht zwingend ist, die Spielfelder als Icons von Buttons darzustellen. Sie sind z.B. auch als PICT-Ressourcen vorstellbar. In diesem Fall könnten sie mit Hilfe der Color-Tools von HyperCard 2.3 auch in Farbe dargestellt werden. Ich gebe zu, ich habe dies getestet, weil es meine ursprüngliche Intention zu diesem Artikel war, auf die Farbfähigkeit von HyperCard einzugehen. Die Spielzüge wurden dann aber selbst auf meinem PowerMac unerträglich langsam, von der Initialisierung des Spielfeldes wollen wir gar nicht erst reden. Mein bisheriger Eindruck, daß Farbe in HyperTalk-Programmen momentan noch nicht einsetzbar ist, hat sich wieder bestätigt. (Dies gilt nicht in gleichem Maße für HyperCard-Anwendungen: Wenn die Farbe direkt in den Stack gesetzt wird und nicht oder nur in geringem Maße von einem HyperTalk-Script beeinflußt wird, sind durchaus ansprechbare Ergebnisse zu erzielen.) Wir Programmierer müssen daher (wieder einmal) auf HyperCard 3.0 hoffen.OptimierungWenn Sie selber solch ein oder ein ähnliches Programm entwickeln wollen, sollten Sie, um Fehler zu finden, erst einmal alle strukturierten Variablen (Arrays und Records) in Felder schreiben. In unserem Spiel sind das folgende:gTileArraygTileArray enthält die einzelne Spielfeldbelegung, gTileKnown "weiß", ob ein Feld sichtbar oder unsichtbar ist und gPlayer enthält die augenblicklichen Koordinaten des Spielers und seine Lebenspunkte. (Hier können Sie bei einer entsprechenden Erweiterung des Spieles zum Beispiel auch Pluspunkte für gesammelte Schätze oder mitgenommene Gegenstände usw. aufnehmen.) Nach erfolgter - hoffentlich erfolgreicher - Fehlersuche sollten diese Felder jedoch in globale Container umgewandelt werden, um die Geschwindigkeit des Programms zu erhöhen. Und achten sie bitte darauf, daß dann auch alle Felder wieder von Ihrer Karte gelöscht werden. Das Schreiben und Suchen von Feldern kostet HyperTalk unheimlich viel Zeit. Und da wir hier an die Grenze der Leistungsfähigkeit vorgestoßen sind, müssen wir leider Programmiersicherheit gegen Schnelligkeit eintauschen. Ähnliches gilt auch für das Array kTileSize, das die Richtungskoordinaten eines Zuges enthält. Unter normalen Umständen hätte ich auch diese Angaben in ein Feld geschrieben, statt sie mühselig mit put-Anweisungen im Quellcode zu initialisieren. Aber auch hierbei ist der Geschwindigkeitsvorteil nicht zu unterschätzen. Zu guter Letzt werden alle Bildschirmausgaben vorgenommen, wenn lockScreen gesetzt ist, so daß ein Redraw erst stattfindet, wenn alle Änderungen HyperCard bekannt sind. Auch dies beschleunigt HyperCard signifikant. Um dem Benutzer dennoch mitzuteilen, daß etwas passiert und sein Rechner nicht abgestürzt ist, mach ich ihn mit set cursor to watch(dieser Befehl zeigt den Cursor als Uhr) darauf aufmerksam, daß er noch warten möchte. Mit set cursor to fingerwird er wieder auf seine normale Form (browse tool) zurückgesetzt. An dieser Stelle ist anzumerken, daß viele HyperTalk-Manuals dieses falsch behandeln. Sie geben an, daß der Befehl set cursor to hand hieße. Dieser Befehl macht den Cursor aber zu einer flachen Hand, wie sie beim Verschieben von Bildern gezeigt wird und nicht zum Zeigefinger. ErweiterungenIn der abgedruckten Version kann der Spieler in den meisten Fällen den Trollen entkommen und wird so schnell langweilig. Daher kann auch dieses Programm von Ihnen natürlich ausgebaut werden. Im schon erwähnten Artikel von Dewdney finden Sie viele Anregungen. Andere Monster sind denkbar, die unterschiedliche Verhalten an den Tag legen (Urige Ungetüme, Greifen oder ähnliches). Ihr Held kann Zaubersprüche finden oder Amulette. Herumliegende Nahrung kann seine Lebenspunkte aufbessern, Zaubertränke ihm, wie bei Asterix und Obelix, ungeahnte Kräfte verleihen. Versteckte oder sichtbare Falltüren können ihn Level überspringen lassen oder auch in gefährliche Situation bringen. Er kann Waffen und Rüstungen finden oder Tarnkappen, die ihn unsichtbar gegenüber seinen Gegnern machen (außer den Trollen natürlich, die haben bekanntlich einen unübertrefflichen Riecher für Menschenfleisch). Zwei Dinge sind bei solchen Erweiterungen zu beachten:Sie müssen die Variable gPlayer entsprechend erweitern, um Punktstände, Nahrungsvorräte und Rüstungen oder Waffen mitzuführen und sie sollten für jeden Level eine eigene Karte anlegen, auf dem die level-spezifischen Programmteile zu finden sind. Falls Sie andere Hintergründe benötigen, sollten Sie diese Level sogar jeweils in eigene Stacks auslagern. Ansonsten wird Ihr Spiel zu langsam und das Spielen macht keinen Spaß mehr. Viele andere Spiele bauen auf ähnlichen Rastern auf. So könnten Sie sich auch einmal an das bekannte MineSweeper, an das Kistenschiebespiel Sokoban oder an Othello versuchen. Viel Spaß! Damit Sie das Programm nachverfolgen können, hier das eigentliche Programmlisting und das Listing des Panic-Buttons.
Wie weiter?In dieser letzten Folge meines kleinen HyperTalk-Kurses wollte ich zeigen, daß durchaus ansprechende Programme mit HyperTalk programmiert werden können. (Na gut, daß mit den Bildern der Icons übe ich noch - ich bin nun mal kein Grafiker. Aber sonst ...). Jetzt liegt alles bei Ihnen - programmieren Sie in HyperTalk und haben Sie genausoviel Spaß dabei, wie ich ihn bei der Abfassung dieses Kurses hatte...© Jörg Kantel, 1997 Literaturliste[1] Jamie McCornack, Ingemar Ragnemalm, Paul Celestin et al.: Tricks of the Mac Game Programming Gurus, Indianapolis, Indiana (Hayden Books) 1995[2] A.K. Dewdney: Im Kerker des Verderbens, in: Ingo Diemer (Hg.): Computer Kurzweil, Reihe: Spektrum der Wissenschaft: Verständliche Forschung, Heidelberg 1988 |
|||||
© 1996 - 2001 by Jörg Kantel Last modified: JK, 04.09.2001; 20:33:33 Uhr email:joerg@kantel.de |