Bomberman Klon (Community Tutorial) BMAX

Kommentare anzeigen Worklog abonnieren
Gehe zu Seite Zurück  1, 2

Worklogs Bomberman Klon (Community Tutorial) BMAX

Na, wer bewegt sich denn da?

Dienstag, 24. August 2010 von KirkZero
Heute versuche ich, euch die Klasse TSpieler näher zu bringen, aber vorher erstmal noch ein paar Fehlerkorrekturen aus dem vorigem Eintrag.

Erstmal Danke @BladeRunner
Das es in BMax schon eine Klasse TMap gibt, war mir zwar bekannt... aber da ich sie noch nie benutzt habe, hab ich das wahrscheinlich garnicht wahrgenommen, das ich meine Map Klasse auch so genannt habe. Das muss ich mir dringend abgewöhnen, da ich diesen Fehler nicht zum ersten mal gemacht habe.
Denke aber, nun sollte ich es endlich mal innen Kopf bekommen.
Das heißt natürlich, umbenennen ist angesagt. Ich habe nun aus meiner TMap einfach TKarte gemacht und das natürlich an allen relevanten Stellen im Code ausgetauscht (ebenfalls die Datei umbenannt in TKarte.bmx).

Ausserdem habe ich in der Erstellen Methode von TKarte vergessen, den Inhalt beim setzen von SoftBlöcken auch auf SoftBlöcke zu setzen...
So ist es richtig:
BlitzMax: [AUSKLAPPEN]
					If Check<2 Then
If NeueMap.Feld[X,Y].BlockTile=0 And Rand(0,2)=1 Then
'wenn auf aktuellem Feld noch kein Block ist und Rand(0,2)=1 dann neuen Block setzen
NeueMap.Feld[X,Y].BlockTile =SoftBl
NeueMap.Feld[X,Y].Inhalt =1
BlockZahl:-1 'gesetzten Block abziehen (denn ich will ja nur 100 haben)
End If
End If


NeueMap.Feld[X,Y].Inhalt ist nun = 1 (1 steht für SoftBlock)
und damit da nicht nur 1 steht, sondern ich auch weiss, was da nun drinne ist... habe ich die Werte durch Konstanten ersetzt:
BlitzMax: [AUSKLAPPEN]

If Check<2 Then
If NeueMap.Feld[X,Y].BlockTile=0 And Rand(0,2)=1 Then
'wenn auf aktuellem Feld noch kein Block ist und Rand(0,2)=1 dann neuen Block setzen
NeueMap.Feld[X,Y].BlockTile =SoftBl
NeueMap.Feld[X,Y].Inhalt =SBLOCK
BlockZahl:-1 'gesetzten Block abziehen (denn ich will ja nur 100 haben)
End If
End If

Die Konstanten lauten wie folgt:
BlitzMax: [AUSKLAPPEN]
Const NIX		:Int = 0		'Für den Inhalt der Felder
Const SBLOCK :Int = 1 'einfacher zu merken als pure Zahlen
Const BOMBE :Int = 5
Const HBLOCK :Int = 10

So lassen sich die Werte nun auch viel einfacher ändern (falls das mal nötig sein sollte). Ich muss nun nicht mehr den ganzen Code durchgehen, um die werte zu ändern, sondern ich brauch lediglich die entsprechende Konstante am Anfang der Datei bearbeiten.

So, nun aber zu TSpieler.
Wie bisher auch, erstelle ich zuerst eine "leere" Klasse
BlitzMax: [AUSKLAPPEN]
Type TSpieler

End Type

speichere diese im Hauptordner unter TSpieler.bmx ab und binde sie mittels Include gleich in die MainGame.bmx ein
BlitzMax: [AUSKLAPPEN]
'------------------------------ includes			----------
Include "TKarte.bmx"
Include "TFeld.bmx"
Include "TSpieler.bmx"


Ich fange mal ganz simpel an. Ich erstelle die Klasse erstmal mit folgenden Feldern:
BlitzMax: [AUSKLAPPEN]
Type TSpieler

Field xFeld :Int 'x und y Koordinaten für das entsprechende Feld
Field yFeld :Int 'auf dem sich der Spieler befindet

Field SpielerIMG :TImage 'speichert die Grafik des Spielers

End Type

ich denke, die Kommentare sagen soweit alles. Bemerken möchte ich nur, dass xFeld und yFeld sich auch nur auf das entsprechende Feld (Map.Feld[X,Y]) beziehen... für pixelweise Bewegung führe ich später noch eigene Variablen ein.

Hier noch die eben dürftig gezeichnete Grafik des Spielers (bin leider kein guter Grafiker, aber denke, hierfür reicht es erstmal):
user posted image
Diese Grafik kommt in den Ordner GFX und schimpft sich Robo1.png
Man wird also mit bombenlegenden Robotern spielen Wink

Nun brauch TSpieler noch eine Funktion, mit der man einen neuen Spieler erstellen kann. Der Funktion selber muss man natürlich auch ein paar Parameter übergeben können. Für den Anfang wären dies die x und y Feld-Koordinaten und natürlich Pfad+Name der Spielergrafik, wie auch die Anzahl der Frames des Bildes (soll ja später mal animiert werden) :
BlitzMax: [AUSKLAPPEN]
	Function Erstellen:TSpieler (xFeld:Int,yFeld:Int,ImgPfadName:String,ImgFrames:Int)
Local NeuerSpieler :TSpieler = New TSpieler 'Temporären Spieler erstellen

NeuerSpieler.xFeld = xFeld 'StartKoordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.SpielerIMG = LoadAnimImage (ImgPfadName,TS,TS,0,ImgFrames)
'AnimImage laden mit höhe und breite von 32 (da TS=32)

Return NeuerSpieler 'Temporär erstellten Spieler zurück geben
End Function

Nun erstelle ich in der MainGame.bmx einen neuen Spieler Wink
Dieser soll im Feld mit den koordinaten x=2 und y=2 starten (also links oben), die Grafik liegt im Ordner GFX und nennt sich Robo1.png und hat 20 Frames. Darum rufe ich die Erstellen Funktion wie folgt auf:
BlitzMax: [AUSKLAPPEN]
'------------------------------ Type-Erstellungen	----------
Global Map:TKarte = TKarte.Erstellen(15,15,0,1,2)
Global Spieler1:TSpieler = TSpieler.Erstellen(2,2,"GFX/robo1.png",20)

Nun starte ich die MainGame.bmx und..... und sehe keinen Spieler... warum nicht? Logo, hab noch keine Zeichnen Methode in der Klasse TSpieler... also wäre dass der nächste Schritt:
BlitzMax: [AUSKLAPPEN]
	Method Zeichnen()
DrawImage (SpielerIMG,xFeld*TS,yFeld*TS,0)
End Method

Es ist Wichtig, das xFeld und yFeld immer mit TS (der Tilesize) multipliziert werden, damit der Spieler auch im richtigem Tile der Map gezeichnet wird.

Ausserdem muss ich diese Methode natürlich auch in der Hauptschleife der MainGame.bmx aufrufen:
BlitzMax: [AUSKLAPPEN]
Repeat
Cls 'Backbuffer löschen

Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
Spieler1.Zeichnen()

WaitTimer (Frames) 'da Frames=60 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync

Until KeyHit(KEY_ESCAPE) 'Programm wird beendet, sobald Escape gedrückt wird
End

Lasse ich nun die MainGame.bmx laufen, sieht man das gewünschte Ergebnis:
user posted image

Die vollständige Klasse TSpieler:
BlitzMax: [AUSKLAPPEN]
Type TSpieler

Field xFeld :Int 'x und y Koordinaten für das entsprechende Feld
Field yFeld :Int 'auf dem sich der Spieler befindet

Field SpielerIMG :TImage 'speichert die Grafik des Spielers

Method Zeichnen()
DrawImage (SpielerIMG,xFeld*TS,yFeld*TS,0)
End Method

