Programm-Ablauf für Anfänger
Übersicht

![]() |
MidimasterBetreff: Programm-Ablauf für Anfänger |
![]() Antworten mit Zitat ![]() |
---|---|---|
Programm-Ablauf für Anfänger
Dies ist ein Tutorial für blutige Anfänger. Es erklärt wie man die ersten Zeilen des Spiel-Codes erstellt. Für die drei vorgestellten Modelle werden Vor- und Nachteile erläutert. (Ich bitte alle, sich mit eigenen Einträgen rauszuhalten und dafür lieber den Thread "Kritik an Midimaster-Tutorials" zu nutzen. Dieses Tutorial soll den Anfänger möglichst durch keine Diskussionen irritieren.) Kritik hier hin: Kritik-Thread Allen Anfängern lege ich wärmstens ans Herz dieses Tutorial durchzuarbeiten. Es spart euch viele Fehler in späteren Programmen. Fragen von Hilfesuchenden bitte ins BB-Beginners-Corner (https://www.blitzforum.de/forum/viewforum.php?f=18), aber auf keinen Fall hier hin posten! Das Tutorial ist didaktisch konzipiert aufgebaut. Die Lektionen bauen aufeinander auf. Lektion I-IV: "1-Ansicht"-Spiel mit 1 Hauptschleife Lektion I: Was gehört wo hin? ![]() Lektion II: Der Code-Anfang: Definieren und Laden ![]() Lektion III: Die Hauptschleife des Spiels ![]() Lektion IV: der Funktionen-Teil ![]() Lektion V: "1-Ansicht"-Spiel mit mehreren Levels ![]() Lektion VI: Paket aus mehreren Ansichten mit jeweils eigener Hauptschleife ![]() |
||
- Zuletzt bearbeitet von Midimaster am So, Jan 10, 2010 17:19, insgesamt 9-mal bearbeitet
![]() |
MidimasterBetreff: Lektion I: Was gehört wo hin? |
![]() Antworten mit Zitat ![]() |
---|---|---|
Lektion I: Was gehört wo hin?
Egal wie klein dein Projekt werden soll, verwende nie Spaghetti-Code! Er ist zu unübersichtlich, schwer zu ändern und die Fehlersuche wird zur Zumutung. Dabei ist es ganz leicht, etwas Struktur in dein Programm zu bringen, auch wenn du erst ganz wenig Ahnung vom Programmieren hast. Wir wollen einmal annehmen dein Spiel startet gleich durch: ohne Titelseite, ohne Einstellungsmenü und es gibt nur 1 Spielansicht. So könnte Deine Programm-Struktur dann aussehen: BlitzBasic: [AUSKLAPPEN] Graphics 800,600,32,2 Alle Spiele sehen so aus! Warum nicht auch deines? Coden wie ein Profi! Deshalb hier vier Grundregeln: Zitat: 1.
Alle verwendeten Variablen werden am Code-Anfang definiert! 2. Alle Ladevorgänge für Bilder, Fonts, Sounds, etc gehören auch an den Code-Anfang! 3. Der Spielablauf kommt in eine WHILE/WEND oder REPEAT/UNTIL-Schleife! 4. Gewöhne dich gleich zu Beginn an die Verwendung von Funktionen! Ein typisches Programm besteht also aus drei Teilen: - Code am Anfang - Die Hauptschleife - Der Teil der Funktionen Die folgenden Kapitel II, III und IV erläutern jeweils einen dieser Teile und sagen dir, was du darin beachten musst |
||
- Zuletzt bearbeitet von Midimaster am Di, Jan 05, 2010 23:31, insgesamt 5-mal bearbeitet
![]() |
MidimasterBetreff: Lektion II: Der Code-Anfang Definieren und Laden |
![]() Antworten mit Zitat ![]() |
---|---|---|
Lektion II: Der Code-Anfang: Definieren und Laden
Auch wenn Dein Spiel später im Full-Screen-Mode laufen wird, lass es zunächst in einem Fenster ablaufen. So siehst Du immer den DEBUGGER und kannst den Code parallel dazu betrachten. Außerdem startet es schneller und lässt sich leichter unterbrechen: BlitzBasic: [AUSKLAPPEN] Graphics 800,600,32,2 Gewöhne dir an, alle Variablen, die du neu verwenden möchtest, am Anfang des Codes zu definieren. Entweder brauchst du sie an vielen Stellen im Programm: Dann gehören Sie als GLOBAL an den Anfang des Gesamtcodes. Oder du benötigst sie nur kurz innerhalb einer Funktion: Dann gehören Sie als LOCAL an den Anfang der Funktion: BlitzBasic: [AUSKLAPPEN] Graphics 800,600 Das Nachladen der Bilder, Sound und Fonts von der Festplatte benötigt viel Zeit und könnte dein Spiel ausbremsen. Daher werden die Daten gleich zu Beginn geladen, bevor das Spiel für den User beginnt. Auch wenn Du eine Datei mehrmals brauchst, musst du sie nicht wieder nachladen. Wurde die Datei in eine GLOBALE Variable geladen, steht sie dir im gesamten Programm zur Verfügung: BlitzBasic: [AUSKLAPPEN] Graphics 800,600 unmittelbar vor das REPEAT gehören noch letzte Vorbereitungen für den Spielstart, z.B. BlitzBasic: [AUSKLAPPEN] Leben=100
|
||
- Zuletzt bearbeitet von Midimaster am Do, Jan 07, 2010 11:01, insgesamt 4-mal bearbeitet
![]() |
MidimasterBetreff: Kapitel III: Die Hauptschleife des Spiels |
![]() Antworten mit Zitat ![]() |
---|---|---|
Kapitel III: Die Hauptschleife des Spiels
Zwischen REPEAT und UNTIL steht alles, was während des Spiels geschieht: - Zeichnen des Hintergrunds und der Figuren - Abfragen der Tastatur und Maus - Kollisionen - Entstehen neuer Gegner und Schüsse - Sterben von Figuren - Textausgaben - Geräusche Dabei kannst du zwischen 2 Modellen wählen. Das eine gruppiert alles was zur selben Figurengruppe gehört in einzelne Funktionen: BlitzBasic: [AUSKLAPPEN] Repeat Das andere Modell sortiert alle Mal-Aufgaben in eine Funktion, alle Kollisionen in eine weitere, etc... BlitzBasic: [AUSKLAPPEN] Repeat Du wirst so ein Modell nicht 100% durchhalten können. Das ist aber kein Problem. Du kannst auch einen eigenen Weg finden. Halte dir aber immer vor Augen, dass die gesamte REAPEAT/UNTIL-Schleife im Spiel in jeder Sekunde 60x durchlaufen wird. Deshalb ist es z.B. nicht nötig einen Schuss, den du gerade neu erschaffst, sofort zeichnen zu lassen. Er wird nach Ablauf einer 1/60-Sekunde sowieso von der nächsten AllesMalen-Aktion gezeichnet. Stirbt etwas, mach dir keinen Kopf, wie du es jetzt vom Bildschirm löschen kannst. Nach 1/60-sec ist es sowieso weg! Was Du aber in beiden Modellen erkennst, ist, dass zwar alles innerhalb der REPEAT/UNTIL-Schleife geschieht, aber doch keine einzige Code-Zeile dort reinkommt. Eigentlich soll alles in Funktionen. Aber auch das musst du nicht 100% durchhalten. |
||
- Zuletzt bearbeitet von Midimaster am Mi, Jan 20, 2010 11:32, insgesamt 2-mal bearbeitet
![]() |
MidimasterBetreff: Kapitel IV: Der Funktionen-Teil |
![]() Antworten mit Zitat ![]() |
---|---|---|
Kapitel IV: Der Funktionen-Teil
Der Hauptgrund, warum bei Anfängern aller Code gerne in der REPEAT/UNTIL- Schleife steht, ist, weil sie mit einem Code aus Funktionen deutlich mehr Fehlermeldungen erhalten und mehr Fehler zu beobachten sind. Nun ist es aber nicht so, dass ein Code, in dem wenige Fehler zu beobachten sind, deshalb schon weniger Fehler hat. Du bemerkst sie nur nicht sofort! So gesehen, zwingen dich Funktionen dazu, sauberer zu arbeiten und weniger Fehler im Code zu produzieren. Arbeite also mit Funktionen! Hauptursache für Fehler bei Codes mit Funktionen ist das völlige Ignorieren von Variablen-DEFINITIONEN durch den Programmierer. Überdenke jede neue Variable in bezug auf Geltungsbereich und Type. Ich verweise hier mal auf mein GLOBAL/LOCAL-Tutorial: https://www.blitzforum.de/foru...037#354037 Für unser Spiel bedeutet das: Zitat: 1.
Alle Variablen, die du in mehreren Funktionen brauchen wirst, sind GLOBAL! 2. Alle Variablen, die du in einer Funktion veränderst und die du bei erneutem Aufruf der Funktion immer noch mit dem alten Wert vorfinden willst, sind ebenfalls GLOBAL! 3. Im Zweifelsfall machst du eine Variable GLOBAL. Das funktioniert immer! 4. So sind z.B. alle DIM-Arrays und TYPES-Elemente in BB sowieso immer automatisch GLOBAL! 5. Variablen, die du versehentlich nicht definierst, sind in BB automatisch LOCAL! Gerade Punkt 5 führt bei Anfängern immer wieder zu Kopfzerbrechen. Darum DEFINIERE!!! so bitte nicht: Code: [AUSKLAPPEN] For i=1 To 5
a=a+1 Next ZeigeDich End Function ZeigeDich() Print a End Function Überlegen selbst, welcher Zahl wohl hier bei PRINT ausgegeben wird. 5? Nein, es ist eine 0! so ist es besser. A% wird definiert: BlitzBasic: [AUSKLAPPEN] Global a% Die typischen Funktionen eines Spiels Natürlich könnten wir in eine Funktion SpielerAktion() schon alle Zeilen reincoden, die nötig sind um den Spieler zu zeichnen, ihn zu bewegen und seine Kollisionen zu testen. Und wir könnten dort weitere Aktionen hineinschreiben, die andere Figuren des Spiel beeinflussen. Das wären dann mal so 50 Zeilen Code. Es sei dir auf freigestellt dies nun zu tun. Aber wenn wir jetzt schon Funktionen endlich verstanden haben und benutzen wollen, warum dann nicht noch einmal nur eine Funktion SpielerAktion(), die wieder nur aus Funktionsaufrufen besteht? Au ja! BlitzBasic: [AUSKLAPPEN] Function SpielerAktionen() Was ist der Vorteil? Du könntest blitzschnell Teile deines Codes ausschalten um andere Teile zu testen. BlitzBasic: [AUSKLAPPEN] Function SpielerAktionen() Oder du könntest zunächst einzelne Arbeitsschritte "faken", um sie erst später mit richtigen Code zu füllen. Hier testest du das Malen, obwohl das Bewegen nur ein fake ist: BlitzBasic: [AUSKLAPPEN] Function SpielerAktionen() Solche Fakes (=schwindeln, schummeln) sind beim Programmieren ideal. Du kannst die Funktionalität eines Abschnittes ausarbeiten, ohne dabei auf andere Code-Teile angewiesen zu sein. Ein typisches Beispiel ist das Töten eines Gegners. Es ist ziemlich mühsam, zum Testen der Explosion jedes Mal dem Gegner hinterher fliegen zu müssen, ihn treffen zu müssen und dabei nicht selbst abgeschossen zu werden. Vor lauter "Spiel-Stress" kommst du gar nicht dazu die Explosionsbilder-Folge genau zu beobachten. Mal abgesehen davon, dass hierfür der Code des Spielers, der Schüsse und die Kollisionen bereits fertig und fehlerfrei sein müssten. Mit Fakes ist das leichter. Du baust eine Zerstörung des Gegners nach <RETURN>-Taste ein, schaltest die Bewegung des Gegners aus, damit er genau vor deinem Player bleibt. Du schaltest deinen eigenen Tod auch aus. Nun kannst du das Programm starten und dich zurücklehnen. 5 Sekunden nach dem Start drückst du <RETURN> und der Gegner wird plötzlich explodieren (...oder auch nicht) BlitzBasic: [AUSKLAPPEN] Function SpielerAktionen() Wie du siehst, sind die meisten der Funktionen bei diesem Test "ausgeschaltet". Das Fake-Konzept kann sogar soweit gehen, dass du statt wirklicher Bilder deiner Figuren zunächst nur verschieden farbige Kreise zeichnest, oder "Cubes", wenn du in B3D programmierst. So können auch andere im Forum dein Programm testen, ohne die benötigten Bilder zu haben. |
||
- Zuletzt bearbeitet von Midimaster am Do, Jan 07, 2010 11:17, insgesamt 2-mal bearbeitet
![]() |
MidimasterBetreff: Kapitel V: 1-Ansicht-Spiel mit mehreren Levels |
![]() Antworten mit Zitat ![]() |
---|---|---|
Kapitel V: 1-Ansicht-Spiel mit mehreren Levels
Wenn du dein einfaches 1-Ansicht-Spiel nun fertiggestellt hast, kannst du es momentan immer nur 1x laufen lassen, weil du nach dem Sieg ein END setzt. Diese Lektion zeigt dir, was getan werden muss, damit das Spiel beliebig oft von vorne beginnen kann, bzw. das gleiche Spiel mit einem höheren Level startet. Neustart des Levels In jedem Spiel gibt es Variable, die sich nie ändern, z.B. BlitzBasic: [AUSKLAPPEN] Bild=LoadImage("Hintergrund.png")Die interessieren uns heute nicht. Aber es gibt Variablen, die nach dem Durchspielen einen anderen Wert als zu Beginn des Spiels haben. Um das Spiel erneut zu spielen, müssen diese "veränderten" Variablen alle wieder auf Ihren Ursprungswert zurück. BlitzBasic: [AUSKLAPPEN] Leben = 5 Zunächst musst du herausfinden, welche "veränderten" Variable überhaupt beteiligt waren, damit das Level 1 funktioniert. Vergiss dabei vor allen nicht die Variablen, die dafür den Wert 0 haben mussten: BlitzBasic: [AUSKLAPPEN] Punkte = 0 Nun schreibst du eine Funktion, die diese Variablen auf diese Anfangs-Werte setzt: BlitzBasic: [AUSKLAPPEN] Function SetzLevel() Möglicherweise gehören in die Funktion SetzLevel() auch noch ein paar Zeilen zum Neupositionieren der Gegner, etc, Reinigen des Screens, Reset bei den Geräuschen, etc... BlitzBasic: [AUSKLAPPEN] Delete Each GegnerTyp Diese Funktion wird nun immer dann aufgerufen, wenn das Spiel von vorne beginnen soll: Zitat: Graphics 800,600,32,2
Variablen definieren Laden von Bilder, Fonts, Sounds ev. Vorbereitungen für das Spiel Repeat - - Cls - - hier kommt der Spielablauf - - Flip Until KeyHit(1) End Function Spieler() - - ... - - If Spieler\Leben=0 Then - - - - SetzLevel() - - Endif End Function Function .... - - ... End Function Function SetzLevel() - - Leben = 5 - - Punkte = 0 - - Gegner = 20 - - GegnerBild = LoadImage("DerNette.png") - - Zeit = 0 - - Ziel = 100 - - Getroffen = 0 - - Delete Each GegnerTyp - - For I=1 to Gegner - - - - ErschaffeNeuenGegner() - - Next - - Player\X = 400 - - Player\Y = 300 - - StopSound ... End Function Umschalten auf nächstes Level Nun ist es nur noch ein kleiner Schritt, verschiedene Level mit verschiedenen Parametern zu unterscheiden Dazu muss nur in der SetzLevel() auf verschiedene Zustände eingegangen werden: BlitzBasic: [AUSKLAPPEN] Function SetzLevel() Die Daten der einzelnen Levels könnten entweder direkt hier unter die jeweiligen CASEs eingeschrieben werden oder mit einem Aufruf weiteren LEVEL1() bis LEVELx()-Funktion erfolgen, wo dann dort die Parameter gesetzt werden. Ein sehr schöne Möglichkeit wäre natürlich die Parameter aus einer Datei zu holen. Durch den laufenden Index Nr% wäre keine SELECT/CASE-Konstruktion nötig. BlitzBasic: [AUSKLAPPEN] Function SetzLevel() Dazu wäre natürlich eine Funktion IniLesen() nötig, die eine INI-Datei öffnet, nach dem entsprechenden Eintrag sucht und den Wert dazu zurückgibt. Die passende Datei "INI.txt" wird mit einem beliebigen Editor erstellt und könnte so aussehen: Zitat: [Level 1]
SpielerLeben=100 SpielerWaffe 1=3 SpielerWaffe 2=0 ... [Level 2] SpielerLeben=80 SpielerWaffe 1=3 SpielerWaffe 2=14 ... |
||
- Zuletzt bearbeitet von Midimaster am Do, Jan 07, 2010 12:57, insgesamt 4-mal bearbeitet
![]() |
MidimasterBetreff: Lektion VI: Paket aus mehreren Ansichten |
![]() Antworten mit Zitat ![]() |
---|---|---|
Lektion VI: Paket aus mehreren Ansichten mit jeweils eigener Hauptschleife
Vorwort Wenn Dein Programm nur aus einem Spielbild besteht, also keine zusätzliche Titel-Seite und keine Einstellungen-Seite hat. Wenn Dein Programm keinen Level-Editor mitbringt, dann brauchst du dieses Tutorial nicht. Ich nenne solch ein Spiel ein "1-Ansicht-Spiel". Hier aber geht es nun um Spiele mit mehreren sehr unterschiedlichen Programm-Teilen, die fast wie eigenständige Programme wirken. Also wenn dein Spiel im immer gleichen Spielbild viele unterschiedliche Level hat, dann bist du noch immer falsch hier! Worum geht es dann hier? Das "Wenige-Ansichten-Spiel" Typischerweise hat ein Spielesoftware mehrere Programm-Teile: TitelScreen, Spielansicht, Einstellungs-Screen, Level-Editor. Ich nenne solch ein Spiel "Wenige-Ansichten-Spiel". Du kannst jeden Teil mit einfachen Mitteln der Lektionen I-IV so erstellen, das es zunächst eigenständig läuft. Erst zu einem sehr späten Zeitpunkt führen wir die Teile zu einem Code zusammen. Wir nehmen einmal an Du hast zu Deinem Projekt ein Spiel und einen Level-Editor fertig. Jeder der Teile wurde so programmiert: Zitat: Graphics 800,600,32,2
Variablen definieren Laden von Bilder, Fonts, Sounds ev. Vorbereitungen für das Spiel Repeat - - Cls - - hier kommt der Spielablauf - - Flip Until KeyHit(1) End Function Spieler() - - ... End Function Function .... - - ... End Function Und davon gibt es nun zwei Scripte. Eines für den Spielverlauf und eines für den Level-Editor. Nun willst Du beides zusammenführen. Diese Voraussetzungen müssen erfüllt sein: Zitat: 1.
Stelle sicher, dass in beiden Programmen außer den Startzeilen und der REPEAT/UNTIL nur Funktionen vorkommen. 2. Stelle sicher, dass es in beiden Programmen keine Funktion mit gleichem Namen gibt, es sei denn, es handelt sich um die gleiche Funktion. 3. Stelle sicher, dass ALLE Variablen in beiden Programmen DEFINIERT sind (GLOBAL oder LOCAL) 4. Stelle sicher, dass in beiden Programmen keine globalen Variablen oder Typen mit gleichem Namen vorkommen, es sei denn, es handelt sich um die gleiche Variable. Kapselung des Programms in eine Funktion Zu Sicherstellung dieser vier Bedingungen änderst Du in beiden Programmen den Code so ab: Zitat: Graphics 800,600,32,2
Variablen definieren Laden von Bilder, Fonts, Sounds SpielTeil() End Function SpielTeil() - - ev. Vorbereitungen für das Spiel - - Repeat - - - - Cls - - - - hier kommt der Spielablauf - - - - Flip - - Until KeyHit(1) End Function Function Spieler() - - ... End Function Function .... - - ... End Function Ich habe dir die veränderten Stellen einmal rot markiert. Läuft das so veränderte Programm ebenfalls problemlos an, dann hast Du alle Variablen richtig definiert. Der Mix aus zwei Programmen So, nun mischen wir die beiden Programme zu einem zusammen. Der Code 1 aus dem Spiel ist hier rot dargestellt, der Code 2 aus dem Level-Editor immer grün, Neues erkennst du an der schwarzen Farbe: Zitat: Graphics 800,600,32,2
Variablen definieren Variablen definieren Global AktAnsicht% Laden von Bilder, Fonts, Sounds Laden von Bilder, Fonts, Sounds Repeat - - If AktAnsicht=0 then - - - - SpielTeil() - - ElseIf AktAnsicht=1 Then - - - - LevelEditor() - - Endif Until KeyHit(1) End Function SpielTeil() - - ev. Vorbereitungen für das Spiel - - Repeat - - - - Cls - - - - hier kommt der Spielablauf - - - - Flip - - Until KeyHit(1) - - AktAnsicht=1 End Function Function LevelEditor() - - ev. Vorbereitungen für den Editorl - - Repeat - - - - Cls - - - - hier kommt der Editor-Ablauf - - - - Flip - - Until KeyHit(1) - - AktAnsicht=0 End Function Function Spieler() ----... End Function Function .... - - ... End Function Function SetzeStein() - - ... End Function Function .... - - ... End Function Der Trick ist also eine übergeordnete REPEAT/UNTIL-Schleife, die je nach AktAnsicht% in den einen oder den anderen Programmteil umschaltet. Diese Programmteile enthalten je eine eigene REPEAT/UNTIL-Schleife, die über ESC-Taste verlassen wird und am Ende die Variable AktAnsicht% so umschalten, dass danach in den anderen Teil geschaltet wird. Ein Start-Screen kommt dazu Nun planst du einen Startscreen, von dem aus es in die verschiedenen Unterprogramme geht (z.B. Spiel und Level-Editor.) Wenn Du dich jetzt fragst, wie man diese "übergeordnete Instanz" hineinbekommt, dann liegst Du völlig falsch. Nur für den Benutzer wirkt der Startscreen übergeordnet. Für uns ist es einfach eine 3.Ansicht (hier blau dargestellt): Zitat: Graphics 800,600,32,2
Variablen definieren Variablen definieren Variablen definieren Global AktAnsicht% Laden von Bilder, Fonts, Sounds Laden von Bilder, Fonts, Sounds Laden von Bilder, Fonts, Sounds Repeat - - If AktAnsicht=0 then - - - - StartTeil() - - ElseIf AktAnsicht=1 Then - - - - SpielTeil() - - ElseIf AktAnsicht=2 Then - - - - LevelEditor() - - Endif Until KeyHit(1) End Function StartTeil() - - ev. Vorbereitungen für das Startbild - - Text "Wähle: - - Text " S.....Spiel - - Text " E.....Editor - - Text " ESC...Ende - - Flip - - Repeat - - - - If KeyHit(31) Then AktAnsicht=1 - - - - If KeyHit(18) Then AktAnsicht=2 - - - - If KeyHit(1) Then END - - Until AktAnsicht <> 0 End Function Function SpielTeil() .... ---AktAnsicht=0 End Function Die Variable AktAnsicht% wird nur in der Funktion StartTeil() vom Benutzer geändert. Am Ende des Spiels, des Level-Editors oder der Einstellungsseite geht sie jetzt immer auf 0. Damit wird erreicht, das dann sofort zum StartTeil() gewechselt wird. |
||
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group