Liebe/-r Experte/-in,
Ich finde im Internet keine klare Antwort
Nun, eigentlich gibt es dazu auch keine „klare Antwort“. Das soll aber nicht heißen, daß es überhaupt keine Antwort dazu gäbe!
Zunächst erst einmal: Auf diese Frage GIBT ES KEINE KURZE ANTWORT!
Man kann diese Frage einfach nicht mit 2 Sätzen beantworten - wer es doch tut, hält dem Fragesteller über 99% der Informationen vor - damit ist keinem geholfen!
Wenn man „Spiele programmieren“ will, sollte man sich klarmachen, welche ART von Spiel man programmieren will - denn es gibt ganz verschiedene SPIELEGENRES und die Programmierung eines Spiels hängt nicht unwesentlich davon ab, welches GENRE das Spiel haben soll. Spontan fallen mir dazu ein:
- Lauf/HüpfSpiel (Jump-n-Run, so etwas wie Mario)
- Action-Shooter (Shoot-em-up, so etwas wie R-Type)
- Fighter (Beat-em-up, so erwas wie Street Fighter)
- Adventures (Click-and-Point-Adventure, so etwas wie Monkey Island)
- Geschicklichkeitsspiele (zu viele, um Namen zu nennen)
- Denkspiele (z.B. Schach oder Kombinatorikspiele)
- Rennspiele (z.B. Autorennen wie Gran Turismo)
- Strategiespiele (z.B. Aufbauspiele oder Kriegssimulationen)
- Glücksspiele
Das klingt vielleicht erst einmal wenig - aber zusätztlich sollte man sich klarmachen, daß es
1.) das ganze auch noch als Kombination von zwei oder mehr dieser Arten gibt
2.) heutzutage die Möglichkeit für 2D oder 3D gibt
3.) heutzutage die Möglichkeit für Singleplayer (1-Spieler) oder Multiplayer (2 bis unendlich Spieler) gibt
4.) heutzutage sowohl für direkt-auf-dem-Computer als auch webbasiert („Browser-Games“) geht
Und das ist noch LANGE nicht alles!
Also sollte man zunächst erst einmal definieren, was für eine ART von Spiel man machen will, ob man ein bestimmtes THEMA haben will (oder eine GESCHICHTE im Spiel), und so weiter.
Natürlich sollte man sich dabei dessen bewußt sein, daß nicht alles, was man machen WILL, auch gleichzeitig in endlicher Zeit für einen einzelnen oder eine kleine Gruppe von Leuten auch MÖGLICH ist. (Beispiel: Man kann zwar „ein Spiel wie World-of-Warcraft“ programmieren WOLLEN, aber dazu braucht man EINIGE HUNDERT hochmotivierte Personen, viel Zeit und viel Fachwissen und Talent.)
Eine kleine Anmerkung [1] dazu - auch wenn es vielleicht etwas böse klingt:
NEIN! Man kann heute KEIN GELD mehr damit VERDIENEN, wenn man heutzutage privat alleine oder mit einer Handvoll Leuten ein Spiel programmiert! - Dazu müßte man wirklich Riesenglück haben und etwas tun, was wirklich noch kein anderer getan hat - d.h. eine bisher komplett unbesetzte Nische bedienen!
Eine weitere Anmerkung [2] :
Spieleprogrammierung ist etwas komplett anderes als Spiele spielen! Es ist Arbeit - die zwar auch Spaß machen kann, aber nur, wenn einem Programmieren oder Texturen malen oder Daten eingeben Spaß macht. (Und ja! - es gibt solche Leute.)
Ein Spiel programmieren dauert in der Regel wesentlich länger als das Spiel durchzuspielen - dessen sollte man sich bewußt sein.
Und: Keiner hat auf ein neues Spiel gewartet und weiß auch nur im Geringsten die Mühe, Arbeit und „Seele“, die man da hineingesteckt hat zu würdigen. Für den normalen Gamer ist es eines unter vielen Spielen und wenn das Spiel nicht etwas besonderes an sich hat, das es nicht auch in anderen Spielen gibt, wird es auch nur eine durchschnittliche Beachtung finden -. wenn überhaupt.
So - das mußte erst einmal gesagt werden, um Dir zu zeigen, worauf Du Dich einläßt.
Aber:
ICH WILL DICH DAMIT KEINESFALLS ENTMUTIGEN; EIN SPIEL ZU SCHREIBEN!
Schon wieder eine Anmerkung [3] :
Ich bin selbst ein privater Spieleprogrammierer. Aber ich programmiere unter MS-DOS. In Borland/Turbo-Pascal und Assembler. Ich programmiere auch alle meine Entwicklungstools selbst und ich lasse mir viel Zeit. Ich weiß genau, daß DOS-Spiele heutzutage nur maximal bis Windows XP (wenn 32bit) laufen (oder in DOSbox). Ich weiß auch genau, daß die 2D-Spiele, die ich schreibe oder zu schreiben gedenke, die große Masse der Spieler-Gemeinschaft überhaupt nicht interessieren und es eher ältere Semester sind, (die 2D-Spiele noch zu schätzen wissen und denen 3D, hochauflösende Grafik und 16 Mio Farben und Realitätsnähe nicht die einzige Kriterien für ein gutes Spiel/Spielspaß sind) die meine Spiele (wenn überhaupt) spielen werden. Für mich ist das Ganze ein Privatvergnügen, weil ich gerne programmiere - und das gerne hardwarenah tue. Aber ich bin mir dessen bewußt, daß ich damit nie Geld verdienen werden - und Geld ist auch nicht der Antrieb für mich.
Ich bin in einigen Computer-/Programmierforen unterwegs und früher habe ich noch ab und zu unverbindlich Anfragen in den Raum gestellt nach Leuten, die eventuell ein Interesse hätten, mit mir zusammen an Spielprojekten zu arbeiten. (Diese Leute müßten nicht einmal selbst programmieren können, denn es gibt bei der Spieleentwicklung ja auch viele andere Dinge zu erledigen.) Ich habe es aber aufgegeben, solche Anmerkungen/Anfragen überhaupt in den Raum zu stellen. Denn ich habe gemerkt, daß NIEMAND Interesse daran hat, irgendeinen wie auch immer gearteten Aufwand zu betreiben einfach nur aus Spaß an der Sache, sondern fast alle Menschen auf der Welt immer als erstes interessiert, was und wieviel man damit verdienen kann und am wann der Rubel rollt.
Viele Menschen sehen Leute wie Bill Gates oder Steve Jobs oder große Softwareschmieden wie Blizzard und sehen, wieviele Milliarden diese scheffeln und wollen NUR AUS DIESEM GRUND Programmierer werden, weil sie gleich Dollarzeichen in den Augen haben (und studieren nur deshalb dann Informatik…) Dabei übersehen die meisten, daß man, um als Programmierer erfolgreich zu sein, erstens sehr gut sein muß und zweitens „diesen Scheiß wirklich LIEBEN MUß“, um wirklich gut zu werden! Alle, für die es (Programmieren) „einfach nur ein Job zum Geldverdienen“ ist, werden NIE richtig gut werden!
OK, das war schon wieder zu viel Information…
DANN GEHT ES JETZT RICHTIG LOS!
******************************************
WIE PROGRAMMIERT MAN EIN SPIEL?
******************************************
Ein Spiel ist im Prinzip auch nichts anderes als jede andere Anwendung. Viele Spiele funktionieren intern wie große Datenbanken mit sich ständig verändernden Werten. Abhängig von diesen Werten werden manche Dinge davon auch grafisch dargestellt.
Ein Beispiel gefällig? Nehmen wir an, man hat ein „Voll-3D“ Spiel. Dann hat eine Spielfigur für ihre Positionierung im 3D-Raum einen Datensatz, der 3 Raum-Koordinaten enthält, nämlich X-, Y- und Z- Position, also wo im „Raumquader“ sich die Figur befindet. (Der „Raumquader“ ist dabei die maximale Ausdehnung des Levels in Breite, Höhe und Tiefe, davon im Bezug befindet sich die Figur mit relativen Koordinaten.) Weiterhin hat die Figur noch 3 Winkel, wie sie gedreht sein kann, sie wird um ihren Schwerpunkt herum um diese Winkel gedreht, wobei der Schwerpunkt selbst sich an den Koordinaten befindet - also noch 3 Werte (die Winkel), ebenfalls im Datensatz der Figur. Weitere Werte im Figurendatensatz sind die Figur selbst - ihre momentane Haltung, d.h. im welchen Winkel die einzelnen Teile der Figur zu den restlichen stehen - also z.B. wasdie Arme oder der Kopf tun. Weiterhin gibt es noch Werte, die auf eine andere Datenbank verweisen. Dort liegen die Grundkoordinaten - „Vektoren“ der einzelnen Flächen/Körper, aus denen die Figur besteht, dann auch die Texturen (die Grafiken), die auf den Flächen liegen … und vieles mehr.
Über die Änderung dieser ganzen Werte (die alle komplett ausschließlich ZAHLENWERTE sind!) kann dann die Bewegung der Figur in sich selbst und innerhalb des Levels („Raums“) gesteuert werden. Wenn Objekte des Levels mit Spielfiguren „kollidieren“ (d.h. sich ihre Koodinaten annähern) oder Spielfiguren untereinander, wird irgendeine entsprechende Reaktion ausgelöst.
Die Sreuerung der Spielfigur (d.h. Änderung ihrer Werte in ihrem Datensatz) erfolgt durch den Spieler, d.h. bestimmten Tasten oder Joystick- oder Pad- oder Mausbewegungen werden bestimmte Zahlenwerte zugeordnet, die dann, abhängig von einer Programmstruktur oder „Reaktionstabelle“ die Werte des Figur-Datensatzes (in diesem Fall der Figur, die dem Spieler zugewiesen ist) verändert.
Die Nicht-Spieler-Figuren (oft werden sie NPCs - Non-Player-Characters - genannt) werden durch eine durch den Programmierer einprogrammierte Logik gesteuert, oft (aber nicht zwingend) dabei bezugnehmend auf die Spielerfigur und deren Datensatz-Werten.
Das klingt jetzt alles sehr theoretisch und mathematisch — ist es auch!
Wo ist nun aber die ganze schicke Grafik? Nun, das Spiel selbst funktioniert auch ohne Grafik - die Grafik ist nur die Darstellung des Spielgeschehens (abhängig von den Datenbank-Werten für das Level und die Figuren) durch farbige Pixel auf dem Bildschirm und dient einzig und allein dazu, dem Spieler auf eine für Menschen leichter verständliche Art die Spielsituation zu präsentieren. Die Grafik nimmt dabei also unabhängig vom Spielgeschehen Bezug auf die aktuelle Spielsituation in den Werten. Umgekehrt passiert dies nicht! - D.h. das Spiel selbst läuft/funktioniert unabhängig von der grafischen Darstellung und wird davon nicht beeinflußt. Die einzige Beeinflussung geschieht durch den Spieler, der seine Steuerungseingaben von den grafischen (und klangtechnischen) Ausgaben abhängig vornimmt.
Das war jetzt viel Theorie - aber genau so oder so ähnlich funktioniert es. Kleine Einschränkung: Auf alten Rechnern wurden teilweise grafische Ausgaben und Spieldaten miteinander verbunden, d.h- das Levelelement, was ausgegeben wurde, war gleichzeitig durch seine Position und Nummer auch „Level-Datum“ und wurde direkt abgefragt, um darauf zu reagieren. (Viele C64-Spiele funktionieren so.)
Um das Komplizierte jetzt etwas einfacher zu machen:
Je weniger „Dimensionen“ ein (Aktions-)Spiel unterstützen muß, umso weniger Daten braucht man und umso einfacher wird es. Ein 2D-Spiel mit „Sprites“ (so etwas wie Mario auf dem Nintendo z.B.) komtm mit 2 Dimensionen aus, jede Figur hat 2 Koordinaten im Level, das Level ist kein „Quader“, sondern ein „Rechteck“, wenn Figuren drehbar sind, dann nur in einem Winkel. Diese „Sprites“ und ihre Bewegungsphasen werden dabei als kleine Grafiken wie ein „Daumenkino“ im Speicher abgelegt - man gibt nur noch an, welche Bewegungsphase gewünscht ist.
Das ist der Grundgedanke - All diese Dinge kann man natürlich beliebig modifizieren, beispielsweise, um es dem Programmierer einfacher zu machen (durch Tabellen oder durch Unterprogramme, die Dinge automatisch tun) oder um Speicher zu sparen (indem bestimmte Dinge zusammengefaßt oder weggelassen werden).
DAS IST ABER ALLES IMMER NOCH ZU THEORETISCH!
Ja, ich weiß!
In der Praxis sieht es so aus, daß man sich erst einmal nach einer geeigneten PROGRAMMIERSPRACHE umsieht… - so wäre es im Idealfall! Die Erfahrung zeigt jedoch, daß die meisten Leute dazu neigen (und zwar aus durchaus berechtigten Gründen), ihre Lieblings-Programmiersprache(n) dazu zu benutzen (bzw die einzige, die sie kennen).
Es gibt gewisse Dinge, die man beachten muß - nämlich, daß manche Programmiersprachen nur für webbasierte (Browser…) Spiele gedacht sind und manche nur für „lokale“ Programmierung (also kein Browsergame) - ja, es gibt da Überschneidungen, trotzdem muß man dann den geeigneten Compiler wählen…
Ansonsten (auch wenn mich einige Leute dafür schlagen werden) ist die Wahl der Programmiersprache beliebig - denn man kann mit fast allen Programmiersprachen auch fast alles tun, was mit anderen Programmiersprachen auch geht - nur eben auf manchen einfacher und auf manchen schwieriger (auf die gestellte Aufgabe bezogen) - was daran liegt, daß bestimmte Programmiersprachen hauptsächlich für bestimmte Zwecke entwickelt wurden und daher für diese dann besonders geeignet sind.
Wenn man ÜBERHAUPT KEINE Programmiersprache oder Skriptsprache beherrscht, kann man nicht programmieren! Die Beherrschung mindestens einer Programmiersprache oder Skriptsprache ist die Mindestvoraussetzung, um überhaupt programmieren zu können - egal ob es ein Spiel oder eine Anwendung ist. (Compilersprachen generieren dabei ein ausführbares Programm, das direkt auf dem jeweiligen System läuft. Interpretersprachen oder Skriptsprachen benötigen zusätzlich noch ein Programm, das das erzeugte Programm „abspielt“.)
Ganz zum Schluß füge ich jetzt noch einmal die ersten beiden Teile meines Textes (auf eine Frage, wie man Programmieren lernt in einem anderen Forum) hier an. Dieser enthält auch ein sehr einfaches Beispiel (aber keine vollständige Beschreibung), wie man herangehen könnte, um ein sehr simples 2D-Spiel zu schreiben.
Bevor ich das jedoch tue, gebe ich Dir noch einen Link auf eine Untersektion meiner Webseite. Dort kannst Du mein Spiel XPYDERZ sehen (und vielleicht auch herunterladen und spielen) und dabei sehen, was man allein mit MS-DOS, Pascal und Assembler, einigen selbstentwickelten Tools und einiges an Arbeit so hinbekommen kann:
http://www.imperial-games.de/html/prea1.htm
Hier nun aber noch der angekündigte Text: Und ja -auch der ist recht lang:
PROGRAMMIEREN - TEIL 1
Ich habe mir Programmieren (verschiedene Rechner, verschiedene Programmiersprachen) quasi selber beigebracht - natürlich mit Hilfe von Büchern und (z.B. im Falle von Pascal) den Hilfe, die in die Programmierumgebung eingebaut ist. Ferner natürlich durch Programmbeispiele und später (seit ich „Internet“ habe/benutze) auch mal mit Online-Tutorial.
Aber vor allem lernt man durch: Machen, Machen, Machen!
Damit meine ich: Nicht nur „Programmieren, um Programmieren zu lernen“, sondern: Ein Projekt (ein Spiel, eine Anwendung, irgendwas) programmieren. Dabei muß man sich automatisch Gedanken machen, wie man dies und jenes umsetzen kann (also: Wie man es in Programmiersprache formulieren muß, um dem dummen binärdenkenden Rechenknecht zu erklären, was er machen soll.)
Zu Anfang denken manche (oder viele) Leute noch, das Schwierige am Programmieren wäre, die ganzen Programmiersprachenbefehle auswendig zu lernen. Aber das ist im Prinzip nicht so schwer und außerdem benutzt man in 90% der Zeit nur 10% der vorhandenen Befehle und in den restlichen 10% der Zeit/des Programms welche aus den vorhandenen restlichen 90%. Klingt komisch - ist aber so. (Und wenn man von denen wirklich mal einen vergißt, kann man den auch mal nachschlagen. Beispiel: In PHP gibt es mittlerweile an die 5000 Befehle/Funktionen und manche sind 20 Zeichen lang - die merkt sich kein Schwein ALLE.)
Nachdem man also so „fit“ in der Programmiersprache ist, daß man die wichtigen Befehle, die zum Aufbau der „Grundgerüste“ nötig sind, kennt, merkt man (so wie Du jetzt gerade), daß es gar nicht um „Befehle büffeln“ geht, sondern vielmehr um die (ja, wir Computerheinis benutzen eben gern dieses Wort dafür) Algorithmen. Damit sind die ganzen Programmabläufe und Programmstrukturen gemeint. Stell’ Dir ein Baugerüst vor: Wenn die ganzen Schrauben, Stangen und Bretter die einzelnen Programmiersprachenbefehle sind, dann ist der Algorithmus das Gerüst. Das Gerüst alleine macht noch keinen Sinn - ein Programm wird es erst, wenn es noch mit Daten gefüllt wird - also den entsprechenden Baumaterialen in dem Fall. Das ist dann das Programm. Das alleine macht auch noch nichts - erst, wenn das Programm gestartet wird - d.h., wenn der (oder die) Bauarbeiter das Gerüst betreten und benutzen. Sind nun entweder falsche Daten (Baumaterialien) da, kann man daraus kein richtiges Haus bauen. Aber: Wenn das Baugerüst fehlerhaft ist (bestimmte Teile fehlen oder irgendwo hinführen, wo gar nicht gebaut werden soll oder in offene Enden), dann macht der Arbeiter bestenfalls etwas anderes, als er machen sollte (baut an einer Stelle, die nicht vorgesehen war usw) und im schlimmstenfalls stürzt er vom Gerüst (zu vergleichen mit einem Rechnerabsturz, wenn so ein Algorithmus eben „offene Enden“ hat.
Ich mache mal ein Beispiel, wie man so einen Algorithmus (den richtigen Programmablauf) zustande kriegt:
Der Neuling will z.B. ein Spiel programmieren. Er kennt die ganzen Befehle seiner Programmiersprache und kann sie auch einzeln für sich verwenden (einzelne Schleifen bauen, einzelne Rechenoperationen durchführen, einzelne Funktionen verwenden). Nun weiß er das alles und er weiß auch, wie das Spiel am Ende aussehen soll. Aber er steht nun vor dieser Aufgabe und weiß gar nicht, wo er anfangen soll. Er ist so wie ein Schriftsteller, der vor einem leeren Blatt Papier sitzt. Er kennt alle Wörter und er kennt auch die Grammatik (so wie der Programmierer die Befehle und die Syntax - so nennt man die Programmiersprachen-Grammatik - kennt). Aber er weiß nicht, wo er anfangen soll, damit es eine Geschichte wird.
Das „Ich programmiere ein Spiel“ ist also ein zu lösendes PROBLEM. Man kann nicht einfach das ganze PROBLEM nehmen und es so lange prügeln, bis ein Spiel rauskommt - das versuchen manche vielleicht, indem sie hin und her Zeug eintippen, bis irgendwann irgendwas passiert. Die (meiner Meinung nach) bessere Methode ist, das große Problem in viele kleine TEILPROBLEME zu zerlegen. Erscheint eines der Teilprobleme immer noch zu schwer durchschaubar, kann man es weiter in weitere Teilprobleme zerlegen - irgendwann läuft es am Ende auf eine ganz einfache Befehlsabfolge hinaus. Diese kann man dann wieder mit einem anderen gelösten Teilproblem „zusammenstecken“ (also beide miteinander verbinden und gemeinsam ausführen) und wenn sie zusammen funktionieren, dann verbindet man sie weiter mit anderen Teilproblemen.
Das klingt vielleicht ein wenig abstrakt - ich werde etwas später noch konkreter werden.
Also: Wir wollen ein kleines Spiel schreiben. Einer der Fehler, den man machen kann, wenn man ALLEINE programmiert ist: Erst den Vorspann, das Titelbild und die Titelmusik machen wollen. Als Neuling geht man vielleicht davon aus, weil es das ist, was der Spieler als erstes sieht, ist es auch das, was als erstes programmiert werden muß (und ja, ganz früher habe ich diesen Fehler auch gemacht) - dem ist aber nicht so!
Man muß sich darüber klarwerden: Was ist das Spiel (die „Essenz“ des Ganzen sozusagen) und was ist das „Beiwerk“? Und - so schlimm sich das für die Leute, die heutzutage mit Computern rummachen, anhört: Grafik und Sound sind Beiwerk! (Will sagen: Jemand, der z.B. wirklich ein BETRIEBSSYSTEM programmieren will, sollte - bei allen Dämonen der Unterwelt! - NICHT mit der GRAFIK (Icons/Fensterbuttons etc) anfangen!)
Nehmen wir mal an, das Spiel soll ein ganz einfaches Ding werden: Ein 2D-„Labyrinth“-artiges Spiel, Sicht von oben. (Sicht von oben ist einfacher, da braucht man keine „Sprünge“ einbauen…) In diesem Spiel gibt es eine Spielfigur (der Spieler), dann einige Figuren, die er Spieler jagen kann und einige andere, die vom Spieler gejagt werden sollen. Für gejagte Figuren gibt es Punkte, wenn der Spieler gefangen wird, verliert er ein Leben. Hat der Spieler alle zu jagenden Figuren eingefangen, kommt er in das nächste Level.
Ja, ich weiß: Das klingt total simpel und es ist keine Konkurrenz World-of-Warcraft oder irgendeinem Kriegsgeballer - nicht mal zu Mario Brothers oder so. Aber es ist ein gutes Beispiel, um sich erstmal klarzuwerden, wie man Algorithmen aufbaut.
Also: Was braucht man?
- Darstellung des Spielfeldes
- Darstellung der Spielfigur (z.B. Männchen)
- Darstellung der jagenden Figuren (z.B. Wolf)
- Darstellung der zu jagenden Figuren (z.B. Hase)
- Darstellung der Anzeigen (für Level, Punkte, Leben)
- Steuerung der Spielfigur
- Steuerung der jagenden Figuren
- Steuerung der zu jagenden Figuren
- Erkennung von Kollisionen
- Erkennung von Levelende
Und ja, das wäre ein sehr einfaches Spielprojekt - aber daran könnte man eben üben, wie man so etwas aufbaut. Ich habe den Text eigentlich schon weitergeschrieben, nämlich, wie man so etwas auf eine einfache Art lösen könnte (durch Zerlegung der Probleme in Teilprobleme).
PROGRAMMIEREN - TEIL 2
DARSTELLUNG
Für alles, was unter „Darstellung“ läuft, sollte man sich klarmachen, WIE man es darstellen will. Man hat nun Möglichkeiten, es z.B. im TEXTMODE laufen zu lassen. Das ist das einfachste - der Textmode ist nicht besonders schwer aufzurufen, außerdem braucht man - wenn man es GANZ EINFACH haben will, nicht einmal Grafiken generieren, da die Buchstaben und „Zeichen“ im Textmode auch dafür benutzt werden können. Man kann das Ganze auch im GRAFIKMODE laufen lassen. Grafikmodi haben jedoch die Eigenschaft, lediglich PUNKT (Pixel) darstellen zu können. Will man also etwas mehr als nur sich jagende PUNKTE haben, so muß man die Figuren aus Punkten zusammensetzen. Solche Figuren werden SPRITES genannt.
(Unwichtiger Hinweis für die Korinthenkacker: Ja ich weiß: Sprites sind es eigentlich nur, wenn sie von der Grafikhardware erzeugt werden, softwaremäßig erzeugte „Sprites“ heißen Shapes. Ich persönlich kenne aber kaum jemanden, der in diesewr Bezeichnung einen Unterschied macht - irgendwann wurde einfach jedes dieser beweglichen Objekte als Sprite bezeichnet - egal ob Hardware oder Software. Die Grenzen sind ohnehin fließend, denn, wenn man mal von den Grafikchips auf C64 u.ä. absieht, werden die Grafikelemente in den modernen Grafikkarten auch durch ein Firmware-Programm erzeugt und nicht mehr durch simple Schaltungen.)
Man kann übrigens auch im Textmode solche „Sprites“ benutzen - indem man einfach Figuren benutzt, die sich aus mehreren Textzeichen zusammensetzen.
Und jetzt kommt’s: JA; man sollte sich klarmachen, daß man irgend etwas braucht, um die Figuren darzustellen - aber es ist quasi wirklich EGAL, ob man zuerst die STEUERUNG oder zuerst die DARSTELLUNG der Figuren programmieren will. Ich werde jetzt erst einmal die DARSTELLUNG abhandeln - mit Hilfe von SPRITES.
SPRITES
Diese Sprites - und auch die restlichen Grafiken (also das Labyrinth) bestehen also wahlweise aus Pixeln oder (evtl. farbigen) Textmode-Zeichen - also sollte man sich wohl erst einmal Gedanken darüber machen, wie man einen Pixel oder ein Textzeichen auf den Bildschirm bringt. Kann man das nicht, kann man kein grafisches (oder Textmode) Spiel schreiben. Diese Dinge sind sozusagen das kleinste Element.
Wie schon erwähnt, sind Sprites aus „Elementen“ zusammengesetzt - im Textmode aus Zeichen, im Grafikmode aus Pixeln. Also machen wir uns erst einmal klar, was ein Sprite im Grunde ist: Es ist eine Fläche. Eine Fläche hat zwei Richtungen, Breite und Höhe - dementsprechend ist ein Sprite also - datentechnisch - einfach ein zweidimensionales Array. Ich definiere jetzt (der Einfachheit halber), daß es nur Sprites geben kann mit einer maximalen Größe von 8x8 Zeichen ODER Pixeln. Ein Zeichen im Textmode ist ein Word (16 Bit, bzw 2 mal 8 bit. Nämlich ein Zeichen und dann seine Farben). Ein Pixel ist allein definiert durch seine Farbe. Hierzu ist eventuell wichtig, in welchem Grafikmodus man sich befindet. Farben - auf dem PC - bestehen aus 3 Phasen (rot/grün/blau), die in verschiednen Mengen zusammengesetzt den Farbton ergeben. Jedoch hat man die technische Möglichkeit, eine Farbpalette zu benutzen, die bestimmte Farben fest definiert und man benutzt dann nur noch die Nummer der Farbe ODER man benutzt eben die wirkliche Farbe als direkten Farbwert.
OK, genug technisches Geschwafel! Es ist eben einfach nur wichtig, sich über solche Dinge Gedanken zu machen, um zu wissen, in welcher Größe und Datenstruktur man die Sprites anlegt. Will man sich das bis zuletzt offenlassen, macht man es so:
Man definiert einen Typ ELEMENT, der dann die Farbe oder das Zeichen/Farbcode enthält und dann definiert man einen zweidimensionalen Array-Typ SPRITE, mit beiden Dimensionen 0 bis 7 (oder 1 bis 8 oder wasweißich). Warum nur einen Array-Typ? Nun, wir brauchen ja MEHRERE solcher Sprites, nämlich einen für das Spieler-Männchen, einen für den „Wolf“, einen für den „Hasen“ (Ja, alle Wölfe und Hasen sehen hier gleich aus, so daß man dasselbe Sprite für mehrere Figuren benutzen kann.) Das heißt: Man definiert ein weiteres Array (IMAGES oder so) vom Typ SPRITE. Dieses muß so groß sein (d.h. so viele Elemente vom Typ SPRITE enthalten), wie es unterschiedliche Sprites gibt.
Wichtige Anmerkung zwischendurch:
Natürlich ist das eine ganz einfache Methode, um ein ganz einfaches Spiel zu bauen! Größere Spielprojekte haben mehr verschiedene Sprites mit verschiedenen Größen, das ist mir klar. Ich selbst baue heutzutage die Sprites ganz anders auf, in speziell gepackten und in Assembler besser zu verarbeitenden Formaten! Allerdings ist das an dieser Stelle ja eventuell zu kompliziert zu erklären - schließlich geht es ja darum, erst einmal einen ANFANG zu finden, um ein Spiel programmieren zu können!
Nehmen wir nun an, wir wollen ANIMATIONEN, d.h. die Figuren sollen sich irgendwie bewegen, damit es lustiger aussieht. Dann muß man für jede Bewegungsphase ein weiteres Element in das IMAGES Array reservieren. Die einzelnen Bewegungsphasen werden so gemacht wie bei einem Zeichentrickfilm.
So, nun haben wir also SPRITES, die aussehen wie Quadrate aus 8x8 Pixeln (oder Zeichen) - es gibt also nur quadratische Figuren? Ja, bisher schon. Wir können (siehe oben) auch Pixel oder Zeichen an jede Position des Bildschirms setzen - das gleiche können wir mit den Sprites machen. Um das Sprite darzustellen, sind also zwei ineinander verschachtelte Schleifen notwendig, um alle Pixel oder Zeichen darzustellen. Wenn die Position des Sprites also an zwei Koordinaten liegt (X und Y für Breite und Höhe des Bildschirms), so kann man zwei Schleifen nehmen, die von 0 bis 7 zählen und dann aus dem Sprite-Array mit den Indizes der Schleifen plus X bzw plus Y die Pixel oder Zeichen an die Positionen setzen. Ja, ich weiß: Eigentlich klingt das jetzt ganz simpel. Aber es gibt eben wirklich Leute, die sehen einen Bildschirm mit sich bewegenden Figuren und fragen sich, wie das gemacht wird. (Achja:Erfahrungsgemäß empfiehlt es sich eher, die Sprites so zu setzen, daß die Koordinaten sich in der Mitte des Sprites befinden, wegen der vereinfachten Kollisionsabfrage.)
So, nächster Gedanke: Uns gefällt nicht, daß die Sprites alle nur bunte Quadrate sind. Was kann man tun, damit sie eine andere Form bekommen? Nun, erstens, man könnte komplizierte Strukturen erfinden, um die Pixel anders zu speichern als im Quadrat. Beispielsweise könnte man zu jedem Pixel eine Definition machen, die einen Offset (Abstand) zum folgenden Pixel angibt. Dann zeichnet man so lange Pixel, bis der Offset =0 wäre (das wäre ungültig, weil man ja dann zweimal auf dieselbe Stelle zeichnen würde). Aber: Das braucht viel mehr Daten…
ODER man benutzt die gängigste Methode: Man definiert einfach eine Farbe/ein Zeichen als „transparent“ (durchsichtig). Und immer, wenn man an eine solche Stelle kommt, setzt man KEINEN Pixel oder Zeichen. Diese Methode hat einen weiteren Vorteil: Man braucht nicht eine generalisierte Zeichensetz- oder Pixelsetz-Funktion benutzen, die jedesmal die Bildposition ausrechnet - denn die Positionen der Pixel/Zeichen sind ja direkt neben-/untereinander. Was will der Künstler uns damit sagen? Nun ja, nehmen wir an, wir hätten einen Sprite und würden ihn z.B. im Modus MCGA darstellen wollen. Das ist der bekannte (und damals sehr beliebte) Modus mit 320x200 Pixeln und 256 Farben (aus 262144 wähbaren) in einer Farbpalette. Der Speicher dieses Modus ist linear und liegt an der Adresse $A000 (Segment) und der Offset ist von 0 bis 63999 (320x200 = 64000). (In Pascal - und sicher auch anderen Sprachen - kann man an diese Adresse nun einfach ein 64000 Pixel großes Array legen - oder eben ein zweidimensionales Array mit 320 x 200 Bytes). Ich wähle mal das 64000er Array - damit erspare ich dem Rechner unnötige Multiplikationen. Also:
Das Sprite wäre 8 Pixel breit und 8 Pixel hoch. Um das Sprite darzustellen, könnte man nun also einfach folgendes tun: Man weiß, wohin das Sprite soll, hat also eine X (Spalte) und Y (Zeile) Position. Nun berechnet man eine Startposition P = Y*320+X. Und dann zeichnet man alle 64 Pixel des Sprites, indem man folgendes tut:
zwei Schleifen, eine äußere, die die Zeilen zählt und eine innere, die die Spalten zählt.
Und dann zeichnet man in der inneren Schleife einen Pixel an die Adresse P und erhöht jeweils danach P um 1. Hinter dem Ende der inneren Schleife und vor dem Ende der äußeren Schleife erhöht man P um 312 (das ist 320 minus 8, nämlich die 8 der Breite) und schon ist P an der Position der nächsten Sprite-Zeile). Auch wenn die Sprites andere Breiten und Höhen haben, kann man diesen Addier-Wert (nämlich Bildbreite minus Sprite-Breite) vorher ausrechnen. Auf diese Art gibt es innerhalb der Schleifen nur Additionen und keine sinnlosen Multiplikationen, die jedesmal die korrekte Pixelposition ausrechnet und dann einen Pixel mit einer generalisierten Pixelroutine irgendwo hinpixelt.
Ja, ich weiß! Das ist Computerfreak-Zeugs! Aber es kann nicht schaden, über solche Dinge ein wenig nachzudenken - und schon hat man mit einfachen Mitteln eine relativ einfache Spriteroutine gebaut. Achja: Da sollte vielleicht eine Abfrage rein, die, wenn die „Keyfarbe“ (so nennt man die), also die Farbe, die NICHT gezeichnet werden soll, im Sprite auftritt, reagiert. Also vielleicht sowas wie A=SPRITE(sprX,sprY); IF AKEYCOLOR THEN SCREEN§=A
(Das ist nur so „Pseudo-Code“, ich schreibe das bewußt möglichst programmiersprachen-unabhängig.)
Und - Ich weiß auch nicht, woran es liegt, daß manche Leute mich immer wieder fragen, wie man es macht, daß die Sprites sich fortbewegen: Nun ja: Man verändert die Koordinaten und setzt das Sprite an die neuen Koordinaten und schon sieht es aus, als bewegten sie sich. (Natürlich muß man entweder sich merken, was UNTER dem Sprite war und das dann nachher wieder hinzeichnen. ODER man zeichnet jedes „Frame“ neu, d.h. das ganze Labyrinth und alle Sprites.)
Zum Schluß noch eine Anmerkung:
JA, ICH WEIß! Es gibt komplett fertige Programmbibliotheken, die die Darstellung von Grafiken und Sprites beinhalten! Die kann man natürlich auch benutzen - und lernt dafür dann eben nie, wie es eigentlich funktioniert.
Dieses „Setze ein Sprite mit Image-Nummer I an Position X und Y“ sollte ein Unterprogramm sein, das eben mit den Parametern I, X und Y (oder IMAGE, SPALTE, ZEILE) aufgerufen wird. Das macht es einfacher, da später noch im Programm durchzusehen. Und außerdem kann man so auch jederzeit sein Sprite-Zeichne-Unterprogramm später durch ein besseres ersetzen, das schneller ist oder mehr Features hat.
Anmerkung:
Sollte man unglücklicherweise unter Multitasking-Betriebssystemen programmieren müssen, kann man oft nicht alle Möglichkeiten der direkten Benutzung der Hardware-Besonderheiten ausschöpfen! In diesem Fall sollte man lieber doch zum Setzen der Pixel eine von der jeweiligen Programmiersprache oder Programmbibliothek vorgegebene generalisierte Routine zum Setzen von Pixeln oder gleich Setzen von Sprite-Images benutzen (wobei letztere wahrscheinlich ihre Sprites in bestimmten, fest durch die Programmierer der Bibliothek (Library) vorgegebenen Formaten im Speicher erwarten).
Sollte aber Interesse (und Möglichkeit) der direkten Benutzung von Grafikmodi bestehen, so empfehle ich hierzu z.B. meinen Text „Wie funktioniert Grafik?“ auf meiner Webseite
http://www.imperial-games.de/html/dosd2.htm zu lesen.
Falls man es der Einfachheit halber lieber erst im TEXTMODE versuchen will - der „normale“ Textmode (80x25, 16farbig) liegt an Segment $B800, alle Zeichen hintereinander, jedes Zeichen braucht 2 Bytes. Das erste Byte ist der Buchstabe/das Zeichen. Das zweite Byte ist geteilt: Die unteren 4 Bits sind die Zeichenfarbe, die oberen 4 die Hintergrundfarbe, wenn BLINKEN AUS. BLINKEN ist aber beim Setzen des Modus AN (im Windows „DOS-Fenster“ wird Blinken nicht supportet, da ist es AUS). Ist BLINKEN an, so gibt es nur die ersten 8 Farben als Hintergrundfarben, das oberste Bit des „Farb-Bytes“ bestimmt, ob das Zeichen blinkt (d.h. zwischen Zeichenfarbe und Hintergrundfarbe (=„unsichtbar“) wechselt.
So, nun habe ich Euch mit Sprites und farbigen Sprites und so vollgelabert und nun habt Ihr gar keine Sprites! Denn Ihr habt jetzt eine Ahnung, wie man Sprites im Speicher anlegen KÖNNTE (das ist keine Pflicht, die auf diese Art zu speichern! Es sollte auf die „zweidimensionales Array“ Methode vor allem verdeutlicht werden, daß eine 2D-Figur eine Fläche von farbigen Punkten ist - diese Farben werden in Zahlen ausgedrückt.). Und Ihr habt eine Sprite-Zeichne-Routine. Aber Ihr habt keine Sprites!
WO BEKOMMT MAN DIE GRAFIK FÜR DAS SPIEL HER?
Ich könnte jetzt weitergehen und erstmal Steuerung und Level usw. erklären - aber wir wollen ja auch mal ein Erfolgserlebnis haben. Und zwar ein Programm, das an jede Stelle des Bildschirms schöne Figuren zeichnen kann. Dazu KANN man sich natürlich jetzt einen Sprite-Editor schreiben, mit dem man diese Sprites erstellt. Man könnte aber auch einfach ein gängiges Malprogramm benutzen, in diesem die Sprites zeichnen und in einem möglichst ungepackten Format (wie BMP) abspeichern - und dann die Sprites vom Programm aus wieder laden.
Wie geht man dazu vor?
Mal eine einfache Methode:
Man startet ein einfaches Malprogramm wie Windows PAINT und pixelt einfach 32 Sprite-Images nebeneinander oben ins Bild. Das Bild wird dann so beschnitten, daß es 256 Pixel breit (32x8) und 8 Pixel hoch ist. Das ganze Ding speichert man dann ab - und zwar als „256 Farben Bitmap“! Das ist wichtig, weil wir’s ja erstmal einfach haben wollen und nicht auch noch mit 24bit-Farben rummachen wollen. Man kann natürlich auch in irgendeinem anderen Malprogramm zeichnen - nur sollte man eben (für dieses einfache Spiel-Beispiel) erstmal palettenbasiert arbeiten, also 8bit, bzw 256 Farben - und es dann als 256-Farb-BMP speichern. Warum das so wichtig ist? Wenn die Bitmap eine feste Größe und eine feste Farbtiefe hat, braucht man im Programm nicht das Format analysieren und da rumfuhrwerken, sondern findet alles, was man braucht an festen Positionen in der BMP-Datei.
Vom Programm aus kann man dieses Bild dann nachladen - und zwar mit richtig angeordneten Schleifen genau an die richtigen Positionen.
(An der Stelle 10 liegt die Breite des Bildes als 16bit (Word)Wert, an der Stelle 12 die Höhe des Bildes - beides in Pixeln. An der Stelle 80 liegt eine Farbpalette aus 768 Bytes (256x3), für jede der 256 Farben ein Rot-, Grün- und Blau-Wert. Direkt dahinter (ab der Stelle 848) liegt das Bild. Die Zeilen sind immer auf Vielfache von 4 aufgefüllt, wenn also die Bildbreite z.B. 213 sein sollte, liegen pro Zeile 216 Bytes vor, von denen die letzten 3 nur Füll-Bytes sind, die nicht zum Bild gehören. Dieser Kram hat technische Ursachen und wurde damals für das BMP-Format so definiert. Außerdem muß beachtet werden, daß BMPs von unten nach oben gespeichert sind. (Ja, ALLE von Microsoft gemachten Grafikformate sind das - wohl wegen des karthesischen Koordinatensystems, {0;0} links unten und so. Ist aber meines Erachtens Blödsinn, vor allem, weil bei der Grafikkarte und jedem Grafikformat der Nullpunkt links oben liegt - aber egal!) - Dies kann man aber ausgleichen, indem man beim Laden der Grafikdaten in den Sprite-Speicher einfach die Zählschleife für die Zeilen rückwärts zählen läßt.)
Das könnte ich natürlich alles noch genauer erklären - aber ich will Euch ja nicht Eure ganzen Ideen nehmen! (Und ja: Mit Grafikprogrammierung kenne ich mich bestens aus! Auch diesen Mode-X, VESA-Modi und so Zeugs…)
Natürlich kann ich jetzt nicht voraussagen, wie in Eurer jeweiligen Programmiersprache von Dateien geladen/gespeichert wird, das ist überall leicht anders gelöst - aber es gibt eben nur die zwei Möglichkeiten: Entweder, man lädt die Daten, die man braucht, aus externen Dateien* nach, oder man integriert die Daten direkt in den Sourcecode (ja, ich habe auch dafür mal ein Programm geschrieben, das so etwas macht: Daten als Konstanten-Arrays in Sourcecodes integrieren).
* = Diese externe Datei kann auch das Programm (die EXE) selbst sein - indem man nachträglich die Daten an die EXE an-„linkt“ und dann von dort lädt - aber das wollte ich jetzt erstmal außen vor lassen.
Okay! Das ist jetzt immer noch kein Spiel!
Ja, ich weiß! Aber dafür ja auch gleich mal meine Merksätze an alle angehenden Spieleprogrammierer:
- Spiele programmieren ist völlig anders als Spiele spielen!
- Ein Spiel programmieren dauert (wesentlich) länger als das Spiel durchzuspielen!
- Spiele programmieren KANN zwar genausoviel Spaß machen wie Spiele spielen - aber nur, wenn einem Programmieren und Herummurksen mit Zahlen und Programmcode Spaß macht - sonst nicht!
ABER:
Jetzt sollte man ein Sprite-Zeichne-Unterprogramm haben und ein Sprite-Image-Nachlade-Unterprogramm und ein BMP-Bild, das die Sprites, bzw deren Bewegungsphasen enthält.
Sollte man sich dafür entschieden haben, statt der Sprites und Grafik im Textmode zu arbeiten, so ist das auch nicht so schlimm. Wichtig ist, daß man irgendeine „Figur“ an irgendeine Position auf den Text- oder Grafikschirm setzen kann.
Vielleicht gibt es da ja noch ein kleines Problem:
F: Wie setzt man den 80x25, 16 Farben -Textmode?
A: AX auf $0003, dann INT $10. Vielleicht hat auch die jeweilige Programmiersprache etwas, um den zu setzen. Ist zu speziell, um darauf allgemein zu antworten.
F: Wie setzt man den 320x200, 256 Farben Grafikmode?
A: wie den Textmode, nur mit AX=$0013, dann INT $10.
Das Problem beim Grafikmode ist, daß da zu Anfang IMMR eine generalisierte Farbpalette gesetzt wird und man da seine eigene setzen muß - beispielsweise die, die man aus seinem BMP geladen hat. Auch das ist jetzt wieder zu speziell, um allgemein darauf zu antworten - Beispiele sind in dem „Wie funktioniert Grafik?“ Text enthalten, aber eben für Assembler. Für das Setzen der Farbpalette muß die Adresse der Palette (also des 768-Byte-Arrays, wo diese liegt/wohin man sie geladen hat) angeben. Eventuell hat die jeweilige Programmiersprache aber auch Dinge, um dies zu tun.
F: Gibt es eine einfachere Methode, um erstmal zum Erfolg zu kommen? Und welche?
A: Ja. Und zwar fertige Bibliotheken zu benutzen.
Ist man mit der Programmierung so weit, KÖNNTE man natürlich erst einmal ein Testprogramm schreiben, das die Figuren nachlädt und dann auf dem Bildschirm Figuren an verschiedenen Positionen anzeigt. Die Fähigkeit zur Verwendung von Variablen und Rechenoperationen zu diesem Zweck setze ich bei jemandem, der seine Programmiersprache verstanden hat, jetzt einfach mal voraus.
OKAY - das soll es jetzt erst einmal gewesen sein. Ich vermute, nach Lektüre dieses Textabschnittes werden ohnehin erst noch einige offene Fragen bestehen.
Unwichtige Anmerkung:
Ich SELBST habe schon über 100 selbstgeschriebene Bibliotheken hier und bisher benutzt die niemand außer mir selbst. Sie enthalten Dinge für Grafikprogrammierung (VESA, VGA, MODE-X, Textmode), Sprites und Leveldarstellung, Direkt-Steuerung per Tastatur und Maus etc. - Es gibt sogar seit einiger Zeit eine Library (nennt sich GameSys2), die in 100% Assembler geschrieben ist und die vollständige Figurensteuerung samt Kollisionsabfrage (also quasi die ganze „Programmierung darunter“) eines beliebigen zu programmierenden 2D-Spiels (Jump’n’run, Shoot’em’up, Labyrinthspiele, auch sowas wie PacMan, Bomberman, Snake, aber auch sowas in der Art wie R-Type, Mario Brothers und Turrican) komplett übernimmt und dies in einer Art VM (Virtual Machine), die mit einer Assembler-ähnlichen Skriptsprache programmiert wird (ich denke gelegentlich laut darüber nach, dafür eine Art "Frontend"Sprache zu bauen, die BASIC-artig ist).
ABER: Das ist alles für DOS und PASCAL! Beides benutzt heute außer mir kaum noch jemand und ich bin mir fast sicher, daß niemand hier Interesse daran hat, DOS-Spiele zu schreiben.
Sollte jemand Interesse daran haben, was man (ich) alleine mit diesen Libraries (und da waren es noch ältere Versionen und GameSys2 wird da noch gar nicht verwendet) so machen kann, könnte man sich ja auch mal in der Preview-Sektion meiner Seite umsehen:
http://www.imperial-games.de/html/prea1.htm
Achso: Ich selbst HABE natürlich entsprechende EDITOREN und KONVERTER-Programme (selbstgeschriebene), um aus vorgefertigten Grafiken entsprechen Sprites oder Levelelementen die entsprechenden Daten für die Anzeige-Subroutinen zu machen.