Function Erstellen:TSpieler (xFeld:Int,yFeld:Int,ImgPfadName:String,ImgFrames:Int)
Local NeuerSpieler :TSpieler = New TSpieler 'Temporären Spieler erstellen

NeuerSpieler.xFeld = xFeld 'StartKoordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.SpielerIMG = LoadAnimImage (ImgPfadName,TS,TS,0,ImgFrames)
'AnimImage laden mit höhe und breite von 32 (da TS=32)

Return NeuerSpieler 'Temporär erstellten Spieler zurück geben
End Function
End Type


Nun will ich mal ein wenig Bewegung in die Sache bringen. Ich gebe der Klasse TSpieler eine Methode namens Steuerung:
BlitzMax: [AUSKLAPPEN]
Method Steuerung() Abstract

diese Methode bleibt absolut "leer" und ausserdem gebe ich ihr das Schlüsselwort Abstract... das heißt, von nun an, kann ich von der Klasse TSpieler keine Instanz mehr erstellen. Stattdessen muss ich nun die Eigenschaften der Klasse TSpieler vererben... die Klasse, welche nun erbt, muss allerdings zwingend die Methode Zeichnen erhalten. Warum ich das mache? Ganz einfach, die Tastaturbelegung jedes Spielers soll natürlich eine andere sein (zumindest beim Spiel an einem Rechner). Lege ich nun die Steuerung schon in der Hauptklasse (TSpieler) fest, so hat jeder Spieler die gleichen Tasten zum steuern (ausser natürlich, ich überschreibe die Methode)
An die erfahrenen Programierer... sinnvoll? Oder doch Denkfehler?

Also wird nun die Klasse TSpieler unsere "Mutter"
Hier die komplette Klasse bis hier hin:
BlitzMax: [AUSKLAPPEN]
Type TSpieler

Field xFeld :Int 'x und y Koordinaten für das entsprechende Feld
Field yFeld :Int 'auf dem sich der Spieler befindet

Field SpielerIMG :TImage 'speichert die Grafik des Spielers

Method Steuerung() Abstract

Method Zeichnen()
DrawImage (SpielerIMG,xFeld*TS,yFeld*TS,0)
End Method

Function Erstellen:TSpieler (xFeld:Int,yFeld:Int,ImgPfadName:String,ImgFrames:Int)
Local NeuerSpieler :TSpieler = New TSpieler 'Temporären Spieler erstellen

NeuerSpieler.xFeld = xFeld 'StartKoordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.SpielerIMG = LoadAnimImage (ImgPfadName,TS,TS,0,ImgFrames)
'AnimImage laden mit höhe und breite von 32 (da TS=32)

Return NeuerSpieler 'Temporär erstellten Spieler zurück geben
End Function
End Type


Die "Mutterklasse" vererbt nun all ihre Eigenschaften an ihr "Kind" TSpieler1. TSpieler1 erbt nun alle Felder, Funktionen und Methoden, welche auch die "Mutter" (TSpieler) besitzt und wird "gezwungen" eine Methode namens Steuerung zu besitzen (wegen des Schlüsselwortes Abstract hinter der Methode Steuerung in der "Mutterklasse")

Dann will ich mal vererben Wink
Ich bleibe in der Datei TSpieler.bmx. Lege unter dem Type TSpieler einen neuen an, welchen ich TSpieler1 nenne und vererbe diesem mit dem Schlüsselwort Extends alles von der Mutterklasse:
BlitzMax: [AUSKLAPPEN]
Type TSpieler

Field xFeld :Int 'x und y Koordinaten für das entsprechende Feld
Field yFeld :Int 'auf dem sich der Spieler befindet

Field SpielerIMG :TImage 'speichert die Grafik des Spielers

Method Steuerung() Abstract
'Von dieser Klasse kann nun keine Instanz mehr gebildet werden
'man muss nun ihre Eigenschaften an eine andere Klasse vererben!!!
'die Klasse, welche erbt, muss allerdings zwingend eine Methode
'namens Steuerung haben!!!!

Method Zeichnen()
DrawImage (SpielerIMG,xFeld*TS,yFeld*TS,0)
End Method

Function Erstellen:TSpieler (xFeld:Int,yFeld:Int,ImgPfadName:String,ImgFrames:Int)
Local NeuerSpieler :TSpieler = New TSpieler 'Temporären Spieler erstellen

NeuerSpieler.xFeld = xFeld 'StartKoordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.SpielerIMG = LoadAnimImage (ImgPfadName,TS,TS,0,ImgFrames)
'AnimImage laden mit höhe und breite von 32 (da TS=32)

Return NeuerSpieler 'Temporär erstellten Spieler zurück geben
End Function
End Type


Type TSpieler1 Extends TSpieler 'Extends vererbt alle Eigenschaften von TSpieler an diese Klasse
'diese Klasse besitzt alle Felder, Funktionen und Methoden von TSpieler
'und MUSS eine Methode namens Steuerung haben

Method Steuerung() 'diese Methode MUSS sein... siehe oben Wink

End Method

End Type


Starte ich nun das Programm, so erhalte ich einen Fehler, da ich nach wie vor eine Instanz der Klasse TSpieler erstelle. Darum werde ich nun die MainGame.bmx ändern und unseren Spieler von der Klasse TSpieler1 erstellen:
BlitzMax: [AUSKLAPPEN]
'------------------------------ Type-Erstellungen	----------
Global Map:TKarte = TKarte.Erstellen(15,15,0,1,2)
Global Spieler1:TSpieler1 = TSpieler1.Erstellen(2,2,"GFX/robo1.png",20)


nun erhalte ich aber immernoch eine Fehlermeldung, da die Erstellen Funktion von TSpieler original vererbt wurde und somit dort, auch wenn ich TSpieler1.Erstellen(2,2,"GFX/robo1.png",20) aufrufe, versucht wird, einen TSpieler zu erstellen.
Also, Erstellen Funktion aus TSpieler rausnehmen und in TSpieler1 einfügen und entsprechend ändern:
BlitzMax: [AUSKLAPPEN]
Type TSpieler

Field xFeld :Int 'x und y Koordinaten für das entsprechende Feld
Field yFeld :Int 'auf dem sich der Spieler befindet

Field SpielerIMG :TImage 'speichert die Grafik des Spielers

Method Steuerung() Abstract
'Von dieser Klasse kann nun keine Instanz mehr gebildet werden
'man muss nun ihre Eigenschaften an eine andere Klasse vererben!!!
'die Klasse, welche erbt, muss allerdings zwingend eine Methode
'namens Steuerung haben!!!!

Method Zeichnen()
DrawImage (SpielerIMG,xFeld*TS,yFeld*TS,0)
End Method

Function Erstellen() Abstract 'Erbende Klasse muss eine Funktion namens Erstellen haben!

End Type


Type TSpieler1 Extends TSpieler 'Extends vererbt alle Eigenschaften von TSpieler an diese Klasse
'diese Klasse besitzt alle Felder, Funktionen und Methoden von TSpieler
'und MUSS eine Methode namens Steuerung haben

Method Steuerung() 'diese Methode MUSS sein... siehe oben Wink

End Method

Function Erstellen:TSpieler1 (xFeld:Int,yFeld:Int,ImgPfadName:String,ImgFrames:Int)
Local NeuerSpieler :TSpieler1 = New TSpieler1 'Temporären Spieler erstellen

NeuerSpieler.xFeld = xFeld 'StartKoordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.SpielerIMG = LoadAnimImage (ImgPfadName,TS,TS,0,ImgFrames)
'AnimImage laden mit höhe und breite von 32 (da TS=32)

Return NeuerSpieler 'Temporär erstellten Spieler zurück geben
End Function


End Type

Klingt kompliziert, aber ich weiss auch grad nicht so richtig, wie ich es besser erklären soll Sad
Vielleicht kann mir da einer von den Veteranen helfen???
Und gleich noch ne FRAGE: kann ich die Erstellen Funktion nicht irgendwie in der Mutterklasse lassen aber die erbende Klasse dann doch eine Funktion Erstellen:TSpieler1 hat anstatt erstellen:Tspieler ???


So... sollte sich da mit der Erstellen Funktion noch ne bessere Lösung ergeben, wird das natürlich editiert, aber nun weiter Wink

Jetzt lege ich die Steuerung für die Klasse TSpieler1 fest:
BlitzMax: [AUSKLAPPEN]
	Method Steuerung() 'diese Methode MUSS sein... siehe oben Wink
If KeyDown(KEY_UP) 'wenn Pfeiltaste OBEN gedrückt wird
yFeld:-1
ElseIf KeyDown(KEY_DOWN) 'wenn Pfeiltaste UNTEN gedrückt wird
yFeld:+1
ElseIf KeyDown(KEY_LEFT) 'wenn Pfeiltaste LINKS gedrückt wird
xFeld:-1
ElseIf KeyDown(KEY_RIGHT) 'wenn Pfeiltaste RECHTS gedrückt wird
xFeld:+1
End If

End Method

Ich benutze hier mit Absicht IF... ElseIF... usw... somit ist keine diagonale Bewegung möglich! Würde ich statt ElseIF immer eine neue IF Abfrage starten, wäre es möglich, wenn ich z.B. UNTEN und RECHTS drücke, das die Figur sich diagonal nach unten rechts bewegt... das will ich aber nicht Wink

Starten wir nun die MainGame.bmx passiert absolut garnix...
Warum? Na... hab vergessen die Steuerungsmethode in die Hauptschleife einzubinden... aber das hole ich schnell mal nach:
BlitzMax: [AUSKLAPPEN]
Repeat
Cls 'Backbuffer löschen

Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
Spieler1.Zeichnen()
Spieler1.Steuerung() 'Steuerung von Spieler 1 wird abgefragt

WaitTimer (Frames) 'da Frames=60 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync

Until KeyHit(KEY_ESCAPE) 'Programm wird beendet, sobald Escape gedrückt wird
End


Super... nun kann ich mich mit hilfe der Pfeiltasten bewegen... das ganze passiert allerdings ziemlich schnell und durch "Mauern" kann ich auch noch laufen...
Bevor ich das nun ändere... hier erstmal der Komplette Code (inklusive .exe) zum Download:

https://www.blitzforum.de/upload/file.php?id=9373

Jetzt kümmer ich mich erstmal darum, das man sich in normaler Geschwindigkeit bewegt...
Damit das passiert, füge ich in die Mutterklasse TSpieler zwei neue Felder ein:
BlitzMax: [AUSKLAPPEN]
	Field BewegungsTimer	:Int = MilliSecs()
Field BewegungsPause :Int = 250


es ist wichtig, dass ich diese in die Mutterklasse TSpieler einfüge und nicht in die erbende Klasse TSpieler1! Denn diese beiden neuen Felder sollen vererbt werden, damit ich sie nicht in jeder neuen erbenden Klasse mit eintragen muss... das spart Schreibarbeit.
Merken: alles, was für jede erbende Klasse zutreffen soll, deklariert man in der "Mutterklasse" und alles was ausschliesslich die erbende Klasse betrifft (in unserem Beispiel die Steuerung von TSpieler1, da sie für jeden Spieler anders sein wird) deklariert man in der erbenden Klasse...

Was bedeuten die beiden neuen Felder nun:
ich gebe dem Feld BewegungsTimer die Zeit, welche seit dem Systemstart vergangen ist als Wert. Das ganze wird in MilliSekunden übergeben.
1000 MilliSekunden = 1 Sekunde
Da ich nun erstmal möchte, das sich der Spieler nur jede viertel Sekunde um einen Schrit bewegen kann, setze ich das Feld BewegungsPause auf 250 (1000 Millisekunden = 1 Sekunde... 250 Millisekunden = eine viertel Sekunde)
Und nun wird das Ganze in die Steuerungs Methode von TSpieler1 eingebunden:
BlitzMax: [AUSKLAPPEN]
	Method Steuerung() 'diese Methode MUSS sein... siehe oben Wink
If KeyDown(KEY_UP) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste OBEN gedrückt wird
yFeld:-1
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_DOWN) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste UNTEN gedrückt wird
yFeld:+1
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_LEFT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste LINKS gedrückt wird
xFeld:-1
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste RECHTS gedrückt wird
xFeld:+1
BewegungsTimer = MilliSecs()
End If

End Method


BlitzMax: [AUSKLAPPEN]
If KeyDown(KEY_UP) And MilliSecs() > BewegungsTimer+BewegungsPause


Bedeutet:
wenn Pfeiltaste nach OBEN gedrückt wird UND die vergangene SystemZeit (seit Start) GRÖßER ist als die zuvor gespeicherte Zeit PLUS der viertel Sekunde (da BewegungsPause 250 beträgt also wenn seit der letzten Bewegung 250 Millisekunden vergangen sind)
DANN:

BlitzMax: [AUSKLAPPEN]
			yFeld:-1
BewegungsTimer = MilliSecs()


bewegt sich der Spieler um ein Feld nach oben (yFeld:-1)
und der BewegungsTimer erhält die neue Zeit, ab der die Bewegung stattgefunden hat (BewegungsTimer = MilliSecs() )
Somit kann die nächste Bewegung erst 250 Millisekunden Später stattfinden...

Arghhhh... hoffe man versteht, was ich damit da sagen will!!!


Das solls dann auch erstmal gewesen sein. Im nächsten Worklogeintrag werde ich die Steuerung so modifizieren, dass man auch nicht mehr durch Blöcke hindurch "gehen" kann und ausserdem werde ich damit beginnen, den Spieler Pixelweise zu bewegen...

Hier noch der komplette Code bis zu dieser Stelle (inklusive .EXE):

https://www.blitzforum.de/upload/file.php?id=9374


An dieser Stelle würde ich gerne nochmal wissen... Kann man als Anfänger (der die Grundlagen natürlich beherrscht) hier überhaupt was lernen... bzw, kann ich überhaupt Wissen vermitteln? Ich weiß halt von mir selber, dass ich nicht sonderlich gut etwas beschreiben kann und hab mir halt auch überlegt... "Mensch, wäre ich nun auf dem Stand, den ich vor 3 Monaten hatte... würde ich mein eigenes Zeug überhaupt verstehen???
Sollte ich nämlich niemandem mit meiner Schreibweise etwas vermitteln können (wobei ich ja nichtmal weiss, ob das alles hier überhaupt einigermassen richtig ist, da ich ja selber noch so ziemlich blutiger Anfänger bin), so würde ich das ganze nicht mehr so ausführlich machen und alles mehr so schreiben, dass mich die Elite hier auf meine Fehler hinweisen kann (denn ich schreibe das ja auch für mich, um euch zu zeigen, wie ich manche Sachen regele, damit ihr mir zeigt, wie es besser geht).
Also würde mich übelst über positive wie auch negative Kritik freuen und VORALLEM auf korrekturen meiner Programmierweise!!!

Ich bedanke mich schonmal recht herzlich!!!

MfG,
Kirk

Die Map (TMap + TFeld)

Freitag, 20. August 2010 von KirkZero
Hatte letzte Nacht (also heute Morgen) noch Lust, an der Map zu arbeiten.
Hat schon seinen Vorteil, wenn man erst um 16 uhr zur Arbeit muss. Nachts kann ich dann immer am Besten am Programm arbeiten, da ich dann Ruhe hab und besser nachdenken kann Wink

Ich habe erstmal damit begonnen mir die Rohlinge der beiden Types anzulegen und abzuspeichern.
Also jeh eine Datei mit

BlitzMax: [AUSKLAPPEN]
Type TMap

End Type

als TMap.bmx im Hauptordner abgespeichert
und eine Datei mit

BlitzMax: [AUSKLAPPEN]
Type TFeld

End Type

als TFeld.bmx im Hauptordner abgespeichert.

Als nächstes binde ich diese auch gleich mit Include in die MainGame.bmx ein. Hab mir das so angewöhnt, immer erst ein "leeren" Type abzuspeichern und dann gleich einzubinden (weiss auch nicht genau warum, hat mich wahrscheinlich immer genervt, wenn ich ne Fehlermeldung bekam, weil ich mal wieder die Datei vergessen habe einzubinden)

Ausserdem habe ich eine neue Konstante namens TS mit dem Wert 32 eingeführt. TS steht für TileSize und da die Tiles das Format 32*32 haben hat sie halt auch diesen Wert

Hier ein Auszug aus der MeinGame.bmx (habe nun wegen der besseren Übersicht auch ein paar Tabs mehr eingefügt)

BlitzMax: [AUSKLAPPEN]
SuperStrict 'zwingt mich, sauber zu programmieren Wink

'------------------------------ includes ----------
Include "TMap.bmx"
Include "TFeld.bmx"

'------------------------------ Grafikmodus ----------
Const BREITE :Int = 800
Const HOEHE :Int = 600 'Ich setze die Bildschirmbreite und Höhe als Konstante
Global Vollbild :Int = False 'Ob Vollbild oder nicht, soll später der User entscheiden, darum keine Konstante

Graphics BREITE , HOEHE , Vollbild 'Bildschirmmodus wird gesetzt
'------------------------------ Vorbereitungen ----------
Const TS :Int = 32 'Tilegröße (32*32)

Global Frames :TTimer = CreateTimer (60) 'damit das Spiel auf jedem Rechner gleichschnell läuft setze ich einen Timer

SeedRnd (MilliSecs()) 'Da ich den "Zufall" im Spiel benötige,füttere ich ihn schonmal mit der Zeit seit dem Systemstart


@Xeres
Die Schreibweise der Timer habe ich so noch nie benutzt, werd ich mir aber unbedingt mal anschauen, da es dann auch besser zum Rest passt... Danke für den Hinweis

EDIT:
Ich benutze ab jetzt öfters die Wörter SoftBlock und HardBlock
also, ein SoftBlock ist ein Zerstörbarer Block und ein HardBlock ist unzerstörbar!!!

Nun nehme ich mir ersteinmal TFeld.bmx vor:
Was brauche ich für Informationen über jedes Feld? Ich habe mir das fürs Erste so gedacht:
BlitzMax: [AUSKLAPPEN]
Type TFeld
Const BODENFRAMES :Int=5
Const BLOCKFRAMES :Int=3
Field BodenTilesIMG :TImage = LoadAnimImage("gfx/boden.png",32,32,0,BODENFRAMES)
Field BlockTilesIMG :TImage = LoadAnimImage("gfx/block.png",32,32,0,BLOCKFRAMES)

Field BodenTile :Int 'die Bodenfliesen. Index für AnimImage welches die Bodenfliesen enthält
Field BlockTile :Int 'die Blöcke. Index für AnimImage. 0=erstes Tile im AnimImage leerer/durchsichtiger Block
Field Inhalt :Int '0=begehbar/kein Block, 1=zerstörbarer Block, 4=Bombe, 5=unzerstöbar/unpassierbar
'Field Explosion :Int noch nicht beachten... der Gedanke dahinter ist noch nicht ganz fertig gedacht


End Type

Erklärung dazu:
BodenTilesIMG und BlockTilesIMG enthalten das jeweilige Image für die BodenTiles bzw für die Blöcke. Da das BodenTile Image z.Z. aus 5 Frames besteht, habe ich dafür eine Konstante (BODENFRAMES) eingeführt, damit ich das Später leichter ändern kann, da dies ja nun erstmal nur ein TestImage ist. Diese Konstante benutze ich dann natürlich auch in der LoadAnimImage Funktion. Genau so verhält es sich mit dem BlockTile Image.

BodenTile enthält die Information darüber, welches BodenTile für das Feld benutzt wird
BlockTile enthält die information darüber, ob und wenn, welches BlockTile benutzt wird.
Das erste Frame in block.png ist durchsichtig, sollte also kein Block auf dem Feld sein, so ist der Wert=0
Inhalt enthält die Information, WAS genau für ein Block (oder sonstiges) sich auf dem Feld befindet. auch die Information, ob eine Bombe dort liegt, wird hier gespeichert. Das mache ich deshalb, weil ich später gerne auch Items einfügen würde, mit deren Hilfe man über SoftBlöcke oder Bomben einfach drüber weggehen kann.

Achja... hier die verwendeten Grafiken:
Die BodenTiles
user posted image
und die Blöcke
user posted image

So weit, so gut. Nun ab zur TMap.bmx
BlitzMax: [AUSKLAPPEN]
Type TMap

Field Feld :TFeld[,] 'Dynamisches Array für die Map, damit keine Größenbeschränkungen entstehen
Field MX :Int 'Breite der Map
Field MY :Int 'Höhe der Map
End Type

(hmmm... irgendwie werden die Tabs nicht richtig angezeigt *grml*)

Feld ist ein Array vom Typ TFeld (TFeld.bmx) dieses wird nicht dimensioniert, da ich mit dem Gedanken spiele, im Story Modus evtl auch größere, scrollbare Maps zu verwenden.
MX und MY stehen für die Breite und die Höhe der Map

Nun wird es Zeit, etwas auf den Bildschirm zu zaubern...
Erstmal reicht eine Standart Bomberman Map ohne zerstörbare Blöcke. Lediglich BodenTiles, einen Rand aus unzerstörbaren Blöcken und das "Schachähnliche" Raster aus unzerstörbaren Blöcken, so wie hier:

user posted image

PS: Vorerst ist alles Hardcode, später werde ich mich aber noch um einen MapEditor kümmern Wink

Die neue TMap.bmx :
BlitzMax: [AUSKLAPPEN]
Type TMap

Field Feld :TFeld[,] 'Dynamisches Array für die Map, damit keine Größenbeschränkungen entstehen
Field MX :Int 'Breite der Map
Field MY :Int 'Höhe der Map


Function Erstellen:TMap(MX:Int,MY:Int,Boden:Int,HardBl:Int,SoftBl:Int)
Local NeueMap:TMap = New TMap 'hier wird die neue Map erstmal Temporär gespeichert

NeueMap.Feld=New TFeld[MX+1,MY+1] 'Map Dimensionieren
NeueMap.MX=MX 'Breite der Map speichern
NeueMap.MY=MY 'Höhe der Map speichern
'#############################################
'# STANDARTMAP ERSTELLEN #
'#############################################
For Local Y:Int=1 To MY 'jedes Feld von 1 bis zur Höhe der Map
For Local X:Int=1 To MX 'jedes Feld von 1 bis zur Breite der Map
NeueMap.Feld[X,Y] = TFeld.Erstellen(Boden) 'die einzelnen Felder werden erstellt und mit dem BodenTile gefüllt
'siehe TFeld.Erstellen Funktion
If X=1 Or Y=1 Or X=MX Or Y=MY Then
NeueMap.Feld[X,Y].BlockTile =HardBl
NeueMap.Feld[X,Y].Inhalt =5
End If
'haben X oder Y eine Wert, welcher den Rand der Map darstellt, so wird das
'BlockTile auf einen HardBlock gesetzt. Auf diese Weise zeichne ich den Rand
'der Map

If X=3 Or X=5 Or X=7 Or X=9 Or X=11 Or X=13 Then
If Y=3 Or Y=5 Or Y=7 Or Y=9 Or Y=11 Or Y=13 Then
NeueMap.Feld[X,Y].BlockTile =HardBl
NeueMap.Feld[X,Y].Inhalt =5
End If
End If
'haben der X und der Y Wert eine Position erreicht, die wichtig für das
'Schachbrettähnliche Muster sind, so wird ebenfalls ein HardBlock an die
'Position gesetzt
Next
Next

Return NeueMap 'hiermit gebe ich die temporär erstellte Map zurück
End Function

End Type

ich weiß, was ich da tue, nur fällt es mir schwer, es in Worte zu fassen. Hab darum den Code mal Dokumentiert und hoffe, das ist so verständlich!???

Zu den Übergabewerten der Funktion:
BlitzMax: [AUSKLAPPEN]
Function Erstellen:TMap(MX:Int,MY:Int,Boden:Int,HardBl:Int,SoftBl:Int)

MX übergibt die Breite der Map
MY übergibt die Höhe der Map
Boden übergibt den Index für das Bodentile der Map
HardBl übergibt den Index für den verwendeten HardBlock
SoftBl übergibt den Index für den verwendeten SoftBlock

Da in der Funktion auch gleich die TFeld.Erstellen Funktion aufgerufen wird, hier ist sie:
BlitzMax: [AUSKLAPPEN]
	Function Erstellen:TFeld(Boden:Int)
Local NeuesFeld:TFeld = New TFeld
NeuesFeld.BodenTile=Boden
Return NeuesFeld
End Function

Boden übergibt einfach nur das BodenTile, welches benutzt wird

Nun will ich natürlich auch etwas auf dem Bildschirm sehen...
Die Geburt der Zeichnen Methode

Für TMap:
BlitzMax: [AUSKLAPPEN]
	Method Zeichnen()
For Local Y:Int=1 To MX
For Local X:Int=1 To MY
Feld[X,Y].Zeichnen(X,Y) 'Übergibt X und Y Werte an Feld.Zeichnen
Next
Next
End Method

Für TFeld:
BlitzMax: [AUSKLAPPEN]
	Method Zeichnen(x:Int,y:Int) 'die Arraywerte für X und Y werden übergeben
DrawImage(BodenTilesIMG,x*TS,y*TS,BodenTile) 'und beim Zeichnen mit der TileSize (TS=32)
DrawImage(BlockTilesIMG,x*TS,y*TS,BlockTile) 'multipliziert, damit sie den richtigen Abstand zueinander haben
End Method


Was ich an dieser Stelle mal bemerkt habe, es ist garnicht so einfach, seine Gedanken in Worte zu fassen, beim Schreiben des Codes weiss ich, was ich mir wo, wie dabei gedacht habe, nur das dann auch in Worte zu bekommen.... aber hoffe, die Codedokumentation ist verständlich genug!!!
Ansonsten... immer FRAGEN!!! Wink

so, nun hab ich alles zusammen, um die map zu Zeichnen, alles was ich jetzt noch tun muss, ist sie zu erstellen. Das wiederum erledige ich "erstmal" in der MeinGame.bmx:
BlitzMax: [AUSKLAPPEN]
'------------------------------ Type-Erstellungen	----------
Global Map:TMap = TMap.Erstellen(15,15,0,1,2)
'Höhe+Breite=15, BodenTile=0 (wäre dann das GrassTile, als HardBlock nehme ich 1 und als SoftBlock 2

'------------------------------ Hauptschleife ----------
Repeat
Cls 'Backbuffer löschen

Map.Zeichnen()

WaitTimer (Frames) 'da Frames=60 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync

Until KeyHit(KEY_ESCAPE) 'Programm wird beendet, sobald Escape gedrückt wird
End

Der Vollständigkeit halber, nochmal alle 3 Dateien Komplett:
MainGame.bmx
BlitzMax: [AUSKLAPPEN]
SuperStrict 'zwingt mich, sauber zu programmieren Wink

'------------------------------ includes ----------
Include "TMap.bmx"
Include "TFeld.bmx"

'------------------------------ Grafikmodus ----------
Const BREITE :Int = 800
Const HOEHE :Int = 600 'Ich setze die Bildschirmbreite und Höhe als Konstante
Global Vollbild :Int = False 'Ob Vollbild oder nicht, soll später der User entscheiden, darum keine Konstante

Graphics BREITE , HOEHE , Vollbild 'Bildschirmmodus wird gesetzt
'------------------------------ Vorbereitungen ----------
Const TS :Int = 32 'Tilegröße (32*32)

Global Frames :TTimer = CreateTimer (60) 'damit das Spiel auf jedem Rechner gleichschnell läuft setze ich einen Timer

SeedRnd (MilliSecs()) 'Da ich den "Zufall" im Spiel benötige,füttere ich ihn schonmal mit der Zeit seit dem Systemstart
'------------------------------ Grafiken laden ----------



'------------------------------ Sounds laden ----------



'------------------------------ Type-Erstellungen ----------
Global Map:TMap = TMap.Erstellen(15,15,0,1,2)


'------------------------------ Hauptschleife ----------
Repeat
Cls 'Backbuffer löschen

Map.Zeichnen()

WaitTimer (Frames) 'da Frames=60 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync

Until KeyHit(KEY_ESCAPE) 'Programm wird beendet, sobald Escape gedrückt wird
End

TMap.bmx:
BlitzMax: [AUSKLAPPEN]
Type TMap

Field Feld :TFeld[,] 'Dynamisches Array für die Map, damit keine Größenbeschränkungen entstehen
Field MX :Int 'Breite der Map
Field MY :Int 'Höhe der Map


Method Zeichnen()
For Local Y:Int=1 To MX
For Local X:Int=1 To MY
Feld[X,Y].Zeichnen(X,Y) 'Übergibt X und Y Werte an Feld.Zeichnen
Next
Next
End Method

Function Erstellen:TMap(MX:Int,MY:Int,Boden:Int,HardBl:Int,SoftBl:Int)
Local NeueMap:TMap = New TMap 'hier wird die neue Map erstmal Temporär gespeichert

NeueMap.Feld=New TFeld[MX+1,MY+1] 'Map Dimensionieren
NeueMap.MX=MX 'Breite der Map speichern
NeueMap.MY=MY 'Höhe der Map speichern
'#############################################
'# STANDARTMAP ERSTELLEN #
'#############################################
For Local Y:Int=1 To MY 'jedes Feld von 1 bis zur Höhe der Map
For Local X:Int=1 To MX 'jedes Feld von 1 bis zur Breite der Map
NeueMap.Feld[X,Y] = TFeld.Erstellen(Boden) 'die einzelnen Felder werden erstellt
'siehe TFeld.Erstellen Funktion
If X=1 Or Y=1 Or X=MX Or Y=MY Then
NeueMap.Feld[X,Y].BlockTile =HardBl
NeueMap.Feld[X,Y].Inhalt =5
End If
'haben X oder Y eine Wert, welcher den Rand der Map darstellt, so wird das
'BlockTile auf einen HardBlock gesetzt. Auf diese Weise zeichne ich den Rand
'der Map

If X=3 Or X=5 Or X=7 Or X=9 Or X=11 Or X=13 Then
If Y=3 Or Y=5 Or Y=7 Or Y=9 Or Y=11 Or Y=13 Then
NeueMap.Feld[X,Y].BlockTile =HardBl
NeueMap.Feld[X,Y].Inhalt =5
End If
End If
'haben der X und der Y Wert eine Position erreicht, die wichtig für das
'Schachbrettähnliche Muster sind, so wird ebenfalls ein HardBlock an die
'Position gesetzt
Next
Next

Return NeueMap 'hiermit gebe ich die temporär erstellte Map zurück
End Function

End Type

und TFeld.bmx:
BlitzMax: [AUSKLAPPEN]
Type TFeld
Const BODENFRAMES :Int=5
Const BLOCKFRAMES :Int=3
Field BodenTilesIMG :TImage = LoadAnimImage("gfx/boden.png",32,32,0,BODENFRAMES)
Field BlockTilesIMG :TImage = LoadAnimImage("gfx/block.png",32,32,0,BLOCKFRAMES)

Field BodenTile :Int 'die Bodenfliesen. Index für AnimImage welches die Bodenfliesen enthält
Field BlockTile :Int 'die Blöcke. Index für AnimImage. 0=erstes Tile im AnimImage leerer/durchsichtiger Block
Field Inhalt :Int '0=begehbar/kein Block, 1=zerstörbarer Block, 4=Bombe, 5=unzerstöbar/unpassierbar
'Field Explosion :Int noch nicht beachten... der Gedanke dahinter ist noch nicht ganz fertig gedacht

Method Zeichnen(x:Int,y:Int) 'die Arraywerte für X und Y werden übergeben
DrawImage(BodenTilesIMG,x*TS,y*TS,BodenTile) 'und beim Zeichnen mit der TileSize (TS=32)
DrawImage(BlockTilesIMG,x*TS,y*TS,BlockTile) 'multipliziert, damit sie den richtigen Abstand zueinander haben
End Method

Function Erstellen:TFeld(Boden:Int)
Local NeuesFeld:TFeld = New TFeld
NeuesFeld.BodenTile=Boden
Return NeuesFeld
End Function


End Type


Wenn nun die Grafikdateien im Ordner GFX abgespeichert sind, und man MainGame.bmx, TMap.bmx und Tfeld.bmx im Hauptordner liegen hat, so wird beim Ausführen der MeinGame.bmx die StandartMap auf dem Bildschirm dargestellt.

Soooo... nun will ich die Map mal mit SoftBlöcken füllen, dabei aber die 4 Startecken der Spieler frei lassen.
So wie hier:
user posted image
Also zurück in die TMap.bmx und die Erstellen Funktion ein wenig bearbeiten:
BlitzMax: [AUSKLAPPEN]
	Function Erstellen:TMap(MX:Int,MY:Int,Boden:Int,HardBl:Int,SoftBl:Int)
Local NeueMap:TMap = New TMap 'hier wird die neue Map erstmal Temporär gespeichert

NeueMap.Feld=New TFeld[MX+1,MY+1] 'Map Dimensionieren
NeueMap.MX=MX 'Breite der Map speichern
NeueMap.MY=MY 'Höhe der Map speichern
'#############################################
'# STANDARTMAP ERSTELLEN #
'#############################################
For Local Y:Int=1 To MY 'jedes Feld von 1 bis zur Höhe der Map
For Local X:Int=1 To MX 'jedes Feld von 1 bis zur Breite der Map
NeueMap.Feld[X,Y] = TFeld.Erstellen(Boden) 'die einzelnen Felder werden erstellt
'siehe TFeld.Erstellen Funktion
If X=1 Or Y=1 Or X=MX Or Y=MY Then
NeueMap.Feld[X,Y].BlockTile =HardBl
NeueMap.Feld[X,Y].Inhalt =5
End If
'haben X oder Y eine Wert, welcher den Rand der Map darstellt, so wird das
'BlockTile auf einen HardBlock gesetzt. Auf diese Weise zeichne ich den Rand
'der Map

If X=3 Or X=5 Or X=7 Or X=9 Or X=11 Or X=13 Then
If Y=3 Or Y=5 Or Y=7 Or Y=9 Or Y=11 Or Y=13 Then
NeueMap.Feld[X,Y].BlockTile =HardBl
NeueMap.Feld[X,Y].Inhalt =5
End If
End If
'haben der X und der Y Wert eine Position erreicht, die wichtig für das
'Schachbrettähnliche Muster sind, so wird ebenfalls ein HardBlock an die
'Position gesetzt
Next
Next
'#############################################
'# MAP MIT SOFTBLÖCKEN FÜLLEN #
'# DABEI SPIELER-STARTECKEN FREI LASSEN #
'#############################################

For Local Y:Int=1 To MY
For Local X:Int=1 To MX
Local Check:Int=0
If Y=2 Or Y=3 Or Y=MY-2 Or Y=MY-1 Then Check:+1
If X=2 Or X=3 Or X=MX-2 Or X=MX-1 Then Check:+1

If Check<2 Then
If NeueMap.Feld[X,Y].BlockTile=0
NeueMap.Feld[X,Y].BlockTile=SoftBl

End If
End If
Next
Next

Return NeueMap 'hiermit gebe ich die temporär erstellte Map zurück
End Function


ab hier wird es dann interessant:
BlitzMax: [AUSKLAPPEN]
		'#############################################
'# MAP MIT SOFTBLÖCKEN FÜLLEN #
'# DABEI SPIELER-STARTECKEN FREI LASSEN #
'#############################################

For Local Y:Int=1 To MY 'ich gehe die gesammte Map durch
For Local X:Int=1 To MX
Local Check:Int=0 'setze eine CheckVariable auf 0
If Y=2 Or Y=3 Or Y=MY-2 Or Y=MY-1 Then Check:+1
'sollte sich die momentane Y Position auf einer StartEcken-Koordinate
'befinden erhöhe ich Check um 1
If X=2 Or X=3 Or X=MX-2 Or X=MX-1 Then Check:+1
'sollte sich die momentane X Position auf einer StartEcken-Koordinate
'befinden erhöhe ich Check ebenfalls um 1

If Check<2 Then 'ist Check <2 dann befindet sich der Zeiger auf keiner StartEcken-Koordinate und es kann ein SoftBlock gezeichnet werden
If NeueMap.Feld[X,Y].BlockTile=0 'jedoch nur, wenn sich dort noch kein Block befindet
NeueMap.Feld[X,Y].BlockTile=SoftBl 'SoftBlock wird gesetzt

End If
End If
Next
Next

Habe den Code erneut zum Verständnis Dokumentiert.
Die Startecken befinden sich einmal oben links, also bei X=2,X=3,Y=2 und Y=3
oben rechts, also bei X=MX-1 (Maximale breite der Map-1), X=MX-2 (Maximale Breite der Map-2), Y=2 und Y=3
unten links, also bei X=2, X=3, Y=MY-1 (Maximale Höhe der Map-1) und Y=MY-2 (maximale Höhe der MAp-2)
und unten rechts, also bei X=MX-1,X=MX-2,Y=MY-1 und Y=MY-2
so kommen die If Then Abfragen zustande
Trifft ein X Wert zu, so wird Check um 1 erhöht, trifft dann noch ein Y Wert zu, so wird Check wieder um 1 erhöht.
und da Softblöcke nur gesetzt werden sollen, wenn Check <2 ist, bleiben die Start-Ecken frei Wink

nun will ich aber nicht alles mit Softblöcken füllen, sondern es sollen lediglich 100 Stück per Zufall gesetzt werden und in der Mitte soll ebenfalls ein freies Feld bleiben (Dort soll später mein erstes Monster starten Wink )
So wie hier gezeigt:
user posted image

Dazu natürlich wieder die Erstellen Funktion von TMap bearbeitet:
BlitzMax: [AUSKLAPPEN]
	Function Erstellen:TMap(MX:Int,MY:Int,Boden:Int,HardBl:Int,SoftBl:Int)
Local NeueMap:TMap = New TMap 'hier wird die neue Map erstmal Temporär gespeichert

NeueMap.Feld=New TFeld[MX+1,MY+1] 'Map Dimensionieren
NeueMap.MX=MX 'Breite der Map speichern
NeueMap.MY=MY 'Höhe der Map speichern
'#############################################
'# STANDARTMAP ERSTELLEN #
'#############################################
For Local Y:Int=1 To MY 'jedes Feld von 1 bis zur Höhe der Map
For Local X:Int=1 To MX 'jedes Feld von 1 bis zur Breite der Map
NeueMap.Feld[X,Y] = TFeld.Erstellen(Boden) 'die einzelnen Felder werden erstellt
'siehe TFeld.Erstellen Funktion
If X=1 Or Y=1 Or X=MX Or Y=MY Then
NeueMap.Feld[X,Y].BlockTile =HardBl
NeueMap.Feld[X,Y].Inhalt =5
End If
'haben X oder Y eine Wert, welcher den Rand der Map darstellt, so wird das
'BlockTile auf einen HardBlock gesetzt. Auf diese Weise zeichne ich den Rand
'der Map

If X=3 Or X=5 Or X=7 Or X=9 Or X=11 Or X=13 Then
If Y=3 Or Y=5 Or Y=7 Or Y=9 Or Y=11 Or Y=13 Then
NeueMap.Feld[X,Y].BlockTile =HardBl
NeueMap.Feld[X,Y].Inhalt =5
End If
End If
'haben der X und der Y Wert eine Position erreicht, die wichtig für das
'Schachbrettähnliche Muster sind, so wird ebenfalls ein HardBlock an die
'Position gesetzt
Next
Next
'#############################################
'# MAP MIT 100 SOFTBLÖCKEN FÜLLEN #
'# DABEI SPIELER-STARTECKEN FREI LASSEN #
'#############################################
Local BlockZahl:Int = 100 '100 Softblöcke sollen gesetzt werden
Repeat 'eine Schleife, die solange läuft, bis 100 SoftBlöcke gesetzt worden sind
For Local Y:Int=1 To MY 'ich gehe wieder die ganze Map durch
For Local X:Int=1 To MX
Local Check:Int=0 'setze Chech auf 0
If Y=2 Or Y=3 Or Y=MY-2 Or Y=MY-1 Then Check:+1 'für die StartEcken
If X=2 Or X=3 Or X=MX-2 Or X=MX-1 Then Check:+1 'wie zuvor beschrieben
If BlockZahl=0 Or (Y=8 And X=8) Then Check=2
'habe ich schon 100 Blöcke gesetzt ODER ist das aktuelle Feld grade die Mitte
'Dann Check auf 2 setzen, damit kein Block gesetzt wird.
If Check<2 Then
If NeueMap.Feld[X,Y].BlockTile=0 And Rand(0,2)=1 Then
'wenn auf aktuellem Feld noch kein Block ist und Rand(0,2)=1 ist dann neuen Block setzen
NeueMap.Feld[X,Y].BlockTile=SoftBl
BlockZahl:-1 'gesetzen Block abziehen (denn ich will ja nur 100 haben)
End If
End If
Next
Next
Until (BlockZahl=0) 'wenn 100 Softblöcke gesetzt wurden Schleife verlassen und Map zurück geben.
Return NeueMap 'hiermit gebe ich die temporär erstellte Map zurück
End Function



und hier der wichtige Teil:
BlitzMax: [AUSKLAPPEN]
		'#############################################
'# MAP MIT 100 SOFTBLÖCKEN FÜLLEN #
'# DABEI SPIELER-STARTECKEN FREI LASSEN #
'#############################################
Local BlockZahl:Int = 100 '100 Softblöcke sollen gesetzt werden
Repeat 'eine Schleife, die solange läuft, bis 100 SoftBlöcke gesetzt worden sind
For Local Y:Int=1 To MY 'ich gehe wieder die ganze Map durch
For Local X:Int=1 To MX
Local Check:Int=0 'setze Chech auf 0
If Y=2 Or Y=3 Or Y=MY-2 Or Y=MY-1 Then Check:+1 'für die StartEcken
If X=2 Or X=3 Or X=MX-2 Or X=MX-1 Then Check:+1 'wie zuvor beschrieben
If BlockZahl=0 Or (Y=8 And X=8) Then Check=2
'habe ich schon 100 Blöcke gesetzt ODER ist das aktuelle Feld grade die Mitte
'Dann Check auf 2 setzen, damit kein Block gesetzt wird.
If Check<2 Then
If NeueMap.Feld[X,Y].BlockTile=0 And Rand(0,2)=1 Then
'wenn auf aktuellem Feld noch kein Block ist und Rand(0,2)=1 ist dann neuen Block setzen
NeueMap.Feld[X,Y].BlockTile=SoftBl
BlockZahl:-1 'gesetzen Block abziehen (denn ich will ja nur 100 haben)
End If
End If
Next
Next
Until (BlockZahl=0) 'wenn 100 Softblöcke gesetzt wurden Schleife verlassen und Map zurück geben.
Return NeueMap 'hiermit gebe ich die temporär erstellte Map zurück


Ich ich erstelle eine Variable namens BlockZahl, setze diese auf 100 (will ja 100 Blöcke haben) und erstelle eine Repeat Until Schleife, welche erst verlassen wird, sobald Blockzahl = 0 ist

Sobald ein Block gesetzt werden kann (siehe Codedokumentation für die Bedingungen) wird BlockZahl um eins veringert.

noch eine kurze Erklärung dazu:
BlitzMax: [AUSKLAPPEN]
If NeueMap.Feld[X,Y].BlockTile=0 And Rand(0,2)=1 Then

ich benutze bei Rand statt nur den bereich 0-1 mit Absicht 0-2 und zeichne nur bei 1 einen Block.
Als ich es auf Rand(0,1) stehen hatte, sahen die Maps nicht wirklich so gut aus. Kann auch Einbildung sein, aber mit dem Bereich von 0-2 hatte ich das Gefühl, bessere Maps zu bekommen.

So, was bleibt mir noch zu tun? achja... natürlich das Projekt, bis zum jetzigem Stande zum Download freigeben Wink

Das gesammte Projekt bis zu diesem Punkt (inklusive .exe):

https://www.blitzforum.de/upload/file.php?id=9338

HUIIIII....
jetzt hab fast 4 Stunden damit verbracht... das alles hier nieder zu schreiben und oftmals denke ich, ich konnte etwas nicht verständlich genug erklären. Hoffe, das täuscht mich nur und jeder kann damit etwas anfangen. Zumindest habe ich den Code gestern schneller geschrieben, als ich heute hier gebraucht habe, das alles zu rechtfertigen Wink

Im nächsten Worklog widme ich mich dann dem TSpieler...
da wollen wir dann mal jemanden über die tolle Map laufen lassen....

Puhhh... jetzt erstmal nen kaltes Bier!!!! *freu*
man gut, das ich morgen (heute Wink ) frei habe *nochmal freu*

und bitte nicht vergessen:

Fragen und Kritik sind herzlichst wilkommen!!!

Ein paar Gedanken

Donnerstag, 19. August 2010 von KirkZero
Nun geht es also los...

Zunächst habe ich mir Heute aus all den Ideen, die mir seit 2 Wochen durch den Kopf schwirren, ein grobes Konzept zurechtgelegt, welches für das Gerüst dient. Ausserdem habe ich mir jetzt schonmal überlegt, welche meiner Ideen für mich umsetzbar, und welche noch eher Zukunftsmusik sind.
Da ich aber ungern Abstriche machen will, möchte ich versuchen, den Code so übersichtlich wie möglich zu gestalten, damit man das Grundgerüst später (soweit möglich) nach belieben ausbauen kann.

Das Grundgerüst:
Folgendes soll im Grundgerüst enthalten sein

- ein simples Menü (wird erst eingefügt, wenn der Rest steht... also ganz zum Schluss, möchte halt, wenn ich nen Testlauf starte, nicht immer erst im Menü Landen Wink )

- eine (zufällig erstellte) Map (wie man es vom Original kennt... die nicht sprengbaren Blöcke haben immer die gleiche Position, während die sprengbaren Blöcke halbwegs zufällig platziert werden... aber dazu später mehr)

- der Spieler, mit den Möglichkeiten sich zu bewegen und Bomben zu legen (wahrscheinlich auch schon ein zweiter Spieler... wäre ja sonst langweilig Wink )

- natürlich die Bomben + Explosionen

- PowerUps (zunächst erstmal nur 2 : Feuerkraft für Bomben erhöhen und Anzahl der Bomben, die man legen kann, erhöhen)

- Vielleicht schonmal einen simplen KI Gegner


Wenn das Grundgerüst soweit steht, möchte ich es dann noch ein wenig erweitern, ich denke mal an Ideen wird es bestimmt nicht mangeln Wink
Was auf jedenfall rein soll:

- einen Storymodus der alleine oder auch zu zweit gespielt werden kann (natürlich dann auf selbsterstellten Karten... also muss auch ein MapEditor her)
- verschieden Gegnertypen mit unterschiedlichen Verhaltensmustern
- natürlich der Battlemodus (Deathmatch und evtl Teamspiel)
- BodenTiles mit besonderen Funtionen (z.B. Fließband, Teleporter, ...)
- neue PowerUps (mal sehen, was sich da alles realisieren lässt)
- die Möglichkeit auch Online zu spielen (das werd ich bestimmt nicht schaffen... aber mal sehen. Wäre jedenfalls super, wenn man das auch hinbekommt)


Zurück zum Grundgerüst:
Ich habe mir mal Gedanken gemacht, welche Objekte bzw. Types ich sinnvollerweise erstellen sollte. Ich habe mir das nun so gedacht:
Natürlich bekommt die Map ihr eigenes Type und da jedes Feld in der Map ebenfalls gewisse Informationen von mir bekommt, werden auch die einzelnen Felder aus Types bestehen
Das wären dann:
TMap und TFeld
der Spieler:
TSpieler
Die Bomben und deren Explosionen:
TBombe und TExplosion
die PowerUps:
TItem
Gegner:
TMonster
und ganz zum Schluss das Menü:
TMenue

Jetzt die große Frage, die ich mir immer stelle, wenn ich ein Projekt beginne: sollte ich noch mehr Types einführen? also das ganze noch unterteilen? oder sind das schon zu viele? Es gäbe z.B. viele Dinge, die ich alleine über die Map regeln könnte (z.B. die Items, die Bomben, die Explosion) aber habe mir gedacht, mehr unterteilen, gibt mehr Übersicht.....

Nun gehts endlich los
Ich habe mir einen Ordner "Bomberman" für das Projekt angelegt (Hauptordner). In diesem habe ich 2 Unterordner erstellt: GFX (für die Grafiken) und SFX (für die Sounds)

Ich werde jeden Type in einer seperaten Datei im Hauptordner speichern und dann per INCLUDE in die Hauptdatei einbinden. Die Dateien tragen den gleiche Name des jeweiligen Types.
Die Hauptdatei nenne ich MainGame.bmx in ihr werden alle Codes zusammengeführt, Grundlegende dinge (wie Bildschirmmodus usw) geregelt und ausserdem befindet sich dort auch die Hauptschleife.

Hier ist meine MainGame.bmx mit den grundlegenden Dingen:
BlitzMax: [AUSKLAPPEN]

SuperStrict 'zwingt mich, sauber zu programmieren Wink

'------------------------------ includes ----------


'------------------------------ Grafikmodus ----------
Const BREITE:Short = 800 , HOEHE:Short = 600 'Ich setze die Bildschirmbreite und Höhe als Konstante
Global Vollbild:Int=False 'Ob Vollbild oder nicht, soll später der User entscheiden, darum keine Konstante
Graphics BREITE , HOEHE , Vollbild 'Bildschirmmodus wird gesetzt
'------------------------------ Vorbereitungen ----------
SeedRnd (MilliSecs()) 'Da ich den "Zufall" im Spiel benötige,füttere ich ihn schonmal mit der Zeit seit dem Systemstart
Global Frames:TTimer = CreateTimer (60) 'damit das Spiel auf jedem Rechner gleichschnell läuft setze ich einen Timer

'------------------------------ Grafiken laden ----------



'------------------------------ Sounds laden ----------



'------------------------------ Type-Erstellungen ----------



'------------------------------ Hauptschleife ----------
Repeat
Cls 'Backbuffer löschen


WaitTimer (Frames) 'da Frames=60 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync

Until KeyHit(KEY_ESCAPE) 'Programm wird beendet, sobald Escape gedrückt wird
End

Bitte gleich zu Beginn immer wieder Hinweise geben, wie man den Code besser lesbar und strukturierter machen kann. Danke!

Das wars dann erstmal. Mein nächster Schritt besteht darin, mich um die Map zu kümmern. (Ich weiss auch nicht warum, aber bei allen Projekten, beginne ich immer erst mit dem Bildschirmaufbau (also in diesem Fall mit der Map) großer Fehler oder eigentlich egal???

Dann bis zum nächsten Eintrag, bei dem es dann mit der Map weitergeht.

Was soll das Ganze hier?

Mittwoch, 18. August 2010 von KirkZero
Ich habe mir in den letzten Monaten eine Menge BMax Wissen angeeignet, viele kleine Testprogramme geschrieben und meinen bisherigen Höhepunkt gefeiert, indem ich beim BCC 40 (Beitrag: PuzzleGotchi) teilgenommen habe. Soweit, so gut...

Ich habe dabei natürlich auch gemerkt, das ich bei weitem noch sehr viel lernen muss und ich auch noch vieles viel komplizierter in Code fasse, als es eigentlich nötig ist (Es gab oft genug viel einfachere Lösungen, auf die ich aber anfangs nicht gekommen bin).
Nun dachte ich mir erneut, learning by doing... und das werde ich nun auch tun, ABER ich hoffe dabei auf die Unterstützung dieser STARKEN Community...

Was heisst das nun genau???

Ich werde hier jeden Schritt, den ich bei diesem Projekt gehe, so gut es geht dokumentieren, jedes stück Code werde ich hier posten und natürlich auch den Gedanken dahinter... also warum ich irgendetwas genau so mache, wie ich es gemacht habe.

... und genau da kommt ihr ins Spiel Wink

Nach jedem Schritt, den ich mache und hier poste, würde ich mich freuen, wenn IHR euch das anschaut, verinnerlicht und mir dann Feedback dazu gebt und meinen "Bullshit" evtl verbessert, mir Logik- oder Denkfehler aufzeigt, bessere Lösungsansätze gebt oder allgemeine Verbesserungen an der Umsetzung aufzeigt.

Nicht falsch verstehen: Ich möchte mir hier keinen fertigen Code erbetteln, ich werde versuchen, mir ersteinmal jeden Schritt selbst zu erarbeiten, ihn dann hier zeigen und nach jedem Schritt auf eure Kritik hoffen.

Was ich mir davon erhoffe?
Das ich besser in die Materie reinfinde, meine bisherigen Programmierfehler beseitige, meinen Codestil verbessere, besseres OOP betreibe.... und, und, und...

Warum solltet ihr mir helfen?
Sollt ihr nicht, ich kann ja niemanden zwingen, würde mich aber übelst freuen, wenn ihr es tut... ist alles freiwillig Wink

Damit auch Alle etwas davon haben:
Nach Abschluss dieses Projektes, würde ich dann das alles hier gerne zusammenfassen und als Community Tutorial in die Sektion BMAX: FAQs und Tutorials eintragen. Damit auch alle Anderen davon profitieren.

Nun aber zum eigentlichen Projekt...

Es wird ein Bomberman Klon... Warum?
Ich denke, in so einem Spiel kommt vieles zusammen, was man auch woanders gebrauchen kann...
- Zeitgesteuerte Ereignisse
- eine Tilemap
- Gegner
- eine einfache KI
- PowerUps
- Zufällig generierte Maps
- Konfigurierbare Tastatureingabe
- verschiedene Spielmodi (Teamspiel, Deathmatch, Coop...)
- Online Spielen (steht ganz weit hinten, aber hoffe, das ich nebenbei mir da noch ein wenig was aneignen kann, weil wäre absolutes Neuland für mich)
- ausserdem soll das ganze ausbaufähig gestaltet werden... also man soll es einfach erweitern können (neue PowerUps usw...)


Gleich vorweg... ich habe mir in den letzten 2 Wochen natürlich schon meine Gedanken gemacht und fange hier nun nicht einfach so an zu programmieren. Habe hier schon ein paar Seiten Papier mit Brainstorming und einige kleine Konzeptzeichnungen Wink

Doch, bevor ich das nun wirklich so starte, wie ich es vor habe, wüsste ich nun gerne ersteinmal...

Sinn oder Unsinn???

Ich würde mich sehr über diese Herrausforderung freuen, also... :
Was haltet ihr davon? Würde überhaupt jemand das ganze verfolgen... noch besser, würde überhaupt jemand Hilfestellung geben, wie oben beschrieben?

Sollte dies nämlich nicht der Fall sein, so hätte das ganze nämlich keinen Sinn Wink

Würde mich sehr über Feedback freuen!!!

MfG

Kirk

Gehe zu Seite Zurück  1, 2