Bomberman Klon (Community Tutorial) BMAX
Back to the... oh man...
Mittwoch, 27. Oktober 2010 von KirkZero
sooo...
Hab mich nun dran versucht mich wieder in meinen Code einzulesen...
Ist garnicht so einfach... will aber das Projekt nicht aufgeben.
(auch wenn es nur ein kleines Licht ist unter den ganzen großen Sachen hier)
Denke, ich brauch da noch ein wenig Zeit...
werde mein eigenes Worklog mal von unten bis oben durchgehen, denke, wenn ich dann wieder klar komme... dann hab ich mein ziel erreicht... ein kleines Tutorial *freu*
ToDo:
- Das Menü
- Multiplayer an einem Rechner
- Singleplayer
Das Menü wird einfach ausfallen...
- primitives Sound an/aus
- Vollbild an/aus
- singleplayer
- multiplayer
der multiplayer Part wird ein einfaches Deathmatch werden...
der Singleplayer eine Art "verteidige den Hügel" oder so... (was man dann auch zu zweit im coop spielen kann)
Das erstmal soweit von mir...
Gehe dann mal wieder "Code Lesen"
Hab mich nun dran versucht mich wieder in meinen Code einzulesen...
Ist garnicht so einfach... will aber das Projekt nicht aufgeben.
(auch wenn es nur ein kleines Licht ist unter den ganzen großen Sachen hier)
Denke, ich brauch da noch ein wenig Zeit...
werde mein eigenes Worklog mal von unten bis oben durchgehen, denke, wenn ich dann wieder klar komme... dann hab ich mein ziel erreicht... ein kleines Tutorial *freu*
ToDo:
- Das Menü
- Multiplayer an einem Rechner
- Singleplayer
Das Menü wird einfach ausfallen...
- primitives Sound an/aus
- Vollbild an/aus
- singleplayer
- multiplayer
der multiplayer Part wird ein einfaches Deathmatch werden...
der Singleplayer eine Art "verteidige den Hügel" oder so... (was man dann auch zu zweit im coop spielen kann)
Das erstmal soweit von mir...
Gehe dann mal wieder "Code Lesen"
Animation des Spielers
Mittwoch, 8. September 2010 von KirkZeroDas ist die SpielerGrafik, sie besteht aus 20 einzelbildern zu je 32x32 Pixeln. Das allererste Bild (oben links) ist Frame 0 und das letzte (unten rechts) ist Frame 19. Daraus folgt:
das 1. Bild für Bewegung nach oben ist Frame 0 (linkes Bild 1. Reihe)
das 1. Bild für Bewegung nach rechts ist Frame 5 (linkes Bild 2. Reihe)
das 1. Bild für Bewegung nach unten ist Frame 10 (linkes Bild 3. Reihe)
das 1. Bild für Bewegung nach links ist Frame 15 (linkes Bild 4. Reihe)
Dafür nehm ich wieder einmal ein paar Konstante:
BlitzMax: [AUSKLAPPEN]
Const ANIOBEN :Int = 0 'StartFrame für Bewegung nach oben
Const ANIUNTEN :Int = 10 'StartFrame für Bewegung nach unten
Const ANILINKS :Int = 15 'StartFrame für Bewegung nach links
Const ANIRECHTS :Int = 5 'StartFrame für Bewegung nach rechts
Die linken 3 Bilder jeder Reihe sind für die Bewegungsanimation zuständig, die rechten 2 Bilder werden erstmal nicht gebraucht, die kommen vielleicht noch später und wären dann für einen "Special Move"
Somit müsste man also immer, wenn der Robo nach oben fährt, nacheinander frame 0, dann frame 1, und zum schluss Frame 2 anzeigen lassen.
BlitzMax: [AUSKLAPPEN]
Const BEWEGUNGSFRAMES :Int = 2 'Bewegung besteht aus 3 Frames (0, 1 und 2)
Field SpielerFrame :Int = 0 'Aktuelles Frame des Spielers
Field BewegungsFrame :Int = 0 'Aktuelles Frame der Bewegung
Die Konstante BEWEGUNGSFRAMES gibt an, wieviele Frames jede Richtung hat. Auch wenn dort die Zahl 2 steht, hat sie dennoch 3, da ja bei 0 angefangen wird zu zählen.
SpielerFrame ist das aktuelle Frame, welches dann auch gezeichnet wird. Es setzt sich aus einer der 4 Konstanten (ANIOBEN, ANIUNTEN,ANILINKS und ANIRECHTS) + dem BewegungsFrame zusammen.
(BewegungsFrame speichert dabei nur den aktuellen Frame der Bewegung, welcher entweder 0,1 oder 2 ist. Ist er > 2 (also > BEWEGUNGSFRAMES) dann wird er wieder auf 0 gesetzt)
BlitzMax: [AUSKLAPPEN]
BewegungsFrame:+1
If BewegungsFrame > BEWEGUNGSFRAMES Then BewegungsFrame=0
Das ganze packe ich nun in die Methode Bewegung() von TSpieler.bmx:
BlitzMax: [AUSKLAPPEN]
Method Bewegung(Richtung:Int)
Local x :Int 'Temporäre Speicher
Local y :Int
Local fx :Int 'Temporäre Speicher für zu prüfende Felder
Local fy :Int 'ist fy=-1 wird oberes vom aktuellen Feld geprüft
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
BewegungsFrame:+1
If BewegungsFrame > BEWEGUNGSFRAMES Then BewegungsFrame=0
Select Richtung
Case OBEN
fy=-1 'oberes Feld prüfen
SpielerFrame=ANIOBEN+BewegungsFrame
Case UNTEN
fy=+1 'unteres Feld prüfen
SpielerFrame=ANIUNTEN+BewegungsFrame
Case LINKS
fx=-1 'linkes Feld prüfen
SpielerFrame=ANILINKS+BewegungsFrame
Case RECHTS
fx=+1 'rechtes Feld prüfen
SpielerFrame=ANIRECHTS+BewegungsFrame
End Select
und jetzt muss ich SpielerFrame noch in der Zeichnen() Methode unterbringen:
BlitzMax: [AUSKLAPPEN]
Method Zeichnen()
'DrawRect (xFeld*TS,yFeld*TS,TS,TS) 'Erstmal auskommentiert... vorerst klappt ja alles
DrawImage (SpielerIMG,xPos,yPos,SpielerFrame)
End Method
hund hier die Komplette TSpieler.bmx:
BlitzMax: [AUSKLAPPEN]
Type TSpieler
Field SpielerNr :Int 'Welcher Spieler bin ich? 1,2,3 oder 4
Field xFeld :Int 'x und y Koordinaten für das entsprechende FELD
Field yFeld :Int 'auf dem sich der Spieler befindet
Field xPos :Int 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Int
Field Speed :Int = 2 'man bewegt sich immer um 2 Pixel pro Bewegung
Field FeuerKraft :Int = 2 'Reichweite der Explosionen einer Bombe (2 Felder in alle Richtungen)
Field BombenMenge :Int = 1 'Anzahl an Bomben, die der Spieler gleichzeitig legen kann
Field MaxBombenMenge :Int = 5 'egal wieviele Items man sammelt, man kann nie mehr legen, als hier verzeichnet
Field GelegteBomben :Int 'Wieviel hat der Spieler bereits gelegt und sind noch nicht explodiert?
Const OBEN :Int = 0
Const UNTEN :Int = 1
Const LINKS :Int = 2
Const RECHTS :Int = 3
Const ANIOBEN :Int = 0 'StartFrame für Bewegung nach oben
Const ANIUNTEN :Int = 10 'StartFrame für Bewegung nach unten
Const ANILINKS :Int = 15 'StartFrame für Bewegung nach links
Const ANIRECHTS :Int = 5 'StartFrame für Bewegung nach rechts
Const BEWEGUNGSFRAMES :Int = 2 'Bewegung besteht aus 3 Frames (0, 1 und 2)
Field SpielerFrame :Int = 0 'Aktuelles Frame des Spielers
Field BewegungsFrame :Int = 0 'Aktuelles Frame der Bewegung
Field SpielerIMG :TImage 'speichert die Grafik des Spielers
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 20
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Bewegung wieder erlaubt (Zeit)
If KeyDown(Taste_Hoch[SpielerNr]) 'wenn Taste für OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(Taste_Runter[SpielerNr]) 'wenn Taste für UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(Taste_Links[SpielerNr]) 'wenn Taste für LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(Taste_Rechts[SpielerNr]) 'wenn Taste für RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End If
If KeyHit(Taste_Aktion[SpielerNr]) 'wenn Taste für Aktion gedrückt wird
BombeLegen() 'dann Methode zum Bombenlegen aufrufen
End If
End Method
Method BombeLegen()
If Map.Feld[xFeld,yFeld].Inhalt = NIX 'wenn aktuelles Feld leer ist
If GelegteBomben < BombenMenge And GelegteBomben < MaxBombenMenge
'wenn bisher weniger Bomben gelegt als man kann UND als man darf
TBombe.Erstellen(SpielerNr,xFeld,yFeld,FeuerKraft) 'Bombe erstellen
GelegteBomben:+1 'um 1 erhöhen, da ja nun eine bombe gelegt wurde
End If
End If
End Method
Method Bewegung(Richtung:Int)
Local x :Int 'Temporäre Speicher
Local y :Int
Local fx :Int 'Temporäre Speicher für zu prüfende Felder
Local fy :Int 'ist fy=-1 wird oberes vom aktuellen Feld geprüft
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
BewegungsFrame:+1
If BewegungsFrame > BEWEGUNGSFRAMES Then BewegungsFrame=0
Select Richtung
Case OBEN
fy=-1 'oberes Feld prüfen
SpielerFrame=ANIOBEN+BewegungsFrame
Case UNTEN
fy=+1 'unteres Feld prüfen
SpielerFrame=ANIUNTEN+BewegungsFrame
Case LINKS
fx=-1 'linkes Feld prüfen
SpielerFrame=ANILINKS+BewegungsFrame
Case RECHTS
fx=+1 'rechtes Feld prüfen
SpielerFrame=ANIRECHTS+BewegungsFrame
End Select
If Map.Feld[xFeld+fx,yFeld+fy].Inhalt = NIX 'wenn auf dem zu prüfenden Feld NIX ist
If fy <> 0 'ist das zu prüfende Feld oben oder unten, dann auf Autobewegung checken
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else
y=fy*Speed 'passt es genau, dann um Speed Pixel nach fy bewegen
End If
End If
If fx <> 0 'ist das zu prüfende Feld links oder rechts, dann auf Autobewegung checken
If yFeld*TS < yPos 'ist (Y Feldkoordinate*TS) kleiner als Pixelkoordinate
y=-Speed 'dann um Speed Pixel nach oben bewegen
Else If yFeld*TS > yPos 'ist (Y Feldkoordinate*TS) größer als Pixelkoordinate
y=+Speed 'dann um Speed Pixel nach unten bewegen
Else
x=fx*Speed 'passt es genau, dann um Speed Pixel nach fx bewegen
End If
End If
Else If fy <> 0 And yMod <> 0 'wenn nicht begehbar aber noch nicht ganz auf dem Feld, dann trotzdem bewegen
y=fy*Speed
Else If fx <> 0 And xMod <> 0 'wenn nicht begehbar aber noch nicht ganz auf dem Feld, dann trotzdem bewegen
x=fx*Speed
End If
yPos:+y 'Spieler Koordinaten aktualisieren
xPos:+x
MapFeld() 'Aktuelles Map.Feld[,] wird berechnet
BewegungsTimer = MilliSecs()
End Method
Method MapFeld() 'berechnet aktuelles Map.Feld[,]
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
If yMod < (TS/2) Then yFeld=(yPos/TS) 'wenn modulus < als 16
If yMod > (TS/2) Then yFeld=(yPos/TS)+1 'wenn modulus > als 16
If xMod < (TS/2) Then xFeld=(xPos/TS) 'wenn modulus < als 16
If xMod > (TS/2) Then xFeld=(xPos/TS)+1 'wenn modulus > als 16
End Method
Method Update()
If Map.Feld[xFeld,yFeld].Item = ITEM_AUFGEDECKT 'wenn aufgedecktes Item auf SpielerFeld
For Local Item:TItem = EachIn TItem.ItemListe 'jedes erstellte Item durchgehen
If xFeld=Item.xFeld And yFeld=Item.yFeld 'wenn richtiges Item gefunden
Map.Feld[xFeld,yFeld].Item = 0 'ItemFlag auf 0
Item.Sammler = SpielerNr 'Spieler der es gesammelt hat festlegen
End If
Next
End If
End Method
Method Zeichnen()
'DrawRect (xFeld*TS,yFeld*TS,TS,TS) 'Erstmal auskommentiert... vorerst klappt ja alles
DrawImage (SpielerIMG,xPos,yPos,SpielerFrame)
End Method
Function Erstellen:TSpieler (SpielerNr:Int,xFeld:Int,yFeld:Int,ImgPfadName:String,ImgFrames:Int)
Local NeuerSpieler :TSpieler = New TSpieler 'Temporären Spieler erstellen
NeuerSpieler.SpielerNr = SpielerNr 'welcher Spieler bin ich?
NeuerSpieler.xFeld = xFeld 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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
und schon bewegen sich die Ketten des Robos und er schaut immer in die richtige Richtung
Hier nochmal ein Zitat von Xeres:
Zitat:
Was mir aufgefallen ist: Dein Spieler Bild hat 4x die Frames die es bräuchte; Für die Top-down Ansicht würde ein Frame-Strip reichen und der Rest ließe sich durch SetRotation erreichen. Um die, sagen wir "Rotationseffekte" (Drehung um die obere, linke Ecke), zu vermeiden, verwende ich eigentlich immer AutoMidHandle - also gebe immer die Mitte der zu zeichnenden Objekte an, um die auch die Drehung stattfindet. Das ist vermutlich reine Gewöhnungssache, hat aber seine Vorteile.
Ich habe das jetzt zwar anders gemacht, aber in meinen zukünftigen Projekten werde ich es mal auf die Art (SetRotation) versuchen.
Vielen Dank fürs Lesen!
Tastenbelegung und Spieler 2
Mittwoch, 8. September 2010 von KirkZero
Erstmal liegt wieder eine Fehlerkorrektur an. Danke an Hummelpups!!!
Ich habe mit der Art und Weise, mit der ich im letzten Eintrag die Items auf der Map versteckt habe, ziemlichen Mist gebaut.
Sie werden nicht wirklich schön gleichmässig verteilt.
Zitat von Hummelpups:
Zitat:
Nun hab ich mir Hummelpups Art mal angeschaut. Die Wahrscheinlichkeit ist nicht nur schön gleichmässig, sondern die Lösung ist auch um einiges eleganter.
Somit entsteht eine Neue Methode in TKarte.bmx:
BlitzMax: [AUSKLAPPEN]
An die Methode werden (von links nach rechts) übergeben:
- das Item, welches versteckt werden soll
- die Menge, also wie viele sollen von der Sorte versteckt werden
- die Map, auf der die Items versteckt werden sollen
und zurück gibt sie die mit Items gefüllte Map
ich rufe sie in der Erstellen() Funktion dann so auf:
BlitzMax: [AUSKLAPPEN]
und hier die komplette TKarte.bmx:
BlitzMax: [AUSKLAPPEN]
Nochmals danke an Hummelpups!!!
Bevor ich nun allerdings einen 2. Spieler erstelle... erstmal eine neue Datei für die Variablen, welche die Tastenbelegung der einzelnen Spieler speichern sollen:
BlitzMax: [AUSKLAPPEN]
Speichern im Ordner Includes unter dem Namen TastaturBelegung.bmx und in der MainGame.bmx includieren:
BlitzMax: [AUSKLAPPEN]
Ich werde das mit den Tasten später noch versuchen anders zu regeln, vieleicht über eine ini datei oder übers Menü. Aber erstmal mach ich es so.
Nun muss ich noch die Steuerung() Methode von TSpieler anpassen:
BlitzMax: [AUSKLAPPEN]
BlitzMax: [AUSKLAPPEN]
und schon läuft Spieler 1 mit den Tasten W A S D und Leertaste zum Bomben legen
Jetzt kann ich Spieler 2 erstellen.
MainGame.bmx:
BlitzMax: [AUSKLAPPEN]
Spieler 2 erhält erstmal die gleiche Grafik wie Spieler 1.
SpielerNr ist 2 und er startet unten rechts (x=14 und y=14)
Da Spieler 2 allerdings noch nicht in der Hauptschleife integriert ist, passiert auch nix weiter. Also ab in die Hauptschleife mit ihm:
BlitzMax: [AUSKLAPPEN]
und hier die ganze MainGame.bmx:
BlitzMax: [AUSKLAPPEN]
Sauber... ab jetzt ist man zu zweit unterwegs
Glaub, jetzt komm ich beim nächsten mal nicht drum rum, die Spieler endlich mal zu animieren...
Vielen dank fürs Lesen!!! *winke*
Ich habe mit der Art und Weise, mit der ich im letzten Eintrag die Items auf der Map versteckt habe, ziemlichen Mist gebaut.
Sie werden nicht wirklich schön gleichmässig verteilt.
Zitat von Hummelpups:
Zitat:
KirkZero, bei deinem "Item setz algo" hast du es dir unnötig schwer
und auch noch falsch gemacht. Deine Items laut wahrscheinlichkeitsrechnung
so gesetzt:
links dein Algo, rechts meiner
und auch noch falsch gemacht. Deine Items laut wahrscheinlichkeitsrechnung
so gesetzt:
links dein Algo, rechts meiner
Nun hab ich mir Hummelpups Art mal angeschaut. Die Wahrscheinlichkeit ist nicht nur schön gleichmässig, sondern die Lösung ist auch um einiges eleganter.
Somit entsteht eine Neue Methode in TKarte.bmx:
BlitzMax: [AUSKLAPPEN]
Method ItemsVerteilen:TKarte (Item:Int,Menge:Int,Map:TKarte)
For Local Nr:Int = 1 To Menge
Local x:Int
Local y:Int
Repeat
x=Rand (1,MX)
y=Rand (1,MY)
If Map.Feld[x,y].Inhalt = SBLOCK And Map.Feld[x,y].Item = 0
'wenn auf aktuellem Feld ein Softblock ist, UND noch KEIN Item
Map.Feld[x,y].Item = Item 'Item verstecken
Exit 'Repeat... Forever... Schleife verlassen
End If
Forever
Next
Return Map
End Method
An die Methode werden (von links nach rechts) übergeben:
- das Item, welches versteckt werden soll
- die Menge, also wie viele sollen von der Sorte versteckt werden
- die Map, auf der die Items versteckt werden sollen
und zurück gibt sie die mit Items gefüllte Map
ich rufe sie in der Erstellen() Funktion dann so auf:
BlitzMax: [AUSKLAPPEN]
NeueMap.ItemsVerteilen (ITEM_BOMBE,AnzahlBomben,NeueMap)
NeueMap.ItemsVerteilen (ITEM_FEUER,AnzahlFeuer,NeueMap)
und hier die komplette TKarte.bmx:
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
Type TKarte
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].Update(X,Y) 'Aktuelles Feld auf Richtigkeit prüfen
Feld[X,Y].Zeichnen(X,Y) 'Übergibt X und Y Werte an Feld.Zeichnen
Next
Next
End Method
Function Erstellen:TKarte(MX:Int,MY:Int,Boden:Int,HardBl:Int,SoftBl:Int)
Local NeueMap:TKarte = New TKarte '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 =HBLOCK
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 =HBLOCK
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 Check 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 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
Next
Next
Until (BlockZahl=0) 'wenn 100 Softblöcke gesetzt wurden Schleife verlassen und Map zurück geben.
'#############################################
'# MAP MIT ITEMS FÜLLEN #
'# ITEMS DÜRFEN NUR AUF FELDER MIT SOFTBLOCK #
'#############################################
Local AnzahlBomben :Int = 10 'wieviel von welchem Item sollen vorkommen?
Local AnzahlFeuer :Int = 10
NeueMap.ItemsVerteilen (ITEM_BOMBE,AnzahlBomben,NeueMap)
NeueMap.ItemsVerteilen (ITEM_FEUER,AnzahlFeuer,NeueMap)
Return NeueMap 'hiermit gebe ich die temporär erstellte Map zurück
End Function
Method ItemsVerteilen:TKarte (Item:Int,Menge:Int,Map:TKarte)
For Local Nr:Int = 1 To Menge
Local x:Int
Local y:Int
Repeat
x=Rand (1,MX)
y=Rand (1,MY)
If Map.Feld[x,y].Inhalt = SBLOCK And Map.Feld[x,y].Item = 0
'wenn auf aktuellem Feld ein Softblock ist, UND noch KEIN Item
Map.Feld[x,y].Item = Item 'Item verstecken
Exit
End If
Forever
Next
Return Map
End Method
End Type
Nochmals danke an Hummelpups!!!
Bevor ich nun allerdings einen 2. Spieler erstelle... erstmal eine neue Datei für die Variablen, welche die Tastenbelegung der einzelnen Spieler speichern sollen:
BlitzMax: [AUSKLAPPEN]
'Tastaturbelegung
Global Taste_Hoch :Int[5]
Global Taste_Runter :Int[5]
Global Taste_Links :Int[5]
Global Taste_Rechts :Int[5]
Global Taste_Aktion :Int[5]
'Tasten Spieler 1 (Spieler[1])
Taste_Hoch [1] = KEY_W
Taste_Runter [1] = KEY_S
Taste_Links [1] = KEY_A
Taste_Rechts [1] = KEY_D
Taste_Aktion [1] = KEY_SPACE
'Tasten Spieler 2 (Spieler[2])
Taste_Hoch [2] = KEY_UP
Taste_Runter [2] = KEY_DOWN
Taste_Links [2] = KEY_LEFT
Taste_Rechts [2] = KEY_RIGHT
Taste_Aktion [2] = KEY_RCONTROL
Speichern im Ordner Includes unter dem Namen TastaturBelegung.bmx und in der MainGame.bmx includieren:
BlitzMax: [AUSKLAPPEN]
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
Include "INCLUDES/TBombe.bmx"
Include "INCLUDES/TExplosion.bmx"
Include "INCLUDES/TItem.bmx"
Include "INCLUDES/TastaturBelegung.bmx"
Ich werde das mit den Tasten später noch versuchen anders zu regeln, vieleicht über eine ini datei oder übers Menü. Aber erstmal mach ich es so.
Nun muss ich noch die Steuerung() Methode von TSpieler anpassen:
BlitzMax: [AUSKLAPPEN]
'Statt so:
If KeyDown(KEY_UP) 'wenn Taste für OBEN gedrückt
'heisst es nun so:
If KeyDown(Taste_Hoch[SpielerNr]) 'wenn Taste für OBEN gedrückt
BlitzMax: [AUSKLAPPEN]
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Bewegung wieder erlaubt (Zeit)
If KeyDown(Taste_Hoch[SpielerNr]) 'wenn Taste für OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(Taste_Runter[SpielerNr]) 'wenn Taste für UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(Taste_Links[SpielerNr]) 'wenn Taste für LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(Taste_Rechts[SpielerNr]) 'wenn Taste für RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End If
If KeyHit(Taste_Aktion[SpielerNr]) 'wenn Taste für Aktion gedrückt wird
BombeLegen() 'dann Methode zum Bombenlegen aufrufen
End If
End Method
und schon läuft Spieler 1 mit den Tasten W A S D und Leertaste zum Bomben legen
Jetzt kann ich Spieler 2 erstellen.
MainGame.bmx:
BlitzMax: [AUSKLAPPEN]
Spieler[1] = TSpieler.Erstellen(1,2,2,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
Spieler[2] = TSpieler.Erstellen(2,14,14,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
Spieler 2 erhält erstmal die gleiche Grafik wie Spieler 1.
SpielerNr ist 2 und er startet unten rechts (x=14 und y=14)
Da Spieler 2 allerdings noch nicht in der Hauptschleife integriert ist, passiert auch nix weiter. Also ab in die Hauptschleife mit ihm:
BlitzMax: [AUSKLAPPEN]
For Local I:Int = 1 To 2
Spieler[I].Steuerung()
Spieler[I].Update()
Spieler[I].Zeichnen()
Next
und hier die ganze MainGame.bmx:
BlitzMax: [AUSKLAPPEN]
'MainGame.bmx
SuperStrict 'zwingt mich, sauber zu programmieren
Framework brl.max2d
Import brl.Timer
Import brl.Random
Import brl.D3D9Max2D
Import brl.PNGLoader
AppTitle = "Bomberman Klon (Community Tutorial)"
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
Include "INCLUDES/TBombe.bmx"
Include "INCLUDES/TExplosion.bmx"
Include "INCLUDES/TItem.bmx"
Include "INCLUDES/TastaturBelegung.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
SetGraphicsDriver D3D9Max2DDriver()
Graphics BREITE, HOEHE, Vollbild 'Bildschirmmodus wird gesetzt
'AutoMidHandle(1)
'------------------------------ Vorbereitungen ----------
Const TS :Int = 32 'Tilegröße (32*32)
Global Frames :TTimer = CreateTimer (120) '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:TKarte = TKarte.Erstellen(15,15,0,1,2)
Global Spieler:TSpieler [5] 'es soll maximal 4 Spieler geben, [5] weil es bei 0 anfängt
Spieler[1] = TSpieler.Erstellen(1,2,2,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
Spieler[2] = TSpieler.Erstellen(2,14,14,"GFX/robo1.png",20) 'Spieler 2 wird erstellt
'------------------------------ Hauptschleife ----------
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Update()
Bombe.Zeichnen()
Next
For Local Explosion:TExplosion = EachIn TExplosion.ExplosionsListe 'jede erstellte Explosion durchgehen
Explosion.Update()
Explosion.Zeichnen()
Next
For Local Item:TItem = EachIn TItem.ItemListe 'jedes erstellte Item durchgehen
Item.Update()
Item.Zeichnen()
Next
For Local I:Int = 1 To 2
Spieler[I].Steuerung()
Spieler[I].Update()
Spieler[I].Zeichnen()
Next
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts gedrückt wird
End
Sauber... ab jetzt ist man zu zweit unterwegs
Glaub, jetzt komm ich beim nächsten mal nicht drum rum, die Spieler endlich mal zu animieren...
Vielen dank fürs Lesen!!! *winke*
Items... ich will sie endlich einsammeln
Dienstag, 7. September 2010 von KirkZero
Jetzt soll man auch endlich Items einsammeln können.
Hier schonmal die Grafik der Items (Item.png):
wird im Ordner GFX unter dem Namen Item.png abgespeichert
Ich benutze hier erstmal nur die ersten beiden Items (Bombe und Feuerkraft)
Erstmal eine neue Datei angelegt... TItem.bmx:
BlitzMax: [AUSKLAPPEN]
Denke mal, die Kommentare sagen soweit alles und ansonsten ist das ganze ja fast genauso, wie bei den Bomben. Die Update() Methode ist noch leer, kommt aber noch. Die Konstanten ganz am Anfang erleichtern mir nur wieder den Umgang mit Zahlen und werden ausserhalb des Types angelegt, damit ich sie überall benutzen kann.
diese Datei kommt wieder in den INCLUDES Ordner.
Noch schnell in der MainGame.bmx includieren:
BlitzMax: [AUSKLAPPEN]
Nun muss ich natürlich auch ein paar der Items auf der Map verstecken. Das erledige ich in der Erstellen() Funktion von TKarte.bmx unter der Stelle, an der ich die SoftBlöcke auf der KArte gesetzt habe:
BlitzMax: [AUSKLAPPEN]
Vielleicht fragt sich ja der ein oder andere, warum ich Zufallszahlen von 0 bis 20 nehme und nicht wie bei den Softblöcken 0 bis 2. Ganz einfach, wenn ich einen kleinen Wertebereich habe, kommt meine gewählte Zahl häufiger, als bei einem großem Wertebereich. Die Folge wäre, das so ziemlich alle Items im Oberen linken Teil der Karte versteckt wären und nicht auf der ganzen Map.
hier noch die vollständige Erstellen() Funktion von TKarte.bmx:
BlitzMax: [AUSKLAPPEN]
Jetzt, wo die Items auf der Map verteilt sind, muss ich sie nur noch erstellen, sobald ein Softblock, unter dem sich ein Item befindet, zerstört wird. Das wird in der Update() Methode von TFeld.bmx erledigt:
BlitzMax: [AUSKLAPPEN]
Der Methode müssen nun Parameter übergeben werden, damit das Item auch seine x und y Koordinaten bekommt. Also muss der Aufruf der Update() Methode von TFeld ebenfalls angepasst werden.
Aufgerufen wird sie in TKarte.bmx in der Methode Zeichnen. Also passe ich den Aufruf dort an:
BlitzMax: [AUSKLAPPEN]
Erstellt werden die Items nun... doch ich muss sie auch in der Hauptschleife von MainGame Zeichnen lassen:
BlitzMax: [AUSKLAPPEN]
Ich rufe hier auch schonmal die Update() Methode von TItem mit auf, auch wenn diese noch "leer" ist. Da ich die Update() Methode aber auch gleich noch bearbeite, brauch ich sie dann nicht mehr in die Hauptschleife einfügen.
Ab jetzt erscheinen die Items, sobald man einen Block zerstört, unter dem eines versteckt ist
Nun gehts ans einsammeln...
Dazu erhält TSpieler.bmx auch erstmal eine "leere" Update() Methode:
BlitzMax: [AUSKLAPPEN]
diese binde ich auch gleich in die Hauptschleife ein:
BlitzMax: [AUSKLAPPEN]
nun muss ich in der Update() Methode (von TSpieler.bmx) nur noch abfragen, ob das aktuelle Feld, auf dem sich der Spieler befindet, den Flag ITEM_AUFGEDECKT hat. Ist das der Fall, so gehe ich die TList der Items durch und überpfrüfe, welches Item die selben FeldKoordinaten wie der Spieler hat und gebe an das Item weiter, wer es gesammelt hat. Ausserdem entfehrne ich den Flag ITEM_AUFGEDECKT damit kein andere Spieler das Item mehr sammeln kann:
BlitzMax: [AUSKLAPPEN]
Jetzt weiter zur bisher "leeren" Update() Methode von TItem.bmx. Da ich ja nun dem Item übergebe, wer es gesammelt hat, werden dort, dem Spieler, die eingesammelten Items und ihre Fähigkeiten gutgeschrieben. Dazu frage ich ab, ob das Item einen Sammler hat. Ist das der Fall, so wird jeh nach eingesammeltem Item (Select... Case...) der entsprechende Bonus freigegeben. Das Item muss dann natürlich auch gelöscht werden:
BlitzMax: [AUSKLAPPEN]
und nu hab ich richtig Mist gebaut. Spieler1 kann niemals Items einsammeln... und warum nicht? Weil Spieler1 beim Erstellen seiner Variable SpielerNr den Wert = 0 zugewiesen bekommt. Da das Item nur eingesammelt werden kann, wenn Sammler (=SpielerNr) größer ist als 0 wird das nie funktionieren.
Also stehen wieder ein paar Änderungen an der MainGame.bmx an. So wird Spieler1 zur Zeit erstellt:
BlitzMax: [AUSKLAPPEN]
Spieler[0] wird also zu Spieler[1] und die SpielerNr welche in der Erstellen() Funktion übergeben wird muss ebenfalls 1 werden:
Spieler[1] = TSpieler.Erstellen(1,2,2,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
(Änderungen FETT hervorgehoben.)
Wenn es weiterhin 4 spieler geben soll, muss natürlich auch das Array Spieler[] anders dimensioniert werden. So ist es grad noch falsch:
BlitzMax: [AUSKLAPPEN]
So ist es dann richtig:
Global Spieler:TSpieler [5] 'es soll maximal 4 Spieler geben, [5] weil es bei 0 anfängt
(Änderung wieder FETT hervorgehoben.)
und natürlich muss das ganze nun in der Hauptschleife auch nicht mehr mit Spieler[0], sondern mit Spieler[1] aufgerufen werden... so wie hier:
BlitzMax: [AUSKLAPPEN]
damit alles komplett ist... hier nochmal die komplette MainGame.bmx wie sie sein muss:
BlitzMax: [AUSKLAPPEN]
sooooo... nun funktioniert auch das Item sammeln... wenn ich nun über ein Item laufe, verschwindet es. Mehr passiert allerdings noch nicht. Damit aber etwas passiert, muss ich nun wieder die Update() Methode von TItem.bmx bearbeiten und die Select... Case... Bedingung mit Code füllen.
Sammelt der Spieler eine extra Bombe (ITEM_BOMBE) so muss ich einfach nur dem Sammelden Spieler die Variable BombenMenge um 1 erhöhen. Sammelt er Feuer (ITEM_FEUER) so erhöhe ich ihm einfach die Variable FeuerKraft um 1.
Die neue Update() Methode von TItem.bmx:
BlitzMax: [AUSKLAPPEN]
und was soll ich sagen... ES FUNKTIONIERT!!!! *freu*
es sei noch kurz angemerkt, das egal, wieviele ITEM_BOMBE man sammelt, man kann nie mehr als 5 legen, da ich das vorher in TSpieler.bmx so festgelegt habe:
BlitzMax: [AUSKLAPPEN]
wer also mehr legen will, muss hier den Wert erhöhen
So... ab jetzt kann man Items sammeln. Sind zwar bisher nur 2, aber das lässt sich ja leicht ändern
und nun gibts mal wieder den KOMPLETTEN Code (inklusive .exe) bis zu diesem Punkt zum Downloaden:
https://www.blitzforum.de/upload/file.php?id=9457
Ich bedanke mich mal wieder fürs Lesen... und wie immer gilt: Anregungen und Kritik (positiv, wie negativ) sowie Verbesserungsvorschläge sind sehr gerne gesehen!!!
Hier schonmal die Grafik der Items (Item.png):
wird im Ordner GFX unter dem Namen Item.png abgespeichert
Ich benutze hier erstmal nur die ersten beiden Items (Bombe und Feuerkraft)
Erstmal eine neue Datei angelegt... TItem.bmx:
BlitzMax: [AUSKLAPPEN]
Const ITEM_AUFGEDECKT :Int = -1 'Werte für die Items in Konstante setzen
Const ITEM_BOMBE :Int = 1 'erspart mir wieder den Umgang mit Zahlen
Const ITEM_FEUER :Int = 2
Type TItem
Const ITEMFRAMES :Int=3 'Anzahl der Frames der ItemGrafik
Global ItemIMG :TImage = LoadAnimImage("gfx/items.png",TS,TS,0,ITEMFRAMES)
Global ItemListe :TList = CreateList() 'eine globale Liste für alle Items anlegen
Field xFeld :Int 'Koordinaten des Items auf dem Feld
Field yFeld :Int
Field Item :Int 'Welches Item ist es? (I_BOMBE, I_FEUER, usw)
Field Sammler :Int 'wer hat das Item eingesammelt?
Method Update()
End Method
Method Zeichnen()
DrawImage (ItemIMG,xFeld*TS,yFeld*TS,Item)
End Method
Function Erstellen:TItem (xFeld:Int,yFeld:Int,Item:Int)
Local NeuesItem:TItem = New TItem
NeuesItem.xFeld = xFeld
NeuesItem.yFeld = yFeld
NeuesItem.Item = Item
ItemListe.AddLast(NeuesItem) 'neues Item der globalen ItemListe hinzufügen
End Function
End Type
Denke mal, die Kommentare sagen soweit alles und ansonsten ist das ganze ja fast genauso, wie bei den Bomben. Die Update() Methode ist noch leer, kommt aber noch. Die Konstanten ganz am Anfang erleichtern mir nur wieder den Umgang mit Zahlen und werden ausserhalb des Types angelegt, damit ich sie überall benutzen kann.
diese Datei kommt wieder in den INCLUDES Ordner.
Noch schnell in der MainGame.bmx includieren:
BlitzMax: [AUSKLAPPEN]
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
Include "INCLUDES/TBombe.bmx"
Include "INCLUDES/TExplosion.bmx"
Include "INCLUDES/TItem.bmx"
Nun muss ich natürlich auch ein paar der Items auf der Map verstecken. Das erledige ich in der Erstellen() Funktion von TKarte.bmx unter der Stelle, an der ich die SoftBlöcke auf der KArte gesetzt habe:
BlitzMax: [AUSKLAPPEN]
'#############################################
'# MAP MIT ITEMS FÜLLEN #
'# ITEMS DÜRFEN NUR AUF FELDER MIT SOFTBLOCK #
'#############################################
Local AnzahlBomben :Int = 10 'wieviel von welchem Item sollen vorkommen?
Local AnzahlFeuer :Int = 10
Repeat 'BombenItems verstecken
For Local Y:Int=1 To MY
For Local X:Int=1 To MX
If AnzahlBomben > 0 'wenn noch Items zu verstecken sind, dann
If NeueMap.Feld[X,Y].Inhalt = SBLOCK And NeueMap.Feld[X,Y].Item = 0
'wenn auf aktuellem Feld ein Softblock ist, UND noch KEIN Item
If Rand (0,20) = 10 Then 'bei der richtigen Zufallszahl...
NeueMap.Feld[X,Y].Item = ITEM_BOMBE 'Item verstecken
AnzahlBomben:-1 'gelegtes Item von den noch zu legenden abziehen
End If
End If
End If
Next
Next
Until (AnzahlBomben=0)
Repeat 'FeuerItems verstecken
For Local Y:Int=1 To MY
For Local X:Int=1 To MX
If AnzahlFeuer > 0 'wenn noch Items zu verstecken sind, dann
If NeueMap.Feld[X,Y].Inhalt = SBLOCK And NeueMap.Feld[X,Y].Item = 0
'wenn auf aktuellem Feld ein Softblock ist, UND noch KEIN Item
If Rand (0,20) = 10 Then 'bei der richtigen Zufallszahl...
NeueMap.Feld[X,Y].Item = ITEM_FEUER 'Item verstecken
AnzahlFeuer:-1 'gelegtes Item von den noch zu legenden abziehen
End If
End If
End If
Next
Next
Until (AnzahlFeuer=0)
Vielleicht fragt sich ja der ein oder andere, warum ich Zufallszahlen von 0 bis 20 nehme und nicht wie bei den Softblöcken 0 bis 2. Ganz einfach, wenn ich einen kleinen Wertebereich habe, kommt meine gewählte Zahl häufiger, als bei einem großem Wertebereich. Die Folge wäre, das so ziemlich alle Items im Oberen linken Teil der Karte versteckt wären und nicht auf der ganzen Map.
hier noch die vollständige Erstellen() Funktion von TKarte.bmx:
BlitzMax: [AUSKLAPPEN]
Function Erstellen:TKarte(MX:Int,MY:Int,Boden:Int,HardBl:Int,SoftBl:Int)
Local NeueMap:TKarte = New TKarte '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 =HBLOCK
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 =HBLOCK
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 Check 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 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
Next
Next
Until (BlockZahl=0) 'wenn 100 Softblöcke gesetzt wurden Schleife verlassen und Map zurück geben.
'#############################################
'# MAP MIT ITEMS FÜLLEN #
'# ITEMS DÜRFEN NUR AUF FELDER MIT SOFTBLOCK #
'#############################################
Local AnzahlBomben :Int = 10 'wieviel von welchem Item sollen vorkommen?
Local AnzahlFeuer :Int = 10
Repeat 'BombenItems verstecken
For Local Y:Int=1 To MY
For Local X:Int=1 To MX
If AnzahlBomben > 0 'wenn noch Items zu verstecken sind, dann
If NeueMap.Feld[X,Y].Inhalt = SBLOCK And NeueMap.Feld[X,Y].Item = 0
'wenn auf aktuellem Feld ein Softblock ist, UND noch KEIN Item
If Rand (0,20) = 10 Then 'bei der richtigen Zufallszahl...
NeueMap.Feld[X,Y].Item = ITEM_BOMBE 'Item verstecken
AnzahlBomben:-1 'gelegtes Item von den noch zu legenden abziehen
End If
End If
End If
Next
Next
Until (AnzahlBomben=0)
Repeat 'FeuerItems verstecken
For Local Y:Int=1 To MY
For Local X:Int=1 To MX
If AnzahlFeuer > 0 'wenn noch Items zu verstecken sind, dann
If NeueMap.Feld[X,Y].Inhalt = SBLOCK And NeueMap.Feld[X,Y].Item = 0
'wenn auf aktuellem Feld ein Softblock ist, UND noch KEIN Item
If Rand (0,20) = 10 Then 'bei der richtigen Zufallszahl...
NeueMap.Feld[X,Y].Item = ITEM_FEUER 'Item verstecken
AnzahlFeuer:-1 'gelegtes Item von den noch zu legenden abziehen
End If
End If
End If
Next
Next
Until (AnzahlFeuer=0)
Return NeueMap 'hiermit gebe ich die temporär erstellte Map zurück
End Function
Jetzt, wo die Items auf der Map verteilt sind, muss ich sie nur noch erstellen, sobald ein Softblock, unter dem sich ein Item befindet, zerstört wird. Das wird in der Update() Methode von TFeld.bmx erledigt:
BlitzMax: [AUSKLAPPEN]
Method Update(x:Int,y:Int)
If Inhalt = NIX And BlockTile > 0'wenn NIX im Feld aber ein BlockTile da ist
BlockTile = 0 'BlockTile löschen
End If
If Inhalt = NIX And Item > 0'wenn NIX im Feld und ein Item wurde freigelegt
TItem.Erstellen(x,y,Item) 'Item erstellen
Item = ITEM_AUFGEDECKT 'und als aufgedeckt markieren.
End If
End Method
Der Methode müssen nun Parameter übergeben werden, damit das Item auch seine x und y Koordinaten bekommt. Also muss der Aufruf der Update() Methode von TFeld ebenfalls angepasst werden.
Aufgerufen wird sie in TKarte.bmx in der Methode Zeichnen. Also passe ich den Aufruf dort an:
BlitzMax: [AUSKLAPPEN]
Method Zeichnen()
For Local Y:Int=1 To MX
For Local X:Int=1 To MY
Feld[X,Y].Update(X,Y) 'Aktuelles Feld auf Richtigkeit prüfen
Feld[X,Y].Zeichnen(X,Y) 'Übergibt X und Y Werte an Feld.Zeichnen
Next
Next
End Method
Erstellt werden die Items nun... doch ich muss sie auch in der Hauptschleife von MainGame Zeichnen lassen:
BlitzMax: [AUSKLAPPEN]
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Update()
Bombe.Zeichnen()
Next
For Local Explosion:TExplosion = EachIn TExplosion.ExplosionsListe 'jede erstellte Explosion durchgehen
Explosion.Update()
Explosion.Zeichnen()
Next
For Local Item:TItem = EachIn TItem.ItemListe 'jedes erstellte Item durchgehen
Item.Update()
Item.Zeichnen()
Next
Spieler[0].Zeichnen()
Spieler[0].Steuerung()
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts gedrückt wird
End
Ich rufe hier auch schonmal die Update() Methode von TItem mit auf, auch wenn diese noch "leer" ist. Da ich die Update() Methode aber auch gleich noch bearbeite, brauch ich sie dann nicht mehr in die Hauptschleife einfügen.
Ab jetzt erscheinen die Items, sobald man einen Block zerstört, unter dem eines versteckt ist
Nun gehts ans einsammeln...
Dazu erhält TSpieler.bmx auch erstmal eine "leere" Update() Methode:
BlitzMax: [AUSKLAPPEN]
Method Update()
End Method
diese binde ich auch gleich in die Hauptschleife ein:
BlitzMax: [AUSKLAPPEN]
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Update()
Bombe.Zeichnen()
Next
For Local Explosion:TExplosion = EachIn TExplosion.ExplosionsListe 'jede erstellte Explosion durchgehen
Explosion.Update()
Explosion.Zeichnen()
Next
For Local Item:TItem = EachIn TItem.ItemListe 'jedes erstellte Item durchgehen
Item.Update()
Item.Zeichnen()
Next
Spieler[0].Steuerung()
Spieler[0].Update()
Spieler[0].Zeichnen()
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts gedrückt wird
End
nun muss ich in der Update() Methode (von TSpieler.bmx) nur noch abfragen, ob das aktuelle Feld, auf dem sich der Spieler befindet, den Flag ITEM_AUFGEDECKT hat. Ist das der Fall, so gehe ich die TList der Items durch und überpfrüfe, welches Item die selben FeldKoordinaten wie der Spieler hat und gebe an das Item weiter, wer es gesammelt hat. Ausserdem entfehrne ich den Flag ITEM_AUFGEDECKT damit kein andere Spieler das Item mehr sammeln kann:
BlitzMax: [AUSKLAPPEN]
Method Update()
If Map.Feld[xFeld,yFeld].Item = ITEM_AUFGEDECKT 'wenn aufgedecktes Item auf SpielerFeld
For Local Item:TItem = EachIn TItem.ItemListe 'jedes erstellte Item durchgehen
If xFeld=Item.xFeld And yFeld=Item.yFeld 'wenn richtiges Item gefunden
Map.Feld[xFeld,yFeld].Item = 0 'ItemFlag auf 0
Item.Sammler = SpielerNr 'Spieler der es gesammelt hat festlegen
End If
Next
End If
End Method
Jetzt weiter zur bisher "leeren" Update() Methode von TItem.bmx. Da ich ja nun dem Item übergebe, wer es gesammelt hat, werden dort, dem Spieler, die eingesammelten Items und ihre Fähigkeiten gutgeschrieben. Dazu frage ich ab, ob das Item einen Sammler hat. Ist das der Fall, so wird jeh nach eingesammeltem Item (Select... Case...) der entsprechende Bonus freigegeben. Das Item muss dann natürlich auch gelöscht werden:
BlitzMax: [AUSKLAPPEN]
Method Update()
If Sammler > 0 'wenn jemand das Item eingesammelt hat
Select Item
Case ITEM_BOMBE
'Spieler kann eine Bombe mehr legen
Case ITEM_FEUER
'Spieler erhält mehr FeuerKraft
End Select
ItemListe.Remove(Self) 'Item aus Liste löschen
End If
End Method
und nu hab ich richtig Mist gebaut. Spieler1 kann niemals Items einsammeln... und warum nicht? Weil Spieler1 beim Erstellen seiner Variable SpielerNr den Wert = 0 zugewiesen bekommt. Da das Item nur eingesammelt werden kann, wenn Sammler (=SpielerNr) größer ist als 0 wird das nie funktionieren.
Also stehen wieder ein paar Änderungen an der MainGame.bmx an. So wird Spieler1 zur Zeit erstellt:
BlitzMax: [AUSKLAPPEN]
'------------------------------ Type-Erstellungen ----------
Global Map:TKarte = TKarte.Erstellen(15,15,0,1,2)
Global Spieler:TSpieler [4] 'es soll maximal 4 Spieler geben
Spieler[0] = TSpieler.Erstellen(0,2,2,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
Spieler[0] wird also zu Spieler[1] und die SpielerNr welche in der Erstellen() Funktion übergeben wird muss ebenfalls 1 werden:
Spieler[1] = TSpieler.Erstellen(1,2,2,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
(Änderungen FETT hervorgehoben.)
Wenn es weiterhin 4 spieler geben soll, muss natürlich auch das Array Spieler[] anders dimensioniert werden. So ist es grad noch falsch:
BlitzMax: [AUSKLAPPEN]
Global Spieler:TSpieler [4] 'es soll maximal 4 Spieler geben
So ist es dann richtig:
Global Spieler:TSpieler [5] 'es soll maximal 4 Spieler geben, [5] weil es bei 0 anfängt
(Änderung wieder FETT hervorgehoben.)
und natürlich muss das ganze nun in der Hauptschleife auch nicht mehr mit Spieler[0], sondern mit Spieler[1] aufgerufen werden... so wie hier:
BlitzMax: [AUSKLAPPEN]
Spieler[1].Steuerung()
Spieler[1].Update()
Spieler[1].Zeichnen()
damit alles komplett ist... hier nochmal die komplette MainGame.bmx wie sie sein muss:
BlitzMax: [AUSKLAPPEN]
'MainGame.bmx
SuperStrict 'zwingt mich, sauber zu programmieren
Framework brl.max2d
Import brl.Timer
Import brl.Random
Import brl.D3D9Max2D
Import brl.PNGLoader
AppTitle = "Bomberman Klon (Community Tutorial)"
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
Include "INCLUDES/TBombe.bmx"
Include "INCLUDES/TExplosion.bmx"
Include "INCLUDES/TItem.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
SetGraphicsDriver D3D9Max2DDriver()
Graphics BREITE, HOEHE, Vollbild 'Bildschirmmodus wird gesetzt
'AutoMidHandle(1)
'------------------------------ Vorbereitungen ----------
Const TS :Int = 32 'Tilegröße (32*32)
Global Frames :TTimer = CreateTimer (120) '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:TKarte = TKarte.Erstellen(15,15,0,1,2)
Global Spieler:TSpieler [5] 'es soll maximal 4 Spieler geben, [5] weil es bei 0 anfängt
Spieler[1] = TSpieler.Erstellen(1,2,2,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
'------------------------------ Hauptschleife ----------
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Update()
Bombe.Zeichnen()
Next
For Local Explosion:TExplosion = EachIn TExplosion.ExplosionsListe 'jede erstellte Explosion durchgehen
Explosion.Update()
Explosion.Zeichnen()
Next
For Local Item:TItem = EachIn TItem.ItemListe 'jedes erstellte Item durchgehen
Item.Update()
Item.Zeichnen()
Next
Spieler[1].Steuerung()
Spieler[1].Update()
Spieler[1].Zeichnen()
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts gedrückt wird
End
sooooo... nun funktioniert auch das Item sammeln... wenn ich nun über ein Item laufe, verschwindet es. Mehr passiert allerdings noch nicht. Damit aber etwas passiert, muss ich nun wieder die Update() Methode von TItem.bmx bearbeiten und die Select... Case... Bedingung mit Code füllen.
Sammelt der Spieler eine extra Bombe (ITEM_BOMBE) so muss ich einfach nur dem Sammelden Spieler die Variable BombenMenge um 1 erhöhen. Sammelt er Feuer (ITEM_FEUER) so erhöhe ich ihm einfach die Variable FeuerKraft um 1.
Die neue Update() Methode von TItem.bmx:
BlitzMax: [AUSKLAPPEN]
Method Update()
If Sammler > 0 'wenn jemand das Item eingesammelt hat
Select Item
Case ITEM_BOMBE
Spieler[Sammler].BombenMenge:+1 'Spieler kann eine Bombe mehr legen
Case ITEM_FEUER
Spieler[Sammler].FeuerKraft:+1 'Spieler erhält mehr FeuerKraft
End Select
ItemListe.Remove(Self) 'Item aus Liste löschen
End If
End Method
und was soll ich sagen... ES FUNKTIONIERT!!!! *freu*
es sei noch kurz angemerkt, das egal, wieviele ITEM_BOMBE man sammelt, man kann nie mehr als 5 legen, da ich das vorher in TSpieler.bmx so festgelegt habe:
BlitzMax: [AUSKLAPPEN]
Field MaxBombenMenge :Int = 5 'egal wieviele Items man sammelt, man kann nie mehr legen, als hier verzeichnet
wer also mehr legen will, muss hier den Wert erhöhen
So... ab jetzt kann man Items sammeln. Sind zwar bisher nur 2, aber das lässt sich ja leicht ändern
und nun gibts mal wieder den KOMPLETTEN Code (inklusive .exe) bis zu diesem Punkt zum Downloaden:
https://www.blitzforum.de/upload/file.php?id=9457
Ich bedanke mich mal wieder fürs Lesen... und wie immer gilt: Anregungen und Kritik (positiv, wie negativ) sowie Verbesserungsvorschläge sind sehr gerne gesehen!!!
Vorbereitungen für die Items
Sonntag, 5. September 2010 von KirkZero
Auf zu den Items:
erstmal neues Field in TFeld.bmx:
BlitzMax: [AUSKLAPPEN]
Sollte später unter dem SoftBlock/auf dem Feld ein Item sein, so entspricht der Wert des Feldes, welches Item dort liegt.
Auch TSpieler benötigt neue Fields:
BlitzMax: [AUSKLAPPEN]
BombenMenge sollte klar sein. Bedeutet, wieviele Bomben der Spieler gleichzeitig auf der Map legen kann.
MaxBombenMenge steht dafür, wieviele Bomben man ALLGEMEIN überhaupt legen darf... unabhängig davon, wieviele Items,welche einem mehr Bomben geben, man eingesammelt hat.
In der Variable gelegte Bomben wird festgehalten, wieviele Bomben der Spieler bereits gelegt hat, welche noch nicht explodiert sind.
Jede neu erstellte Klasse TSpieler soll nun bei der Erstellung mit auf den Weg bekommen, welcher Spieler er eigentlich ist. dieser Wert wird in SpielerNr gespeichert.
Hier die neue Erstellen() Funktion von TSpieler:
BlitzMax: [AUSKLAPPEN]
Nun noch ein paar Änderungen an der MainGame.bmx. Da der Spieler nun seine SpielerNr mitbekommen soll, muss die Erstellen() Funktion anders aufgerufen werden. Ausserdem ist der Spieler nun ein Array:
BlitzMax: [AUSKLAPPEN]
Hauptschleife noch anpassen:
BlitzMax: [AUSKLAPPEN]
und schon läuft das ganze wieder.
Jetzt muss ich noch jeder Bombe, die ich lege ebenfalls mit auf den Weg geben, welcher Spieler sie gelegt hat. TBombe bekommt also ein neues Field und eine angepasste Erstellen() Funktion:
BlitzMax: [AUSKLAPPEN]
BlitzMax: [AUSKLAPPEN]
und den Aufruf in TSpieler ebenfalls angepasst:
BlitzMax: [AUSKLAPPEN]
Wo ich schonmal bei der Methode BombeLegen bin...
Ich möchte ja, das der Spieler nur so viele Bomben legen kann, wie er Items dafür eingesammelt hat und dazu noch nicht mehr als in der Variablen MaxBombenMenge angegeben. Also muss eine If Abfrage her:
BlitzMax: [AUSKLAPPEN]
Startet man nun das Programm, so kann man nur eine Bombe legen. Wenn diese explodiert kann man allerdings keine weitere legen, da die Variable GelegteBomben nach der Explosion nicht wieder um 1 reduziert wird.
Das erledige ich in TBombe.bmx in der Update() Methode:
BlitzMax: [AUSKLAPPEN]
Diese Stelle sorgt dafür, das der Spieler nach der Explosion der Bombe auch wieder weitere legen kann:
BlitzMax: [AUSKLAPPEN]
Noch kurz ein Testlauf....
Funktioniert perfekt
nun ist alles soweit für die ersten beiden Items vorbereitet
Es handelt sich dabei um ein Item, welches die Feuerkraft erhöht und das andere die Anzahl der Bomben, die man legen kann.
Diese gibts aber erst im nächsten Eintrag
Hier nochmal alle .bmx Dateien, die ich bearbeitet habe:
BlitzMax: [AUSKLAPPEN]
BlitzMax: [AUSKLAPPEN]
BlitzMax: [AUSKLAPPEN]
BlitzMax: [AUSKLAPPEN]
Danke fürs Lesen!!!
erstmal neues Field in TFeld.bmx:
BlitzMax: [AUSKLAPPEN]
Field Item :Int 'bekommt den Wert des Items, wenn kein Item, dann = 0
Sollte später unter dem SoftBlock/auf dem Feld ein Item sein, so entspricht der Wert des Feldes, welches Item dort liegt.
Auch TSpieler benötigt neue Fields:
BlitzMax: [AUSKLAPPEN]
Field SpielerNr :Int 'Welcher Spieler bin ich? 1,2,3 oder 4
Field BombenMenge :Int = 1 'Anzahl an Bomben, die der Spieler gleichzeitig legen kann
Field MaxBombenMenge :Int = 5 'egal wieviele Items man sammelt, man kann nie mehr legen, als hier verzeichnet
Field GelegteBomben :Int 'Wieviel hat der Spieler bereits gelegt und sind noch nicht explodiert?
BombenMenge sollte klar sein. Bedeutet, wieviele Bomben der Spieler gleichzeitig auf der Map legen kann.
MaxBombenMenge steht dafür, wieviele Bomben man ALLGEMEIN überhaupt legen darf... unabhängig davon, wieviele Items,welche einem mehr Bomben geben, man eingesammelt hat.
In der Variable gelegte Bomben wird festgehalten, wieviele Bomben der Spieler bereits gelegt hat, welche noch nicht explodiert sind.
Jede neu erstellte Klasse TSpieler soll nun bei der Erstellung mit auf den Weg bekommen, welcher Spieler er eigentlich ist. dieser Wert wird in SpielerNr gespeichert.
Hier die neue Erstellen() Funktion von TSpieler:
BlitzMax: [AUSKLAPPEN]
Function Erstellen:TSpieler (SpielerNr:Int,xFeld:Int,yFeld:Int,ImgPfadName:String,ImgFrames:Int)
Local NeuerSpieler :TSpieler = New TSpieler 'Temporären Spieler erstellen
NeuerSpieler.SpielerNr = SpielerNr 'welcher Spieler bin ich?
NeuerSpieler.xFeld = xFeld 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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 noch ein paar Änderungen an der MainGame.bmx. Da der Spieler nun seine SpielerNr mitbekommen soll, muss die Erstellen() Funktion anders aufgerufen werden. Ausserdem ist der Spieler nun ein Array:
BlitzMax: [AUSKLAPPEN]
'------------------------------ Type-Erstellungen ----------
Global Map:TKarte = TKarte.Erstellen(15,15,0,1,2)
Global Spieler:TSpieler [4] 'es soll maximal 4 Spieler geben
Spieler[0] = TSpieler.Erstellen(0,2,2,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
Hauptschleife noch anpassen:
BlitzMax: [AUSKLAPPEN]
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Update()
Bombe.Zeichnen()
Next
For Local Explosion:TExplosion = EachIn TExplosion.ExplosionsListe 'jede erstellte Explosion durchgehen
Explosion.Update()
Explosion.Zeichnen()
Next
Spieler[0].Zeichnen()
Spieler[0].Steuerung()
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts gedrückt wird
End
und schon läuft das ganze wieder.
Jetzt muss ich noch jeder Bombe, die ich lege ebenfalls mit auf den Weg geben, welcher Spieler sie gelegt hat. TBombe bekommt also ein neues Field und eine angepasste Erstellen() Funktion:
BlitzMax: [AUSKLAPPEN]
Field Besitzer :Int 'wer hat die Bombe gelegt ?
BlitzMax: [AUSKLAPPEN]
Function Erstellen:TBombe(Besitzer:Int,xFeld:Int,yFeld:Int,FeuerKraft:Int) 'neue Bombe wird erstellt
Local NeueBombe:TBombe = New TBombe
NeueBombe.Besitzer = Besitzer 'Wer hat die Bombe gelegt?
NeueBombe.xFeld=xFeld 'Koordinaten der neuen Bombe übergeben
NeueBombe.yFeld=yFeld
NeueBombe.FeuerKraft=FeuerKraft
Map.Feld[xFeld,yFeld].Inhalt = BOMBE 'wichtig! Inhalt des Feldes auf Bombe setzen
BombenListe.AddLast(NeueBombe) 'neue Bombe der globalen BombenListe hinzufügen
End Function
und den Aufruf in TSpieler ebenfalls angepasst:
BlitzMax: [AUSKLAPPEN]
Method BombeLegen()
If Map.Feld[xFeld,yFeld].Inhalt = NIX 'wenn aktuelles Feld leer ist
TBombe.Erstellen(SpielerNr,xFeld,yFeld,FeuerKraft)
End If
End Method
Wo ich schonmal bei der Methode BombeLegen bin...
Ich möchte ja, das der Spieler nur so viele Bomben legen kann, wie er Items dafür eingesammelt hat und dazu noch nicht mehr als in der Variablen MaxBombenMenge angegeben. Also muss eine If Abfrage her:
BlitzMax: [AUSKLAPPEN]
Method BombeLegen()
If Map.Feld[xFeld,yFeld].Inhalt = NIX 'wenn aktuelles Feld leer ist
If GelegteBomben < BombenMenge And GelegteBomben < MaxBombenMenge
'wenn bisher weniger Bomben gelegt als man kann UND als man darf
TBombe.Erstellen(SpielerNr,xFeld,yFeld,FeuerKraft) 'Bombe erstellen
GelegteBomben:+1 'um 1 erhöhen, da ja nun eine bombe gelegt wurde
End If
End If
End Method
Startet man nun das Programm, so kann man nur eine Bombe legen. Wenn diese explodiert kann man allerdings keine weitere legen, da die Variable GelegteBomben nach der Explosion nicht wieder um 1 reduziert wird.
Das erledige ich in TBombe.bmx in der Update() Methode:
BlitzMax: [AUSKLAPPEN]
Method Update()
If MilliSecs() > BombenTimer+BombenIntervall
BombenCountDown:-1 'Intervall erreicht, CountDown um 1 verringern
BombenTimer=MilliSecs()
If BombenFrame < BOMBENFRAMES-1
BombenFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
End If
End If
If Map.Feld[xFeld,yFeld].Explosion = True 'Explosion auf Feld
BombenCountDown = 0 'Bombe zur Explosion bringen
End If
If BombenCountDown <=0 'CountDown ist abgelaufen *BOOOM*
Spieler[Besitzer].GelegteBomben:-1 'damit der Spieler wieder neue Bomben legen kann
BombenListe.Remove(Self) 'Bombe aus Liste löschen
Map.Feld[xFeld,yFeld].Inhalt = NIX 'wichtig! Inhalt des Feldes auf NIX zurück setzen
TExplosion.Erstellen(xFeld,yFeld,FeuerKraft) 'Explosion wird erstellt
End If
End Method
Diese Stelle sorgt dafür, das der Spieler nach der Explosion der Bombe auch wieder weitere legen kann:
BlitzMax: [AUSKLAPPEN]
If BombenCountDown <=0 'CountDown ist abgelaufen *BOOOM*
Spieler[Besitzer].GelegteBomben:-1 'damit der Spieler wieder neue Bomben legen kann
BombenListe.Remove(Self) 'Bombe aus Liste löschen
Map.Feld[xFeld,yFeld].Inhalt = NIX 'wichtig! Inhalt des Feldes auf NIX zurück setzen
TExplosion.Erstellen(xFeld,yFeld,FeuerKraft) 'Explosion wird erstellt
End If
Noch kurz ein Testlauf....
Funktioniert perfekt
nun ist alles soweit für die ersten beiden Items vorbereitet
Es handelt sich dabei um ein Item, welches die Feuerkraft erhöht und das andere die Anzahl der Bomben, die man legen kann.
Diese gibts aber erst im nächsten Eintrag
Hier nochmal alle .bmx Dateien, die ich bearbeitet habe:
BlitzMax: [AUSKLAPPEN]
Type TFeld
Const BODENFRAMES :Int=5
Const BLOCKFRAMES :Int=3
Global BodenTilesIMG :TImage = LoadAnimImage("gfx/boden.png",TS,TS,0,BODENFRAMES)
Global BlockTilesIMG :TImage = LoadAnimImage("gfx/block.png",TS,TS,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, 5=Bombe, 10=unzerstöbar/unpassierbar
Field Explosion :Int 'wird auf true gesetzt, solange eine Explosion auf dem Feld ist
Field Item :Int 'bekommt den Wert des Items, wenn kein Item, dann = 0
Method Update()
If Inhalt = NIX And BlockTile > 0'wenn NIX im Feld aber ein BlockTile da ist
BlockTile = 0 'BlockTile löschen
End If
End Method
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) 'BodenTile wird übergeben
Local NeuesFeld:TFeld = New TFeld
NeuesFeld.BodenTile=Boden
Return NeuesFeld
End Function
End Type
BlitzMax: [AUSKLAPPEN]
Type TSpieler
Field SpielerNr :Int 'Welcher Spieler bin ich? 1,2,3 oder 4
Field xFeld :Int 'x und y Koordinaten für das entsprechende FELD
Field yFeld :Int 'auf dem sich der Spieler befindet
Field xPos :Int 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Int
Field Speed :Int = 2 'man bewegt sich immer um 2 Pixel pro Bewegung
Field FeuerKraft :Int = 2 'Reichweite der Explosionen einer Bombe (2 Felder in alle Richtungen)
Field BombenMenge :Int = 1 'Anzahl an Bomben, die der Spieler gleichzeitig legen kann
Field MaxBombenMenge :Int = 5 'egal wieviele Items man sammelt, man kann nie mehr legen, als hier verzeichnet
Field GelegteBomben :Int 'Wieviel hat der Spieler bereits gelegt und sind noch nicht explodiert?
Const OBEN :Int = 0
Const UNTEN :Int = 1
Const LINKS :Int = 2
Const RECHTS :Int = 3
Field SpielerIMG :TImage 'speichert die Grafik des Spielers
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 20
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Bewegung wieder erlaubt (Zeit)
If KeyDown(KEY_UP) 'wenn Pfeiltaste OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(KEY_DOWN) 'wenn Pfeiltaste UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(KEY_LEFT) 'wenn Pfeiltaste LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(KEY_RIGHT) 'wenn Pfeiltaste RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End If
If KeyHit(KEY_LCONTROL) 'wenn linke STRG Taste gedrückt wird
BombeLegen() 'dann Methode zum Bombenlegen aufrufen
End If
End Method
Method BombeLegen()
If Map.Feld[xFeld,yFeld].Inhalt = NIX 'wenn aktuelles Feld leer ist
If GelegteBomben < BombenMenge And GelegteBomben < MaxBombenMenge
'wenn bisher weniger Bomben gelegt als man kann UND als man darf
TBombe.Erstellen(SpielerNr,xFeld,yFeld,FeuerKraft) 'Bombe erstellen
GelegteBomben:+1 'um 1 erhöhen, da ja nun eine bombe gelegt wurde
End If
End If
End Method
Method Bewegung(Richtung:Int)
Local x :Int 'Temporäre Speicher
Local y :Int
Local fx :Int 'Temporäre Speicher für zu prüfende Felder
Local fy :Int 'ist fy=-1 wird oberes vom aktuellen Feld geprüft
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
Select Richtung
Case OBEN
fy=-1 'oberes Feld prüfen
Case UNTEN
fy=+1 'unteres Feld prüfen
Case LINKS
fx=-1 'linkes Feld prüfen
Case RECHTS
fx=+1 'rechtes Feld prüfen
End Select
If Map.Feld[xFeld+fx,yFeld+fy].Inhalt = NIX 'wenn auf dem zu prüfenden Feld NIX ist
If fy <> 0 'ist das zu prüfende Feld oben oder unten, dann auf Autobewegung checken
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else
y=fy*Speed 'passt es genau, dann um Speed Pixel nach fy bewegen
End If
End If
If fx <> 0 'ist das zu prüfende Feld links oder rechts, dann auf Autobewegung checken
If yFeld*TS < yPos 'ist (Y Feldkoordinate*TS) kleiner als Pixelkoordinate
y=-Speed 'dann um Speed Pixel nach oben bewegen
Else If yFeld*TS > yPos 'ist (Y Feldkoordinate*TS) größer als Pixelkoordinate
y=+Speed 'dann um Speed Pixel nach unten bewegen
Else
x=fx*Speed 'passt es genau, dann um Speed Pixel nach fx bewegen
End If
End If
Else If fy <> 0 And yMod <> 0 'wenn nicht begehbar aber noch nicht ganz auf dem Feld, dann trotzdem bewegen
y=fy*Speed
Else If fx <> 0 And xMod <> 0 'wenn nicht begehbar aber noch nicht ganz auf dem Feld, dann trotzdem bewegen
x=fx*Speed
End If
yPos:+y 'Spieler Koordinaten aktualisieren
xPos:+x
MapFeld() 'Aktuelles Map.Feld[,] wird berechnet
BewegungsTimer = MilliSecs()
End Method
Method MapFeld() 'berechnet aktuelles Map.Feld[,]
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
If yMod < (TS/2) Then yFeld=(yPos/TS) 'wenn modulus < als 16
If yMod > (TS/2) Then yFeld=(yPos/TS)+1 'wenn modulus > als 16
If xMod < (TS/2) Then xFeld=(xPos/TS) 'wenn modulus < als 16
If xMod > (TS/2) Then xFeld=(xPos/TS)+1 'wenn modulus > als 16
End Method
Method Zeichnen()
'DrawRect (xFeld*TS,yFeld*TS,TS,TS) 'Erstmal auskommentiert... vorerst klappt ja alles
DrawImage (SpielerIMG,xPos,yPos,0)
End Method
Function Erstellen:TSpieler (SpielerNr:Int,xFeld:Int,yFeld:Int,ImgPfadName:String,ImgFrames:Int)
Local NeuerSpieler :TSpieler = New TSpieler 'Temporären Spieler erstellen
NeuerSpieler.SpielerNr = SpielerNr 'welcher Spieler bin ich?
NeuerSpieler.xFeld = xFeld 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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
BlitzMax: [AUSKLAPPEN]
Type TBombe
Const BOMBENFRAMES :Int=3 'Anzahl der Frames der BombenGrafik
Global BombenIMG :TImage = LoadAnimImage("gfx/bombe.png",TS,TS,0,BOMBENFRAMES)
Global BombenListe :TList = CreateList() 'eine globale Liste für alle Bomben anlegen
Field Besitzer :Int 'wer hat die Bombe gelegt ?
Field xFeld :Int 'Koordinaten der Bombe auf dem Feld
Field yFeld :Int
Field FeuerKraft :Int 'Reichweite der Explosionen einer Bombe
Field BombenFrame :Int = 0 'Aktuelles Frame der BombenGrafik (0=erstes Frame)
Field BombenCountDown :Int = 3 'jede Bombe soll nach 3 Sekunden (oder Intervallen) explodieren
Field BombenIntervall :Int = 1000 'der Intervall mit dem runtergezählt wird (1000 = 1 Sekunde)
Field BombenTimer :Int = MilliSecs() 'aktuelle Zeit setzen
Method Update()
If MilliSecs() > BombenTimer+BombenIntervall
BombenCountDown:-1 'Intervall erreicht, CountDown um 1 verringern
BombenTimer=MilliSecs()
If BombenFrame < BOMBENFRAMES-1
BombenFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
End If
End If
If Map.Feld[xFeld,yFeld].Explosion = True 'Explosion auf Feld
BombenCountDown = 0 'Bombe zur Explosion bringen
End If
If BombenCountDown <=0 'CountDown ist abgelaufen *BOOOM*
Spieler[Besitzer].GelegteBomben:-1 'damit der Spieler wieder neue Bomben legen kann
BombenListe.Remove(Self) 'Bombe aus Liste löschen
Map.Feld[xFeld,yFeld].Inhalt = NIX 'wichtig! Inhalt des Feldes auf NIX zurück setzen
TExplosion.Erstellen(xFeld,yFeld,FeuerKraft) 'Explosion wird erstellt
End If
End Method
Method Zeichnen()
DrawImage (BombenIMG,xFeld*TS,yFeld*TS,BombenFrame)
End Method
Function Erstellen:TBombe(Besitzer:Int,xFeld:Int,yFeld:Int,FeuerKraft:Int) 'neue Bombe wird erstellt
Local NeueBombe:TBombe = New TBombe
NeueBombe.Besitzer = Besitzer 'Wer hat die Bombe gelegt?
NeueBombe.xFeld=xFeld 'Koordinaten der neuen Bombe übergeben
NeueBombe.yFeld=yFeld
NeueBombe.FeuerKraft=FeuerKraft
Map.Feld[xFeld,yFeld].Inhalt = BOMBE 'wichtig! Inhalt des Feldes auf Bombe setzen
BombenListe.AddLast(NeueBombe) 'neue Bombe der globalen BombenListe hinzufügen
End Function
End Type
BlitzMax: [AUSKLAPPEN]
'MainGame.bmx
SuperStrict 'zwingt mich, sauber zu programmieren
Framework brl.max2d
Import brl.Timer
Import brl.Random
Import brl.D3D9Max2D
Import brl.PNGLoader
AppTitle = "Bomberman Klon (Community Tutorial)"
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
Include "INCLUDES/TBombe.bmx"
Include "INCLUDES/TExplosion.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
SetGraphicsDriver D3D9Max2DDriver()
Graphics BREITE, HOEHE, Vollbild 'Bildschirmmodus wird gesetzt
'AutoMidHandle(1)
'------------------------------ Vorbereitungen ----------
Const TS :Int = 32 'Tilegröße (32*32)
Global Frames :TTimer = CreateTimer (120) '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:TKarte = TKarte.Erstellen(15,15,0,1,2)
Global Spieler:TSpieler [4] 'es soll maximal 4 Spieler geben
Spieler[0] = TSpieler.Erstellen(0,2,2,"GFX/robo1.png",20) 'Spieler 1 wird erstellt
'------------------------------ Hauptschleife ----------
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Update()
Bombe.Zeichnen()
Next
For Local Explosion:TExplosion = EachIn TExplosion.ExplosionsListe 'jede erstellte Explosion durchgehen
Explosion.Update()
Explosion.Zeichnen()
Next
Spieler[0].Zeichnen()
Spieler[0].Steuerung()
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts gedrückt wird
End
Danke fürs Lesen!!!
Die Bombe kann... BOOOM ;)
Donnerstag, 2. September 2010 von KirkZero
So, die Explosionen sollen nun auch etwas kaputt machen...
nämlich andere Bomben und SoftBlöcke.
Zuerst mal sollen andere Bomben zur Explosion gebracht werden.
Ich setze jedesmal, wenn ich eine Explosion erstelle (siehe vorigen WorklogEintrag) dem Field Explosion den flag True:
BlitzMax: [AUSKLAPPEN]
nun muss ich einfach in der Update() Methode von TBombe.bmx jedesmal prüfen, ob das Feld, auf dem die Bombe liegt im Field Explosion den wert True hat, ist dem so, so lasse ich die Bombe Explodieren:
BlitzMax: [AUSKLAPPEN]
und schon entzünden Explosionen andere Bomben
Anmerkung von mir: auf diese Weise prüfe ich später auch, ob ein Spieler in einer Explosion steht
Nun will ich auch, dass eine Explosion, die auf eine Bombe trifft, sich nicht weiter fortpflanzt:
Ich weise jedesmal, wenn ich eine Bombe lege (siehe vorigen WorklogEintrag) dem Inhalt des Feldes den Wert der Konstante BOMBE zu:
BlitzMax: [AUSKLAPPEN]
Somit muss ich also nur rausfinden, ob der Inhalt des Feldes, auf dem ich eine neue Explosion erstelle den Wert der Konstante BOMBE beträgt:
BlitzMax: [AUSKLAPPEN]
ist das der Fall, soll die FeuerKraft auf 0 gesetzt werden, damit sich die Explosion nicht weiter ausbreitet.
Das Ganze kommt nun mit in die Erstellen Funktion von TExplosion:
BlitzMax: [AUSKLAPPEN]
Das war einfacher, als ich anfangs dachte
Jetzt lassen sich Kettenreaktionen auslösen
so, nun gehts den SoftBlöcken an den Kragen.
Da die Map z.Z. keine Softblöcke enthält (hatte den Wert auf 0 gesetzt, damit ich die Bewegung besser testen konnte), werd ich nun wieder ein paar einfügen. Dazu einfach die Erstellen Funktion von TKarte.bmx bearbeiten:
BlitzMax: [AUSKLAPPEN]
ich lasse nun einfach mal 50 zufällige Softblöcke erstellen.
Ich muss nun einfach nur prüfen, ob der inhalt des Feldes ein softblock ist, dann die Fortpflanzung der Explosion stoppen und den Inhalt des Feldes auf NIX setzen:
BlitzMax: [AUSKLAPPEN]
Das ganze kommt in die Update() Methode der TExplosion.bmx und zwar ganz am Anfang (es soll ja die Fortpflanzung verhindert werden):
BlitzMax: [AUSKLAPPEN]
Jetzt wird bei einer Explosion auf einem Softblock der Inhalt auf NIX gesetzt, und man kann durchlaufen... der Block bleibt aber weiterhin sichtbar. Das liegt daran, das der Inhalt des Feldes nichts mit dessen Grafik zu tun hat. Eine Update() Methode in TFeld.bmx schafft da abhilfe:
BlitzMax: [AUSKLAPPEN]
so... diese Update() Methode rufe ich in der Zeichnen() Methode von TKarte.bmx auf:
BlitzMax: [AUSKLAPPEN]
und schon werden Felder, welche den Inhalt NIX haben, aber dennoch BlockTiles besitzen korrigiert. Die Update() Methode von TFeld werde ich später noch für andere Sachen benutzen
Noch einen WICHTIGE Fehlerkorrektur:
Ich habe grade gemerkt, das es möglich ist, das ein Feld den Status Explosion = True zu früh verlieren kann, wenn sich Explosionen auf einem Feld überschneiden. Um das zu umgehen, setze ich den Status am Anfang der Update() Methode von TExplosion immer wieder erneut auf True!!!:
BlitzMax: [AUSKLAPPEN]
Ausserdem kann nun endlich mal das DrawRect weg, welches mir visuell anzeigt, auf welchem Feld sich der Spieler grad befindet. Dazu kommentiere ich den Befehl einfach erstmal aus (vielleicht brauche ich es ja später nocheinmal) das erledige ich dann in der Zeichnen() Methode von TSpieler:
BlitzMax: [AUSKLAPPEN]
Download (Code und .EXE) bis hier hin:
https://www.blitzforum.de/upload/file.php?id=9438
Nun werden Softblöcke gesprengt... andere Bomben zur Explosion gebracht und mich bringt es nun zu der Überlegung:
ITEMS
wie machen? Hardcode oder durch script?
Jetzt brauch ich ein bissel Hilfe... Hardcoded wäre das alles kein Problem... aber, da ich ja auch was lernen will, würde ich diese gerne per Script oder sonstiges (externe Datei) ins Spiel bringen.
Welche Möglichkeiten wären sinnvoll???
Gibt es ein tolles Tutorial (englisch oder deutsch ist egal) oder hat da jemand ne tolle Anregung?
Hoffe in der Richtung auf zahlreiche Kommentare und Anregungen... und natürlich dürft ihr mir wie immer auf die Finger hauen, wenn ich bisher mist gebaut habe...
Ich bedanke mich schonmal und mach mir jetzt nen Bier auf *plopp*
nämlich andere Bomben und SoftBlöcke.
Zuerst mal sollen andere Bomben zur Explosion gebracht werden.
Ich setze jedesmal, wenn ich eine Explosion erstelle (siehe vorigen WorklogEintrag) dem Field Explosion den flag True:
BlitzMax: [AUSKLAPPEN]
Map.Feld[xFeld,yFeld].Explosion = True
nun muss ich einfach in der Update() Methode von TBombe.bmx jedesmal prüfen, ob das Feld, auf dem die Bombe liegt im Field Explosion den wert True hat, ist dem so, so lasse ich die Bombe Explodieren:
BlitzMax: [AUSKLAPPEN]
Method Update()
If MilliSecs() > BombenTimer+BombenIntervall
BombenCountDown:-1 'Intervall erreicht, CountDown um 1 verringern
BombenTimer=MilliSecs()
If BombenFrame < BOMBENFRAMES-1
BombenFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
End If
End If
If Map.Feld[xFeld,yFeld].Explosion = True 'Explosion auf Feld
BombenCountDown = 0 'Bombe zur Explosion bringen
End If
If BombenCountDown <=0 'CountDown ist abgelaufen *BOOOM*
BombenListe.Remove(Self) 'Bombe aus Liste löschen
Map.Feld[xFeld,yFeld].Inhalt = NIX 'wichtig! Inhalt des Feldes auf NIX zurück setzen
TExplosion.Erstellen(xFeld,yFeld,FeuerKraft) 'Explosion wird erstellt
End If
End Method
und schon entzünden Explosionen andere Bomben
Anmerkung von mir: auf diese Weise prüfe ich später auch, ob ein Spieler in einer Explosion steht
Nun will ich auch, dass eine Explosion, die auf eine Bombe trifft, sich nicht weiter fortpflanzt:
Ich weise jedesmal, wenn ich eine Bombe lege (siehe vorigen WorklogEintrag) dem Inhalt des Feldes den Wert der Konstante BOMBE zu:
BlitzMax: [AUSKLAPPEN]
Map.Feld[xFeld,yFeld].Inhalt = BOMBE
Somit muss ich also nur rausfinden, ob der Inhalt des Feldes, auf dem ich eine neue Explosion erstelle den Wert der Konstante BOMBE beträgt:
BlitzMax: [AUSKLAPPEN]
If Map.Feld[xFeld,yFeld].Inhalt = BOMBE Then
ist das der Fall, soll die FeuerKraft auf 0 gesetzt werden, damit sich die Explosion nicht weiter ausbreitet.
Das Ganze kommt nun mit in die Erstellen Funktion von TExplosion:
BlitzMax: [AUSKLAPPEN]
Function Erstellen:TExplosion(xFeld:Int,yFeld:Int,FeuerKraft:Int,ExplosionsRichtung:Int=ALLE)
Local NeueExplosion:TExplosion = New TExplosion
NeueExplosion.xFeld=xFeld 'Koordinaten der neuen Explosion übergeben
NeueExplosion.yFeld=yFeld
If Map.Feld[xFeld,yFeld].Inhalt = BOMBE 'wenn Bombe auf Feld
FeuerKraft=0 'auf 0 setzen, Explosion soll sich nicht weiter fortpflanzen
Else
NeueExplosion.FeuerKraft=FeuerKraft 'ansonsten Feuerkraft und
NeueExplosion.ExplosionsRichtung=ExplosionsRichtung 'Richtung in die sie sich "fortpflanzt" übergeben
End If
Map.Feld[xFeld,yFeld].Explosion = True 'wichtig! Inhalt des Feldes auf true setzen
ExplosionsListe.AddLast(NeueExplosion) 'neue Bombe der globalen BombenListe hinzufügen
End Function
Das war einfacher, als ich anfangs dachte
Jetzt lassen sich Kettenreaktionen auslösen
so, nun gehts den SoftBlöcken an den Kragen.
Da die Map z.Z. keine Softblöcke enthält (hatte den Wert auf 0 gesetzt, damit ich die Bewegung besser testen konnte), werd ich nun wieder ein paar einfügen. Dazu einfach die Erstellen Funktion von TKarte.bmx bearbeiten:
BlitzMax: [AUSKLAPPEN]
'#############################################
'# MAP MIT 100 SOFTBLÖCKEN FÜLLEN #
'# DABEI SPIELER-STARTECKEN FREI LASSEN #
'#############################################
Local BlockZahl:Int = 50 '100 Softblöcke sollen gesetzt werden
ich lasse nun einfach mal 50 zufällige Softblöcke erstellen.
Ich muss nun einfach nur prüfen, ob der inhalt des Feldes ein softblock ist, dann die Fortpflanzung der Explosion stoppen und den Inhalt des Feldes auf NIX setzen:
BlitzMax: [AUSKLAPPEN]
If Map.Feld[xFeld,yFeld].Inhalt = SBLOCK 'wenn SoftBlock auf Feld
FeuerKraft=0 'auf 0 setzen, Explosion soll sich nicht weiter fortpflanzen
Map.Feld[xFeld,yFeld].Inhalt = NIX
End If
Das ganze kommt in die Update() Methode der TExplosion.bmx und zwar ganz am Anfang (es soll ja die Fortpflanzung verhindert werden):
BlitzMax: [AUSKLAPPEN]
Method Update()
If Map.Feld[xFeld,yFeld].Inhalt = SBLOCK 'wenn SoftBlock auf Feld
FeuerKraft=0 'auf 0 setzen, Explosion soll sich nicht weiter fortpflanzen
Map.Feld[xFeld,yFeld].Inhalt = NIX
End If
If MilliSecs() > ExplosionsTimer+ExplosionsIntervall
ExplosionsTimer=MilliSecs()
If Feuerkraft > 0
FeuerKraft:-1 'um 1 reduzieren, damit korrekter Wert an nächste Explosion gegeben wird
If ExplosionsRichtung = OBEN Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld,yFeld-1].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld,yFeld-1,FeuerKraft,OBEN) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = UNTEN Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld,yFeld+1].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld,yFeld+1,FeuerKraft,UNTEN) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = LINKS Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld-1,yFeld].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld-1,yFeld,FeuerKraft,LINKS) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = RECHTS Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld+1,yFeld].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld+1,yFeld,FeuerKraft,RECHTS) 'neue Explosion in Richtung
End If
End If
FeuerKraft=0 'auf 0 setzen, damit keine endlos Fortpflanzung entsteht
End If
If ExplosionsFrame < EXPLOFRAMES-1
ExplosionsFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
Else 'wenn max Explosionsframes erreicht sind, Explosion löschen
ExplosionsListe.Remove(Self) 'Explosion aus Liste löschen
Map.Feld[xFeld,yFeld].Explosion = False 'Wichtig! Feld auf false setzen
End If
End If
End Method
Jetzt wird bei einer Explosion auf einem Softblock der Inhalt auf NIX gesetzt, und man kann durchlaufen... der Block bleibt aber weiterhin sichtbar. Das liegt daran, das der Inhalt des Feldes nichts mit dessen Grafik zu tun hat. Eine Update() Methode in TFeld.bmx schafft da abhilfe:
BlitzMax: [AUSKLAPPEN]
Method Update()
If Inhalt = NIX And BlockTile > 0'wenn NIX im Feld aber ein BlockTile da ist
BlockTile = 0 'BlockTile löschen
End If
End Method
so... diese Update() Methode rufe ich in der Zeichnen() Methode von TKarte.bmx auf:
BlitzMax: [AUSKLAPPEN]
Method Zeichnen()
For Local Y:Int=1 To MX
For Local X:Int=1 To MY
Feld[X,Y].Update() 'Aktuelles Feld auf Richtigkeit prüfen
Feld[X,Y].Zeichnen(X,Y) 'Übergibt X und Y Werte an Feld.Zeichnen
Next
Next
End Method
und schon werden Felder, welche den Inhalt NIX haben, aber dennoch BlockTiles besitzen korrigiert. Die Update() Methode von TFeld werde ich später noch für andere Sachen benutzen
Noch einen WICHTIGE Fehlerkorrektur:
Ich habe grade gemerkt, das es möglich ist, das ein Feld den Status Explosion = True zu früh verlieren kann, wenn sich Explosionen auf einem Feld überschneiden. Um das zu umgehen, setze ich den Status am Anfang der Update() Methode von TExplosion immer wieder erneut auf True!!!:
BlitzMax: [AUSKLAPPEN]
Method Update()
Map.Feld[xFeld,yFeld].Explosion = True 'muss immer erneut gesetzt werden, da überschneidende
'Explosionen den Status zu früh aufheben können
If Map.Feld[xFeld,yFeld].Inhalt = SBLOCK 'wenn SoftBlock auf Feld
FeuerKraft=0 'auf 0 setzen, Explosion soll sich nicht weiter fortpflanzen
Map.Feld[xFeld,yFeld].Inhalt = NIX
End If
If MilliSecs() > ExplosionsTimer+ExplosionsIntervall
ExplosionsTimer=MilliSecs()
If Feuerkraft > 0
FeuerKraft:-1 'um 1 reduzieren, damit korrekter Wert an nächste Explosion gegeben wird
If ExplosionsRichtung = OBEN Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld,yFeld-1].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld,yFeld-1,FeuerKraft,OBEN) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = UNTEN Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld,yFeld+1].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld,yFeld+1,FeuerKraft,UNTEN) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = LINKS Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld-1,yFeld].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld-1,yFeld,FeuerKraft,LINKS) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = RECHTS Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld+1,yFeld].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld+1,yFeld,FeuerKraft,RECHTS) 'neue Explosion in Richtung
End If
End If
FeuerKraft=0 'auf 0 setzen, damit keine endlos Fortpflanzung entsteht
End If
If ExplosionsFrame < EXPLOFRAMES-1
ExplosionsFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
Else 'wenn max Explosionsframes erreicht sind, Explosion löschen
ExplosionsListe.Remove(Self) 'Explosion aus Liste löschen
Map.Feld[xFeld,yFeld].Explosion = False 'Wichtig! Feld auf false setzen
End If
End If
End Method
Ausserdem kann nun endlich mal das DrawRect weg, welches mir visuell anzeigt, auf welchem Feld sich der Spieler grad befindet. Dazu kommentiere ich den Befehl einfach erstmal aus (vielleicht brauche ich es ja später nocheinmal) das erledige ich dann in der Zeichnen() Methode von TSpieler:
BlitzMax: [AUSKLAPPEN]
Method Zeichnen()
'DrawRect (xFeld*TS,yFeld*TS,TS,TS) 'Erstmal auskommentiert... vorerst klappt ja alles
DrawImage (SpielerIMG,xPos,yPos,0)
End Method
Download (Code und .EXE) bis hier hin:
https://www.blitzforum.de/upload/file.php?id=9438
Nun werden Softblöcke gesprengt... andere Bomben zur Explosion gebracht und mich bringt es nun zu der Überlegung:
ITEMS
wie machen? Hardcode oder durch script?
Jetzt brauch ich ein bissel Hilfe... Hardcoded wäre das alles kein Problem... aber, da ich ja auch was lernen will, würde ich diese gerne per Script oder sonstiges (externe Datei) ins Spiel bringen.
Welche Möglichkeiten wären sinnvoll???
Gibt es ein tolles Tutorial (englisch oder deutsch ist egal) oder hat da jemand ne tolle Anregung?
Hoffe in der Richtung auf zahlreiche Kommentare und Anregungen... und natürlich dürft ihr mir wie immer auf die Finger hauen, wenn ich bisher mist gebaut habe...
Ich bedanke mich schonmal und mach mir jetzt nen Bier auf *plopp*
Die Bombe tickt
Mittwoch, 1. September 2010 von KirkZero
Lasst mich endlich Bomben legen
Vorerst soll dies mittels der linken steuerungstaste (STRG) geschehen. Also Steuerungsmethode erweitert und da ich dort auch die Methode BombeLegen() aufrufe... ist diese auch gleich mit dabei:
BlitzMax: [AUSKLAPPEN]
Noch passiert nix, da die Methode BombeLegen nicht wirklich etwas macht... es wird lediglich abgefragt, ob das aktuelle Feld leer ist. Sollte dies der Fall sein, soll eine neue Bombe gelegt werden.
Also neue Datei angelegt: TBombe.bmx
BlitzMax: [AUSKLAPPEN]
im INCLUDES Ordner speichern und in der MainGame.bmx per include einbinden:
BlitzMax: [AUSKLAPPEN]
nun fülle ich TBombe.bmx mit ein wenig Zeugs
BlitzMax: [AUSKLAPPEN]
-eine Konstante für die Anzahl der Frames die die Grafik der Bombe hat
-die Grafik der Bombe wird geladen (global)
-ich erstelle eine globale TList, in der alle neu erstellten Bomben gespeichert werden
-natürlich benötigt jede Bombe ihre Koordinaten
Grafik der Bombe:
dann noch die Zeichnen() Methode, wie bei allen anderen Klassen auch und natürlich die Erstellen() Funktion, in der ich eine neue Bombe erstelle, die Koordinaten übergebe und sie in die TList einfüge.
Dabei ist auch wichtig, Map.Feld[xFeld,yFeld].Inhalt auf eine Bombe zu setzen.
Aufgerufen wird die Erstellen() Funktion in TSpieler.bmx in der Methode BombeLegen():
BlitzMax: [AUSKLAPPEN]
nun noch in der MainGame.bmx eine Schleife eingefügt, welche jede Bombe der TList durchgeht und diese dann zeichnet:
BlitzMax: [AUSKLAPPEN]
und schon kann man, wenn man das Programm startet, lustig Bomben auf dem Spielfeld legen.
(Da der Inhalt der Map auf Bombe gesetzt wird, sobald man eine legt, kann man nun auch nicht mehr über solche Felder drüber laufen, sobald man sie, nach dem legen, komplett verlassen hat)
Mehr passiert aber noch nicht.
Jetzt soll die Bombe nach 3 Sekunden einfach verschwinden. Ein Paar zusätliche Fields und eine Update() Methode sollen das für mich erledigen:
BlitzMax: [AUSKLAPPEN]
Denke mal, die Kommentare im Code sollten genügen... ansonsten fragen
Update() Methode in die MainGame.bmx eingefügt:
BlitzMax: [AUSKLAPPEN]
und schon verschwinden die gelegten Bomben nach 3 Sekunden wieder.
Ist aber laaaangweilig... will Explosionen...
Also, neue Datei erstellt. TExplosion.bmx:
BlitzMax: [AUSKLAPPEN]
im Verzeichnis INCLUDES speichern und in der MainGame.bmx per Include einbinden:
BlitzMax: [AUSKLAPPEN]
Da ja jeder Spieler später Items einsammeln kann, welche die Feuerkraft erhöhen, und diese für Bomben sowie für die Explosion wichtig ist, führen wir die nun schonmal ein. Das neue Feld nenne ich passenderweise mal FeuerKraft
Zuerst für den Spieler in TSpieler.bmx
BlitzMax: [AUSKLAPPEN]
Der wert soll an jede gelegte Bombe übergeben werden, somit brauchen wir das Feld auch in der TBombe.bmx:
BlitzMax: [AUSKLAPPEN]
und nun muss ich den Wert beim legen einer Bombe natürlich auch an die Bombe übergeben. Also erstellen Funktion in TBombe.bmx angepasst:
BlitzMax: [AUSKLAPPEN]
und den Aufruf der Funktion in TSpieler ebenfalls anpassen:
BlitzMax: [AUSKLAPPEN]
nun wird die FeuerKraft des Spielers an die Bomben die er legt weitergegeben *freu*
nun auf zur Explosion!!! erstmal die verwendete Grafik:
Diese gehört natürlich in den Ordner GFX und nennt sich Explosion.png
so, jetzt ab zur TExplosion.bmx. Diese ähnelt der TBombe.bmx sehr ich denke, das ich dann dazu erstmal nichts weiter sagen muss:
BlitzMax: [AUSKLAPPEN]
jetzt noch die passende Update() Methode um die Frames zu aktualisieren und die Explosion zu löschen, sobald sie zu ende ist:
BlitzMax: [AUSKLAPPEN]
WICHTIG:
Map.Feld[xFeld,yFeld].Explosion
ist ein neues Field in der TFeld.bmx, dieses hatte ich dort bisher immer auskommentiert, da ich es nun aber benutze, ändere ich das schnell noch:
BlitzMax: [AUSKLAPPEN]
so... nun muss nur noch eine Explosion erstellt werden, sobald die gelegte Bombe sich nach 3 Sekunden auflöst
Das erledige ich in der Update() Methode von TBombe.bmx:
BlitzMax: [AUSKLAPPEN]
So, damit man das Ganze nun auch sehen kann... müssen die Update() und Zeichnen() Methoden noch in die Hauptschleife der MainGame.bmx eingefügt werden:
BlitzMax: [AUSKLAPPEN]
und schon gibts ne tolle Explosion, nachdem die Bombe verschwindet. Jedoch berücksichtige ich momentan die Feuerkraft noch nicht. Die Explosion soll sich in benachbarte Felder "fortpflanzen" das erledige ich in der Update() Methode von TExplosion, aber erstmal brauche ich ein neues Field und wieder ein paar Konstanten um mir den Umgang mit Zahlen zu ersparen (TExplosion.bmx):
BlitzMax: [AUSKLAPPEN]
FeuerKraft ist klar.... das hatte ich schon. Neu ist
Field ExplosionsRichtung :Int hier wird gespeichert, in welche Richtung sich die aktuelle Explosion "fortpflanzt" und die Konstanten geben dabei die Richtung an.
ALLE wird nur beim erstellen einer Bombe benutzt, da sich die erste Explosion in alle Richtungen "fortpflanzen muss"
Dazu passe ich kurz noch die Erstellen Funktion der TExplosion.bmx an, damit ich die ExplosionsRichtung an die NeueExplosion übergeben kann:
BlitzMax: [AUSKLAPPEN]
Wird die Erstellen Funktion ohne den Parameter ExplosionsRichtung aufgerufen, so ist dieser automatisch auf ALLE gesetzt (ist praktisch, denn ich brauche jetzt den Aufruf der Funktion, in TBombe.bmx nicht bearbeiten)
Jetzt ist alles fürs "Fortpflanzen" soweit vorbereitet. Hier nun die Fortpflanzung in der Update() Methode der TExplosion.bmx:
BlitzMax: [AUSKLAPPEN]
BlitzMax: [AUSKLAPPEN]
Kurz erklärt:
Wenn die ExplosionsRichtung nach OBEN oder in ALLE Richtungen gehen soll, dann wird eine neue Explosion ein yFeld weiter oben, mit um 1 reduzierter FeuerKraft (da vor der IF Abfrage FeuerKraft:-1) erstellt, welche sich weiterhin nach OBEN fortpflanzen soll.
Und schon hab ich schöne Explosionen in der Größe der FeuerKraft
Wie man sieht, gehen diese Explosionen noch durch alle Wände durch... aber das behebe ich mal kurz. Es müssen in der Update() Methode lediglich noch ein paar IF Abfragen:
BlitzMax: [AUSKLAPPEN]
ab jetzt werden die Explosionen von HardBlöcken gestoppt
Im nächsten Eintrag sollen die Explosionen dann SoftBlöcke zerstören und andere Bomben zur Explosion bringen... und es gilt wie immer:
Ich würde mich übelst über positive wie auch negative Kritik und Verbesserungsvorschläge freuen, Danke
Download (Code und .EXE) bis hier hin:
https://www.blitzforum.de/upload/file.php?id=9431
Danke fürs lesen
Vorerst soll dies mittels der linken steuerungstaste (STRG) geschehen. Also Steuerungsmethode erweitert und da ich dort auch die Methode BombeLegen() aufrufe... ist diese auch gleich mit dabei:
BlitzMax: [AUSKLAPPEN]
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Bewegung wieder erlaubt (Zeit)
If KeyDown(KEY_UP) And MilliSecs() 'wenn Pfeiltaste OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(KEY_DOWN) And MilliSecs() 'wenn Pfeiltaste UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(KEY_LEFT) And MilliSecs() 'wenn Pfeiltaste LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() 'wenn Pfeiltaste RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End If
If KeyHit(KEY_LCONTROL) 'wenn linke STRG Taste gedrückt wird
BombeLegen() 'dann Methode zum Bombenlegen aufrufen
End If
End Method
Method BombeLegen()
If Map.Feld[xFeld,yFeld].Inhalt = NIX 'wenn aktuelles Feld leer ist
End If
End Method
Noch passiert nix, da die Methode BombeLegen nicht wirklich etwas macht... es wird lediglich abgefragt, ob das aktuelle Feld leer ist. Sollte dies der Fall sein, soll eine neue Bombe gelegt werden.
Also neue Datei angelegt: TBombe.bmx
BlitzMax: [AUSKLAPPEN]
Type TBombe
End Type
im INCLUDES Ordner speichern und in der MainGame.bmx per include einbinden:
BlitzMax: [AUSKLAPPEN]
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
Include "INCLUDES/TBombe.bmx"
nun fülle ich TBombe.bmx mit ein wenig Zeugs
BlitzMax: [AUSKLAPPEN]
Type TBombe
Const BOMBENFRAMES :Int=3 'Anzahl der Frames der BombenGrafik
Global BombenIMG :TImage = LoadAnimImage("gfx/bombe.png",TS,TS,0,BOMBENFRAMES)
Global BombenListe:TList = CreateList() 'eine globale Liste für alle Bomben anlegen
Field xFeld :Int 'Koordinaten der Bombe auf dem Feld
Field yFeld :Int
Method Zeichnen()
DrawImage (BombenIMG,xFeld*TS,yFeld*TS,0)
End Method
Function Erstellen:TBombe(xFeld:Int,yFeld:Int) 'neue Bombe wird erstellt
Local NeueBombe:TBombe = New TBombe
NeueBombe.xFeld=xFeld 'Koordinaten der neuen Bombe übergeben
NeueBombe.yFeld=yFeld
Map.Feld[xFeld,yFeld].Inhalt = BOMBE 'wichtig! Inhalt des Feldes auf Bombe setzen
BombenListe.AddLast(NeueBombe) 'neue Bombe der globalen BombenListe hinzufügen
End Function
End Type
-eine Konstante für die Anzahl der Frames die die Grafik der Bombe hat
-die Grafik der Bombe wird geladen (global)
-ich erstelle eine globale TList, in der alle neu erstellten Bomben gespeichert werden
-natürlich benötigt jede Bombe ihre Koordinaten
Grafik der Bombe:
dann noch die Zeichnen() Methode, wie bei allen anderen Klassen auch und natürlich die Erstellen() Funktion, in der ich eine neue Bombe erstelle, die Koordinaten übergebe und sie in die TList einfüge.
Dabei ist auch wichtig, Map.Feld[xFeld,yFeld].Inhalt auf eine Bombe zu setzen.
Aufgerufen wird die Erstellen() Funktion in TSpieler.bmx in der Methode BombeLegen():
BlitzMax: [AUSKLAPPEN]
Method BombeLegen()
If Map.Feld[xFeld,yFeld].Inhalt = NIX 'wenn aktuelles Feld leer ist
TBombe.Erstellen(xFeld,yFeld)
End If
End Method
nun noch in der MainGame.bmx eine Schleife eingefügt, welche jede Bombe der TList durchgeht und diese dann zeichnet:
BlitzMax: [AUSKLAPPEN]
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
Spieler1.Zeichnen()
Spieler1.Steuerung()
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Zeichnen()
Next
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts im Fenster gedrückt wird
End
und schon kann man, wenn man das Programm startet, lustig Bomben auf dem Spielfeld legen.
(Da der Inhalt der Map auf Bombe gesetzt wird, sobald man eine legt, kann man nun auch nicht mehr über solche Felder drüber laufen, sobald man sie, nach dem legen, komplett verlassen hat)
Mehr passiert aber noch nicht.
Jetzt soll die Bombe nach 3 Sekunden einfach verschwinden. Ein Paar zusätliche Fields und eine Update() Methode sollen das für mich erledigen:
BlitzMax: [AUSKLAPPEN]
Type TBombe
Const BOMBENFRAMES :Int=3 'Anzahl der Frames der BombenGrafik
Global BombenIMG :TImage = LoadAnimImage("gfx/bombe.png",TS,TS,0,BOMBENFRAMES)
Global BombenListe:TList = CreateList() 'eine globale Liste für alle Bomben anlegen
Field xFeld :Int 'Koordinaten der Bombe auf dem Feld
Field yFeld :Int
Field BombenFrame :Int = 0 'Aktuelles Frame der BombenGrafik (0=erstes Frame)
Field BombenCountDown :Int = 3 'jede Bombe soll nach 3 Sekunden (oder Intervallen) explodieren
Field BombenIntervall :Int = 1000 'der Intervall mit dem runtergezählt wird (1000 = 1 Sekunde)
Field BombenTimer :Int = MilliSecs() 'aktuelle Zeit setzen
Method Update()
If MilliSecs() > BombenTimer+BombenIntervall
BombenCountDown:-1 'Intervall erreicht, CountDown um 1 verringern
BombenTimer=MilliSecs()
If BombenFrame < BOMBENFRAMES-1
BombenFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
End If
End If
If BombenCountDown=0 'CountDown ist abgelaufen *BOOOM*
BombenListe.Remove(Self) 'Bombe aus Liste löschen
Map.Feld[xFeld,yFeld].Inhalt = NIX 'wichtig! Inhalt des Feldes auf NIX zurück setzen
End If
End Method
Method Zeichnen()
DrawImage (BombenIMG,xFeld*TS,yFeld*TS,BombenFrame)
End Method
Function Erstellen:TBombe(xFeld:Int,yFeld:Int) 'neue Bombe wird erstellt
Local NeueBombe:TBombe = New TBombe
NeueBombe.xFeld=xFeld 'Koordinaten der neuen Bombe übergeben
NeueBombe.yFeld=yFeld
Map.Feld[xFeld,yFeld].Inhalt = BOMBE 'wichtig! Inhalt des Feldes auf Bombe setzen
BombenListe.AddLast(NeueBombe) 'neue Bombe der globalen BombenListe hinzufügen
End Function
End Type
Denke mal, die Kommentare im Code sollten genügen... ansonsten fragen
Update() Methode in die MainGame.bmx eingefügt:
BlitzMax: [AUSKLAPPEN]
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
Spieler1.Zeichnen()
Spieler1.Steuerung()
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Update()
Bombe.Zeichnen()
Next
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts im Fenster gedrückt wird
End
und schon verschwinden die gelegten Bomben nach 3 Sekunden wieder.
Ist aber laaaangweilig... will Explosionen...
Also, neue Datei erstellt. TExplosion.bmx:
BlitzMax: [AUSKLAPPEN]
Type TExplosion
End Type
im Verzeichnis INCLUDES speichern und in der MainGame.bmx per Include einbinden:
BlitzMax: [AUSKLAPPEN]
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
Include "INCLUDES/TBombe.bmx"
Include "INCLUDES/TExplosion.bmx"
Da ja jeder Spieler später Items einsammeln kann, welche die Feuerkraft erhöhen, und diese für Bomben sowie für die Explosion wichtig ist, führen wir die nun schonmal ein. Das neue Feld nenne ich passenderweise mal FeuerKraft
Zuerst für den Spieler in TSpieler.bmx
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 xPos :Int 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Int
Field Speed :Int = 2 'man bewegt sich immer um 2 Pixel pro Bewegung
Field FeuerKraft :Int = 2 'Reichweite der Explosionen einer Bombe (2 Felder in alle Richtungen)
Der wert soll an jede gelegte Bombe übergeben werden, somit brauchen wir das Feld auch in der TBombe.bmx:
BlitzMax: [AUSKLAPPEN]
Type TBombe
Const BOMBENFRAMES :Int=3 'Anzahl der Frames der BombenGrafik
Global BombenIMG :TImage = LoadAnimImage("gfx/bombe.png",TS,TS,0,BOMBENFRAMES)
Global BombenListe :TList = CreateList() 'eine globale Liste für alle Bomben anlegen
Field xFeld :Int 'Koordinaten der Bombe auf dem Feld
Field yFeld :Int
Field FeuerKraft :Int 'Reichweite der Explosionen einer Bombe
und nun muss ich den Wert beim legen einer Bombe natürlich auch an die Bombe übergeben. Also erstellen Funktion in TBombe.bmx angepasst:
BlitzMax: [AUSKLAPPEN]
Function Erstellen:TBombe(xFeld:Int,yFeld:Int,FeuerKraft:Int) 'neue Bombe wird erstellt
Local NeueBombe:TBombe = New TBombe
NeueBombe.xFeld=xFeld 'Koordinaten der neuen Bombe übergeben
NeueBombe.yFeld=yFeld
NeueBombe.FeuerKraft=FeuerKraft
Map.Feld[xFeld,yFeld].Inhalt = BOMBE 'wichtig! Inhalt des Feldes auf Bombe setzen
BombenListe.AddLast(NeueBombe) 'neue Bombe der globalen BombenListe hinzufügen
End Function
und den Aufruf der Funktion in TSpieler ebenfalls anpassen:
BlitzMax: [AUSKLAPPEN]
Method BombeLegen()
If Map.Feld[xFeld,yFeld].Inhalt = NIX 'wenn aktuelles Feld leer ist
TBombe.Erstellen(xFeld,yFeld,FeuerKraft)
End If
End Method
nun wird die FeuerKraft des Spielers an die Bomben die er legt weitergegeben *freu*
nun auf zur Explosion!!! erstmal die verwendete Grafik:
Diese gehört natürlich in den Ordner GFX und nennt sich Explosion.png
so, jetzt ab zur TExplosion.bmx. Diese ähnelt der TBombe.bmx sehr ich denke, das ich dann dazu erstmal nichts weiter sagen muss:
BlitzMax: [AUSKLAPPEN]
Type TExplosion
Const EXPLOFRAMES :Int=49 'Anzahl der Frames der ExplosionsGrafik
Global ExplosionsIMG :TImage = LoadAnimImage("gfx/explosion.png",TS,TS,0,EXPLOFRAMES)
Global ExplosionsListe :TList = CreateList() 'eine globale Liste für alle Explosionen anlegen
Field xFeld :Int 'Koordinaten der Explosion auf dem Feld
Field yFeld :Int
Field FeuerKraft :Int 'Reichweite der Explosionen
Field ExplosionsFrame :Int = 0 'Aktuelles Frame der ExplosionsGrafik (0=erstes Frame)
Field ExplosionsIntervall:Int = 25 'der Intervall mit dem die Frames gewechselt werden
Field ExplosionsTimer :Int = MilliSecs() 'aktuelle Zeit setzen
Method Zeichnen()
DrawImage (ExplosionsIMG,xFeld*TS,yFeld*TS,ExplosionsFrame)
End Method
Function Erstellen:TExplosion(xFeld:Int,yFeld:Int,FeuerKraft:Int) 'neue Explosion wird erstellt
Local NeueExplosion:TExplosion = New TExplosion
NeueExplosion.xFeld=xFeld 'Koordinaten der neuen Explosion übergeben
NeueExplosion.yFeld=yFeld
NeueExplosion.FeuerKraft=FeuerKraft
Map.Feld[xFeld,yFeld].Explosion = True 'wichtig! Inhalt des Feldes auf true setzen
ExplosionsListe.AddLast(NeueExplosion) 'neue Bombe der globalen BombenListe hinzufügen
End Function
End Type
jetzt noch die passende Update() Methode um die Frames zu aktualisieren und die Explosion zu löschen, sobald sie zu ende ist:
BlitzMax: [AUSKLAPPEN]
Method Update()
If MilliSecs() > ExplosionsTimer+ExplosionsIntervall
ExplosionsTimer=MilliSecs()
If ExplosionsFrame < EXPLOFRAMES-1
ExplosionsFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
Else 'wenn max Explosionsframes erreicht sind, Explosion löschen
ExplosionsListe.Remove(Self) 'Explosion aus Liste löschen
Map.Feld[xFeld,yFeld].Explosion = False 'Wichtig! Feld auf false setzen
End If
End If
End Method
WICHTIG:
Map.Feld[xFeld,yFeld].Explosion
ist ein neues Field in der TFeld.bmx, dieses hatte ich dort bisher immer auskommentiert, da ich es nun aber benutze, ändere ich das schnell noch:
BlitzMax: [AUSKLAPPEN]
Type TFeld
Const BODENFRAMES :Int=5
Const BLOCKFRAMES :Int=3
Global BodenTilesIMG :TImage = LoadAnimImage("gfx/boden.png",TS,TS,0,BODENFRAMES)
Global BlockTilesIMG :TImage = LoadAnimImage("gfx/block.png",TS,TS,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, 5=Bombe, 10=unzerstöbar/unpassierbar
Field Explosion :Int 'wird auf true gesetzt, solange eine Explosion auf dem Feld ist
so... nun muss nur noch eine Explosion erstellt werden, sobald die gelegte Bombe sich nach 3 Sekunden auflöst
Das erledige ich in der Update() Methode von TBombe.bmx:
BlitzMax: [AUSKLAPPEN]
Method Update()
If MilliSecs() > BombenTimer+BombenIntervall
BombenCountDown:-1 'Intervall erreicht, CountDown um 1 verringern
BombenTimer=MilliSecs()
If BombenFrame < BOMBENFRAMES-1
BombenFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
End If
End If
If BombenCountDown=0 'CountDown ist abgelaufen *BOOOM*
BombenListe.Remove(Self) 'Bombe aus Liste löschen
Map.Feld[xFeld,yFeld].Inhalt = NIX 'wichtig! Inhalt des Feldes auf NIX zurück setzen
TExplosion.Erstellen(xFeld,yFeld,FeuerKraft) 'Explosion wird erstellt
End If
So, damit man das Ganze nun auch sehen kann... müssen die Update() und Zeichnen() Methoden noch in die Hauptschleife der MainGame.bmx eingefügt werden:
BlitzMax: [AUSKLAPPEN]
Repeat
Cls 'Backbuffer löschen
Map.Zeichnen() 'die Zeichen Methode von Map wird ausgeführt
Spieler1.Zeichnen()
Spieler1.Steuerung()
For Local Bombe:TBombe = EachIn TBombe.BombenListe 'jede erstellte Bombe durchgehen
Bombe.Update()
Bombe.Zeichnen()
Next
For Local Explosion:TExplosion = EachIn TExplosion.ExplosionsListe 'jede erstellte Explosion durchgehen
Explosion.Update()
Explosion.Zeichnen()
Next
WaitTimer (Frames) 'da Frames=120 wird die Hauptschleife 60 mal pro Sekunde durchlaufen
Flip (0) 'Backbuffer wird sichtbar (0)=kein VSync
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts im Fenster gedrückt wird
End
und schon gibts ne tolle Explosion, nachdem die Bombe verschwindet. Jedoch berücksichtige ich momentan die Feuerkraft noch nicht. Die Explosion soll sich in benachbarte Felder "fortpflanzen" das erledige ich in der Update() Methode von TExplosion, aber erstmal brauche ich ein neues Field und wieder ein paar Konstanten um mir den Umgang mit Zahlen zu ersparen (TExplosion.bmx):
BlitzMax: [AUSKLAPPEN]
Field FeuerKraft :Int 'Reichweite der Explosionen
Field ExplosionsRichtung :Int 'Richtung, in die Explosion sich "fortpflanzt"
Const OBEN :Int = 0 'nur wieder um nicht mit Zahlen
Const UNTEN :Int = 1 'hantieren zu müssen
Const LINKS :Int = 2
Const RECHTS :Int = 3
Const ALLE :Int = 5
FeuerKraft ist klar.... das hatte ich schon. Neu ist
Field ExplosionsRichtung :Int hier wird gespeichert, in welche Richtung sich die aktuelle Explosion "fortpflanzt" und die Konstanten geben dabei die Richtung an.
ALLE wird nur beim erstellen einer Bombe benutzt, da sich die erste Explosion in alle Richtungen "fortpflanzen muss"
Dazu passe ich kurz noch die Erstellen Funktion der TExplosion.bmx an, damit ich die ExplosionsRichtung an die NeueExplosion übergeben kann:
BlitzMax: [AUSKLAPPEN]
Function Erstellen:TExplosion(xFeld:Int,yFeld:Int,FeuerKraft:Int,ExplosionsRichtung:Int=ALLE) 'neue Explosion wird erstellt
Local NeueExplosion:TExplosion = New TExplosion
NeueExplosion.xFeld=xFeld 'Koordinaten der neuen Explosion übergeben
NeueExplosion.yFeld=yFeld
NeueExplosion.FeuerKraft=FeuerKraft 'Feuerkraft
NeueExplosion.ExplosionsRichtung=ExplosionsRichtung 'und Richtung in die sie sich "fortpflanzt"
Map.Feld[xFeld,yFeld].Explosion = True 'wichtig! Inhalt des Feldes auf true setzen
ExplosionsListe.AddLast(NeueExplosion) 'neue Bombe der globalen BombenListe hinzufügen
End Function
Wird die Erstellen Funktion ohne den Parameter ExplosionsRichtung aufgerufen, so ist dieser automatisch auf ALLE gesetzt (ist praktisch, denn ich brauche jetzt den Aufruf der Funktion, in TBombe.bmx nicht bearbeiten)
Jetzt ist alles fürs "Fortpflanzen" soweit vorbereitet. Hier nun die Fortpflanzung in der Update() Methode der TExplosion.bmx:
BlitzMax: [AUSKLAPPEN]
Method Update()
If MilliSecs() > ExplosionsTimer+ExplosionsIntervall
ExplosionsTimer=MilliSecs()
If Feuerkraft > 0
FeuerKraft:-1 'um 1 reduzieren, damit korrekter Wert an nächste Explosion gegeben wird
If ExplosionsRichtung = OBEN Or ExplosionsRichtung = ALLE
TExplosion.Erstellen(xFeld,yFeld-1,FeuerKraft,OBEN)
End If
If ExplosionsRichtung = UNTEN Or ExplosionsRichtung = ALLE
TExplosion.Erstellen(xFeld,yFeld+1,FeuerKraft,UNTEN)
End If
If ExplosionsRichtung = LINKS Or ExplosionsRichtung = ALLE
TExplosion.Erstellen(xFeld-1,yFeld,FeuerKraft,LINKS)
End If
If ExplosionsRichtung = RECHTS Or ExplosionsRichtung = ALLE
TExplosion.Erstellen(xFeld+1,yFeld,FeuerKraft,RECHTS)
End If
FeuerKraft=0 'auf 0 setzen, damit keine endlos Fortpflanzung entsteht
End If
If ExplosionsFrame < EXPLOFRAMES-1
ExplosionsFrame:+1 'Frame um 1 erhöhen, solange Anzahl an Frames der Grafik noch nicht erreicht
Else 'wenn max Explosionsframes erreicht sind, Explosion löschen
ExplosionsListe.Remove(Self) 'Explosion aus Liste löschen
Map.Feld[xFeld,yFeld].Explosion = False 'Wichtig! Feld auf false setzen
End If
End If
End Method
BlitzMax: [AUSKLAPPEN]
If ExplosionsRichtung = OBEN Or ExplosionsRichtung = ALLE
TExplosion.Erstellen(xFeld,yFeld-1,FeuerKraft,OBEN)
End If
Kurz erklärt:
Wenn die ExplosionsRichtung nach OBEN oder in ALLE Richtungen gehen soll, dann wird eine neue Explosion ein yFeld weiter oben, mit um 1 reduzierter FeuerKraft (da vor der IF Abfrage FeuerKraft:-1) erstellt, welche sich weiterhin nach OBEN fortpflanzen soll.
Und schon hab ich schöne Explosionen in der Größe der FeuerKraft
Wie man sieht, gehen diese Explosionen noch durch alle Wände durch... aber das behebe ich mal kurz. Es müssen in der Update() Methode lediglich noch ein paar IF Abfragen:
BlitzMax: [AUSKLAPPEN]
If ExplosionsRichtung = OBEN Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld,yFeld-1].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld,yFeld-1,FeuerKraft,OBEN) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = UNTEN Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld,yFeld+1].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld,yFeld+1,FeuerKraft,UNTEN) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = LINKS Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld-1,yFeld].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld-1,yFeld,FeuerKraft,LINKS) 'neue Explosion in Richtung
End If
End If
If ExplosionsRichtung = RECHTS Or ExplosionsRichtung = ALLE
If Map.Feld[xFeld+1,yFeld].Inhalt <> HBLOCK 'wenn in ExplosionsRichtung KEIN HardBlock
TExplosion.Erstellen(xFeld+1,yFeld,FeuerKraft,RECHTS) 'neue Explosion in Richtung
End If
End If
ab jetzt werden die Explosionen von HardBlöcken gestoppt
Im nächsten Eintrag sollen die Explosionen dann SoftBlöcke zerstören und andere Bomben zur Explosion bringen... und es gilt wie immer:
Ich würde mich übelst über positive wie auch negative Kritik und Verbesserungsvorschläge freuen, Danke
Download (Code und .EXE) bis hier hin:
https://www.blitzforum.de/upload/file.php?id=9431
Danke fürs lesen
Kollision mit der TileMap
Sonntag, 29. August 2010 von KirkZero
Bevor es nun an die Kollision mit der TileMap geht, erstmal noch eine kleine Verbesserung. Danke für den Hinweis @n-Halbleiter
Zitat:
Somit sieht die Steuerungs Methode nun so aus:
BlitzMax: [AUSKLAPPEN]
Jetzt gehts an die Kollision mit der TileMap
Ich beziehe mich hier immer auf die Datei TSpieler.bmx! Sollte das einmal nicht der Fall sein, so werde ich es ausdrücklich betonen
Ich habe im letzten Worklog mit der Methode MapFeld() berechnet, auf welchem Tile der Map ich mich eigentlich grade befinde. Wenn ich mich nun nach Oben bewegen will, muss ich prüfen, ob das Feld über mir überhaupt begehbar ist:
BlitzMax: [AUSKLAPPEN]
und das Gleiche natürlich für die anderen Richtungen:
BlitzMax: [AUSKLAPPEN]
Sobald man sich nun ein bissel hin und her bewegt, merkt man schnell... das ist wohl so noch nicht ganz richtig. Denn, sobald das Feld aktualisiert wird, wird bei einer weiteren Bewegung in der selben Richtung, gleich das nächste Feld abgefragt. Sollte dies dann jedoch nicht begehbar sein, kann man das aktuelle Feld nicht komplett betreten. (ohjeh... hab ich mal wieder blöd erklärt)
Man hängt also irgendwann fest.
Das Problem löse ich nun wieder mittels Mod:
BlitzMax: [AUSKLAPPEN]
Wer damit nun aber ein wenig rumspielt, wird bemerken, es sind immernoch fehlerhafte Bewegungen möglich. Bewegt man sich z.B. zu Beginn nur ein kleines Stück nach rechts und dann nach unten, so ist der Spieler ja zum Teil in einem unbegehbaren Block. Bewegt man sich dann nochmals nach rechts, kann man sogar einen unbegehbaren komplett betreten.
Ein Stück nach rechts bewegen:
Dann nach unten
und wenn man sich nun nach rechts bewegt, landet man komplett auf einem unbegehbarem Feld
Bevor ich mich allerdings diesem Problem widme, erweitere ich erstmal die Methode Bewegung() um 2 Lokale Variablen. Da ich nun auch dort mit Mod arbeite.
So schauts nun aus:
BlitzMax: [AUSKLAPPEN]
Und nun zu dem genannten Problem.
Sollte ich nun diese Position haben:
und ich bewege mich nun nach unten, so möchte ich, das der Spieler sich automatisch solange nach links bewegt, bis eine Bewegung nach unten möglich ist.
(Nach links deshalb, weil mein aktuelles Feld sich links vom Sprite befindet.)
Dazu prüfe ich ersteinmal, ob meine aktuelle Feldkoordinate (mit der Tilesize multipliziert) kleiner ist, als meine aktuelle Pixelkoordinate:
BlitzMax: [AUSKLAPPEN]
und nun das Ganze auch für den fall, das mein aktuelles Feld rechts von mir ist und ich mich dann automatisch nach rechts bewegen muss, bis ich genau in die lücke nach unten passe:
BlitzMax: [AUSKLAPPEN]
und nun für alle Richtungen:
BlitzMax: [AUSKLAPPEN]
Anmerkung von mir: um die Kommentare usw richtig eingerückt zu sehen, am besten den Code Kopieren und in die IDE einfügen... dann sollte es übersichtlicher sein.
EDIT ########## ##########
ich habe das ganze grad nochmal schön zusammengefasst... das spart Code und gibt wieder mehr Übersicht! *freu*
BlitzMax: [AUSKLAPPEN]
END EDIT ########## ##########
und hier die Komplette Spieler.bmx (ALT) ohne Zusammenfassung (siehe EDIT hier drüber):
BlitzMax: [AUSKLAPPEN]
und hier nochmal die komplette TSpieler.bmx mit der zusammengefassten Bewegungs Methode:
BlitzMax: [AUSKLAPPEN]
Um ein wenig auf der Map rumzulaufen, ohne die störenden Softblöcke (um das ganze einfach mal zu testen), kann man diese ganz einfach in der TKarte.bmx entfernen.
Einfach in der Erstellen Funktion die Variable BlockZahl auf 0 setzen:
BlitzMax: [AUSKLAPPEN]
dort bei
BlitzMax: [AUSKLAPPEN]
einfach 0 eintragen:
BlitzMax: [AUSKLAPPEN]
und die MainGame.bmx starten. Schon kann man die ganze Sache mit mehr Freiraum testen.
Diesmal gibt es wieder den kompletten Code bis hier hin (inklusive .EXE) zum Download:
https://www.blitzforum.de/upload/file.php?id=9412
Das war es dann erstmal zur Pixelweise Bewegung mit TileMap Kollision. Ich bedanke mich erneut fürs Lesen und es gilt wie immer:
Ich würde mich übelst über positive wie auch negative Kritik und Verbesserungsvorschläge freuen, Danke
Bein nächsten mal lege ich dann ne Bombe oder evtl. werd ich den Spieler ersteinmal animieren... oder beides... mal sehen *wink*
Zitat:
Deine Steuerungsmethode lässt sich schön beschleunigen (wenn auch nur minimal). Du musst das " And MilliSecs() > BewegungsTimer+BewegungsPause" bei jeder If-Abfrage entfernen und dann die gesamte If-Abfrage für die Tasten in eine Andere mit der Bedingung "MilliSecs() > BewegungsTimer+BewegungsPause" schachteln.
Die Methode würde damit wie folgt aussehen:
<code>
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause
If KeyDown(KEY_UP) 'wenn Pfeiltaste OBEN gedrückt wird
yPos:-Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_DOWN) 'wenn Pfeiltaste UNTEN gedrückt wird
yPos:+Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_LEFT) 'wenn Pfeiltaste LINKS gedrückt wird
xPos:-Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_RIGHT) 'wenn Pfeiltaste RECHTS gedrückt wird
xPos:+Speed
BewegungsTimer = MilliSecs()
End If
End If
End Method
</code>
Die Methode würde damit wie folgt aussehen:
<code>
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause
If KeyDown(KEY_UP) 'wenn Pfeiltaste OBEN gedrückt wird
yPos:-Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_DOWN) 'wenn Pfeiltaste UNTEN gedrückt wird
yPos:+Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_LEFT) 'wenn Pfeiltaste LINKS gedrückt wird
xPos:-Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_RIGHT) 'wenn Pfeiltaste RECHTS gedrückt wird
xPos:+Speed
BewegungsTimer = MilliSecs()
End If
End If
End Method
</code>
Somit sieht die Steuerungs Methode nun so aus:
BlitzMax: [AUSKLAPPEN]
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause
If KeyDown(KEY_UP) 'wenn Pfeiltaste OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(KEY_DOWN) 'wenn Pfeiltaste UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(KEY_LEFT) 'wenn Pfeiltaste LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(KEY_RIGHT) 'wenn Pfeiltaste RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End If
End Method
Jetzt gehts an die Kollision mit der TileMap
Ich beziehe mich hier immer auf die Datei TSpieler.bmx! Sollte das einmal nicht der Fall sein, so werde ich es ausdrücklich betonen
Ich habe im letzten Worklog mit der Methode MapFeld() berechnet, auf welchem Tile der Map ich mich eigentlich grade befinde. Wenn ich mich nun nach Oben bewegen will, muss ich prüfen, ob das Feld über mir überhaupt begehbar ist:
BlitzMax: [AUSKLAPPEN]
Method Bewegung(Richtung:Int)
Local x :Int ' Temporäre Speicher
Local y :Int
Select Richtung
Case OBEN
If Map.Feld[xFeld,yFeld-1].Inhalt = NIX 'wenn oben NIX ist, dann nach oben bewegen
y=-Speed
End If
und das Gleiche natürlich für die anderen Richtungen:
BlitzMax: [AUSKLAPPEN]
Method Bewegung(Richtung:Int)
Local x :Int ' Temporäre Speicher
Local y :Int
Select Richtung
Case OBEN
If Map.Feld[xFeld,yFeld-1].Inhalt = NIX 'wenn oben NIX ist, dann nach oben bewegen
y=-Speed
End If
Case UNTEN
If Map.Feld[xFeld,yFeld+1].Inhalt = NIX 'wenn unten NIX ist, dann nach unten bewegen
y=+Speed
End If
Case LINKS
If Map.Feld[xFeld-1,yFeld].Inhalt = NIX 'wenn links NIX ist, dann nach links bewegen
x=-Speed
End If
Case RECHTS
If Map.Feld[xFeld+1,yFeld].Inhalt = NIX 'wenn rechts NIX ist, dann nach rechts bewegen
x=+Speed
End If
End Select
yPos:+y 'Spieler Koordinaten aktualisieren
xPos:+x
MapFeld() 'Aktuelles Map.Feld[,] wird berechnet
BewegungsTimer = MilliSecs()
End Method
Sobald man sich nun ein bissel hin und her bewegt, merkt man schnell... das ist wohl so noch nicht ganz richtig. Denn, sobald das Feld aktualisiert wird, wird bei einer weiteren Bewegung in der selben Richtung, gleich das nächste Feld abgefragt. Sollte dies dann jedoch nicht begehbar sein, kann man das aktuelle Feld nicht komplett betreten. (ohjeh... hab ich mal wieder blöd erklärt)
Man hängt also irgendwann fest.
Das Problem löse ich nun wieder mittels Mod:
BlitzMax: [AUSKLAPPEN]
Method Bewegung(Richtung:Int)
Local x :Int ' Temporäre Speicher
Local y :Int
Select Richtung
Case OBEN
If Map.Feld[xFeld,yFeld-1].Inhalt = NIX 'wenn oben NIX ist, dann nach oben bewegen
y=-Speed
Else If (yPos Mod TS) <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=-Speed
End If
Case UNTEN
If Map.Feld[xFeld,yFeld+1].Inhalt = NIX 'wenn unten NIX ist, dann nach unten bewegen
y=+Speed
Else If (yPos Mod TS) <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=+Speed
End If
Case LINKS
If Map.Feld[xFeld-1,yFeld].Inhalt = NIX 'wenn links NIX ist, dann nach links bewegen
x=-Speed
Else If (xPos Mod TS) <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
x=-Speed
End If
Case RECHTS
If Map.Feld[xFeld+1,yFeld].Inhalt = NIX 'wenn rechts NIX ist, dann nach rechts bewegen
x=+Speed
Else If (xPos Mod TS) <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
x=+Speed
End If
End Select
yPos:+y 'Spieler Koordinaten aktualisieren
xPos:+x
MapFeld() 'Aktuelles Map.Feld[,] wird berechnet
BewegungsTimer = MilliSecs()
End Method
Wer damit nun aber ein wenig rumspielt, wird bemerken, es sind immernoch fehlerhafte Bewegungen möglich. Bewegt man sich z.B. zu Beginn nur ein kleines Stück nach rechts und dann nach unten, so ist der Spieler ja zum Teil in einem unbegehbaren Block. Bewegt man sich dann nochmals nach rechts, kann man sogar einen unbegehbaren komplett betreten.
Ein Stück nach rechts bewegen:
Dann nach unten
und wenn man sich nun nach rechts bewegt, landet man komplett auf einem unbegehbarem Feld
Bevor ich mich allerdings diesem Problem widme, erweitere ich erstmal die Methode Bewegung() um 2 Lokale Variablen. Da ich nun auch dort mit Mod arbeite.
So schauts nun aus:
BlitzMax: [AUSKLAPPEN]
Method Bewegung(Richtung:Int)
Local x :Int ' Temporäre Speicher
Local y :Int
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
Select Richtung
Case OBEN
If Map.Feld[xFeld,yFeld-1].Inhalt = NIX 'wenn oben NIX ist, dann nach oben bewegen
y=-Speed
Else If yMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=-Speed
End If
Case UNTEN
If Map.Feld[xFeld,yFeld+1].Inhalt = NIX 'wenn unten NIX ist, dann nach unten bewegen
y=+Speed
Else If yMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=+Speed
End If
Case LINKS
If Map.Feld[xFeld-1,yFeld].Inhalt = NIX 'wenn links NIX ist, dann nach links bewegen
x=-Speed
Else If xMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
x=-Speed
End If
Case RECHTS
If Map.Feld[xFeld+1,yFeld].Inhalt = NIX 'wenn rechts NIX ist, dann nach rechts bewegen
x=+Speed
Else If xMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
x=+Speed
End If
End Select
yPos:+y 'Spieler Koordinaten aktualisieren
xPos:+x
MapFeld() 'Aktuelles Map.Feld[,] wird berechnet
BewegungsTimer = MilliSecs()
Und nun zu dem genannten Problem.
Sollte ich nun diese Position haben:
und ich bewege mich nun nach unten, so möchte ich, das der Spieler sich automatisch solange nach links bewegt, bis eine Bewegung nach unten möglich ist.
(Nach links deshalb, weil mein aktuelles Feld sich links vom Sprite befindet.)
Dazu prüfe ich ersteinmal, ob meine aktuelle Feldkoordinate (mit der Tilesize multipliziert) kleiner ist, als meine aktuelle Pixelkoordinate:
BlitzMax: [AUSKLAPPEN]
Case UNTEN
If Map.Feld[xFeld,yFeld+1].Inhalt = NIX 'wenn unten NIX ist
If xFeld*TS < xPos 'ist (Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um "Speed" Pixel nach links bewegen
Else 'passt es genau, dann um "Speed" Pixel nach unten bewegen
y=+Speed
End If
Else If yMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=+Speed
End If
und nun das Ganze auch für den fall, das mein aktuelles Feld rechts von mir ist und ich mich dann automatisch nach rechts bewegen muss, bis ich genau in die lücke nach unten passe:
BlitzMax: [AUSKLAPPEN]
Case UNTEN
If Map.Feld[xFeld,yFeld+1].Inhalt = NIX 'wenn unten NIX ist
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else 'passt es genau, dann um Speed Pixel nach unten bewegen
y=+Speed
End If
Else If yMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=+Speed
End If
und nun für alle Richtungen:
BlitzMax: [AUSKLAPPEN]
Select Richtung
Case OBEN
If Map.Feld[xFeld,yFeld-1].Inhalt = NIX 'wenn oben NIX ist, nach oben bewegen
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else 'passt es genau, dann um Speed Pixel nach oben bewegen
y=-Speed
End If
Else If yMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=-Speed
End If
Case UNTEN
If Map.Feld[xFeld,yFeld+1].Inhalt = NIX 'wenn unten NIX ist
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else
y=+Speed 'passt es genau, dann um Speed Pixel nach unten bewegen
End If
Else If yMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=+Speed
End If
Case LINKS
If Map.Feld[xFeld-1,yFeld].Inhalt = NIX 'wenn links NIX ist, nach links bewegen
If yFeld*TS < yPos 'ist (Y Feldkoordinate*TS) kleiner als Pixelkoordinate
y=-Speed 'dann um Speed Pixel nach oben bewegen
Else If yFeld*TS > yPos 'ist (Y Feldkoordinate*TS) größer als Pixelkoordinate
y=+Speed 'dann um Speed Pixel nach unten bewegen
Else
x=-Speed 'passt es genau, dann um Speed Pixel nach links bewegen
End If
Else If xMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
x=-Speed
End If
Case RECHTS
If Map.Feld[xFeld+1,yFeld].Inhalt = NIX 'wenn rechts NIX ist, nach rechts bewegen
If yFeld*TS < yPos 'ist (Y Feldkoordinate*TS) kleiner als Pixelkoordinate
y=-Speed 'dann um Speed Pixel nach oben bewegen
Else If yFeld*TS > yPos 'ist (Y Feldkoordinate*TS) größer als Pixelkoordinate
y=+Speed 'dann um Speed Pixel nach unten bewegen
Else
x=+Speed 'passt es genau, dann um Speed Pixel nach rechts bewegen
End If
Else If xMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
x=+Speed
End If
End Select
Anmerkung von mir: um die Kommentare usw richtig eingerückt zu sehen, am besten den Code Kopieren und in die IDE einfügen... dann sollte es übersichtlicher sein.
EDIT ########## ##########
ich habe das ganze grad nochmal schön zusammengefasst... das spart Code und gibt wieder mehr Übersicht! *freu*
BlitzMax: [AUSKLAPPEN]
Method Bewegung(Richtung:Int)
Local x :Int 'Temporäre Speicher
Local y :Int
Local fx :Int 'Temporäre Speicher für zu prüfende Felder
Local fy :Int 'ist fy=-1 wird oberes vom aktuellen Feld geprüft
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
Select Richtung
Case OBEN
fy=-1 'oberes Feld prüfen
Case UNTEN
fy=+1 'unteres Feld prüfen
Case LINKS
fx=-1 'linkes Feld prüfen
Case RECHTS
fx=+1 'rechtes Feld prüfen
End Select
If Map.Feld[xFeld+fx,yFeld+fy].Inhalt = NIX 'wenn auf dem zu prüfenden Feld NIX ist
If fy <> 0 'ist das zu prüfende Feld oben oder unten, dan auf Autobewegung checken
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else
y=fy*Speed 'passt es genau, dann um Speed Pixel nach fy bewegen
End If
End If
If fx <> 0 'ist das zu prüfende Feld oben oder unten, dan auf Autobewegung checken
If yFeld*TS < yPos 'ist (Y Feldkoordinate*TS) kleiner als Pixelkoordinate
y=-Speed 'dann um Speed Pixel nach oben bewegen
Else If yFeld*TS > yPos 'ist (Y Feldkoordinate*TS) größer als Pixelkoordinate
y=+Speed 'dann um Speed Pixel nach unten bewegen
Else
x=fx*Speed 'passt es genau, dann um Speed Pixel nach fx bewegen
End If
End If
Else If fy <> 0 And yMod <> 0 'wenn nicht begehbar aber noch nicht ganz auf dem Feld, dann trotzdem bewegen
y=fy*Speed
Else If fx <> 0 And xMod <> 0 'wenn nicht begehbar aber noch nicht ganz auf dem Feld, dann trotzdem bewegen
x=fx*Speed
End If
yPos:+y 'Spieler Koordinaten aktualisieren
xPos:+x
MapFeld() 'Aktuelles Map.Feld[,] wird berechnet
BewegungsTimer = MilliSecs()
End Method
END EDIT ########## ##########
und hier die Komplette Spieler.bmx (ALT) ohne Zusammenfassung (siehe EDIT hier drüber):
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 xPos :Int 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Int
Field Speed :Int = 2
Const OBEN :Int = 0
Const UNTEN :Int = 1
Const LINKS :Int = 2
Const RECHTS :Int = 3
Field SpielerIMG :TImage 'speichert die Grafik des Spielers
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 25
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Bewegung wieder erlaubt (Zeit)
If KeyDown(KEY_UP) And MilliSecs() 'wenn Pfeiltaste OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(KEY_DOWN) And MilliSecs() 'wenn Pfeiltaste UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(KEY_LEFT) And MilliSecs() 'wenn Pfeiltaste LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() 'wenn Pfeiltaste RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End If
End Method
Method Bewegung(Richtung:Int)
Local x :Int ' Temporäre Speicher
Local y :Int
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
Select Richtung
Case OBEN
If Map.Feld[xFeld,yFeld-1].Inhalt = NIX 'wenn oben NIX ist, nach oben bewegen
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else 'passt es genau, dann um Speed Pixel nach oben bewegen
y=-Speed
End If
Else If yMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=-Speed
End If
Case UNTEN
If Map.Feld[xFeld,yFeld+1].Inhalt = NIX 'wenn unten NIX ist
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else
y=+Speed 'passt es genau, dann um Speed Pixel nach unten bewegen
End If
Else If yMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
y=+Speed
End If
Case LINKS
If Map.Feld[xFeld-1,yFeld].Inhalt = NIX 'wenn links NIX ist, nach links bewegen
If yFeld*TS < yPos 'ist (Y Feldkoordinate*TS) kleiner als Pixelkoordinate
y=-Speed 'dann um Speed Pixel nach oben bewegen
Else If yFeld*TS > yPos 'ist (Y Feldkoordinate*TS) größer als Pixelkoordinate
y=+Speed 'dann um Speed Pixel nach unten bewegen
Else
x=-Speed 'passt es genau, dann um Speed Pixel nach links bewegen
End If
Else If xMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
x=-Speed
End If
Case RECHTS
If Map.Feld[xFeld+1,yFeld].Inhalt = NIX 'wenn rechts NIX ist, nach rechts bewegen
If yFeld*TS < yPos 'ist (Y Feldkoordinate*TS) kleiner als Pixelkoordinate
y=-Speed 'dann um Speed Pixel nach oben bewegen
Else If yFeld*TS > yPos 'ist (Y Feldkoordinate*TS) größer als Pixelkoordinate
y=+Speed 'dann um Speed Pixel nach unten bewegen
Else
x=+Speed 'passt es genau, dann um Speed Pixel nach rechts bewegen
End If
Else If xMod <> 0 'wenn nicht ganz auf dem Feld, dann trotzdem bewegen
x=+Speed
End If
End Select
yPos:+y 'Spieler Koordinaten aktualisieren
xPos:+x
MapFeld() 'Aktuelles Map.Feld[,] wird berechnet
BewegungsTimer = MilliSecs()
End Method
Method MapFeld() 'berechnet aktuelles Map.Feld[,]
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
If yMod < (TS/2) Then yFeld=(yPos/TS) 'wenn modulus < als 16
If yMod > (TS/2) Then yFeld=(yPos/TS)+1 'wenn modulus > als 16
If xMod < (TS/2) Then xFeld=(xPos/TS) 'wenn modulus < als 16
If xMod > (TS/2) Then xFeld=(xPos/TS)+1 'wenn modulus > als 16
End Method
Method Zeichnen()
DrawRect (xFeld*TS,yFeld*TS,TS,TS)
DrawImage (SpielerIMG,xPos,yPos,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 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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
und hier nochmal die komplette TSpieler.bmx mit der zusammengefassten Bewegungs Methode:
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 xPos :Int 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Int
Field Speed :Int = 2
Const OBEN :Int = 0
Const UNTEN :Int = 1
Const LINKS :Int = 2
Const RECHTS :Int = 3
Field SpielerIMG :TImage 'speichert die Grafik des Spielers
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 20
Method Steuerung() 'Enthält die Steuerungsabfrage
If MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Bewegung wieder erlaubt (Zeit)
If KeyDown(KEY_UP) And MilliSecs() 'wenn Pfeiltaste OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(KEY_DOWN) And MilliSecs() 'wenn Pfeiltaste UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(KEY_LEFT) And MilliSecs() 'wenn Pfeiltaste LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() 'wenn Pfeiltaste RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End If
End Method
Method Bewegung(Richtung:Int)
Local x :Int 'Temporäre Speicher
Local y :Int
Local fx :Int 'Temporäre Speicher für zu prüfende Felder
Local fy :Int 'ist fy=-1 wird oberes vom aktuellen Feld geprüft
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
Select Richtung
Case OBEN
fy=-1 'oberes Feld prüfen
Case UNTEN
fy=+1 'unteres Feld prüfen
Case LINKS
fx=-1 'linkes Feld prüfen
Case RECHTS
fx=+1 'rechtes Feld prüfen
End Select
If Map.Feld[xFeld+fx,yFeld+fy].Inhalt = NIX 'wenn rechts NIX ist
If fy <> 0 'ist das zu prüfende Feld oben oder unten, dan auf Autobewegung checken
If xFeld*TS < xPos 'ist (X Feldkoordinate*TS) kleiner als Pixelkoordinate
x=-Speed 'dann um Speed Pixel nach links bewegen
Else If xFeld*TS > xPos 'ist (X Feldkoordinate*TS) größer als Pixelkoordinate
x=+Speed 'dann um Speed Pixel nach rechts bewegen
Else
y=fy*Speed 'passt es genau, dann um Speed Pixel nach fy bewegen
End If
End If
If fx <> 0 'ist das zu prüfende Feld oben oder unten, dan auf Autobewegung checken
If yFeld*TS < yPos 'ist (Y Feldkoordinate*TS) kleiner als Pixelkoordinate
y=-Speed 'dann um Speed Pixel nach oben bewegen
Else If yFeld*TS > yPos 'ist (Y Feldkoordinate*TS) größer als Pixelkoordinate
y=+Speed 'dann um Speed Pixel nach unten bewegen
Else
x=fx*Speed 'passt es genau, dann um Speed Pixel nach fx bewegen
End If
End If
Else If fy <> 0 And yMod <> 0 'wenn nicht begehbar aber noch nicht ganz auf dem Feld, dann trotzdem bewegen
y=fy*Speed
Else If fx <> 0 And xMod <> 0 'wenn nicht begehbar aber noch nicht ganz auf dem Feld, dann trotzdem bewegen
x=fx*Speed
End If
yPos:+y 'Spieler Koordinaten aktualisieren
xPos:+x
MapFeld() 'Aktuelles Map.Feld[,] wird berechnet
BewegungsTimer = MilliSecs()
End Method
Method MapFeld() 'berechnet aktuelles Map.Feld[,]
Local xMod :Int = (xPos Mod TS) 'Temporärer Speicher für den xPos modulus von TS (32)
Local yMod :Int = (yPos Mod TS)
If yMod < (TS/2) Then yFeld=(yPos/TS) 'wenn modulus < als 16
If yMod > (TS/2) Then yFeld=(yPos/TS)+1 'wenn modulus > als 16
If xMod < (TS/2) Then xFeld=(xPos/TS) 'wenn modulus < als 16
If xMod > (TS/2) Then xFeld=(xPos/TS)+1 'wenn modulus > als 16
End Method
Method Zeichnen()
DrawRect (xFeld*TS,yFeld*TS,TS,TS)
DrawImage (SpielerIMG,xPos,yPos,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 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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
Um ein wenig auf der Map rumzulaufen, ohne die störenden Softblöcke (um das ganze einfach mal zu testen), kann man diese ganz einfach in der TKarte.bmx entfernen.
Einfach in der Erstellen Funktion die Variable BlockZahl auf 0 setzen:
BlitzMax: [AUSKLAPPEN]
'#############################################
'# MAP MIT 100 SOFTBLÖCKEN FÜLLEN #
'# DABEI SPIELER-STARTECKEN FREI LASSEN #
'#############################################
Local BlockZahl:Int = 100 '100 Softblöcke sollen gesetzt werden
dort bei
BlitzMax: [AUSKLAPPEN]
Local BlockZahl:Int = 100
einfach 0 eintragen:
BlitzMax: [AUSKLAPPEN]
Local BlockZahl:Int = 0
und die MainGame.bmx starten. Schon kann man die ganze Sache mit mehr Freiraum testen.
Diesmal gibt es wieder den kompletten Code bis hier hin (inklusive .EXE) zum Download:
https://www.blitzforum.de/upload/file.php?id=9412
Das war es dann erstmal zur Pixelweise Bewegung mit TileMap Kollision. Ich bedanke mich erneut fürs Lesen und es gilt wie immer:
Ich würde mich übelst über positive wie auch negative Kritik und Verbesserungsvorschläge freuen, Danke
Bein nächsten mal lege ich dann ne Bombe oder evtl. werd ich den Spieler ersteinmal animieren... oder beides... mal sehen *wink*
Pixelweise Bewegung und Map.Feld Berechnungen
Sonntag, 29. August 2010 von KirkZero
Nun will ich mich Pixelweise bewegen...
Dazu erhält TSpieler erstmal ein paar neue Field Einträge und ein paar Konstante:
BlitzMax: [AUSKLAPPEN]
Neu sind nun XPos und yPos. Diese sind nun für die Position in Pixel für den Spieler zuständig. xFeld und yFeld bleiben allerdings weiterhin wichtig, da ich ja immer noch wissen will, auf welchem Feld der Map sich der Spieler befindet.
Speed habe ich auf 2 gesetzt. Speed gibt an, wieviele Pixel sich der Spieler bei jeder Bewegung fortbewegt.
die 4 Konstanten OBEN, UNTEN, LINKS und RECHTS vereinfachen mir nur wieder die Sache, dass ich nicht mit Zahlen arbeiten muss, sondern aussagekräftige Namen habe... wofür die sind, kommt später.
BewegungsPause habe ich runter auf 10 gesetzt, da wir uns ja nun gleich Pixelweise bewegen wollen und 250 wären ziemlich langsame Schritte
die Erstellen Funktion passe ich ebenfalls an:
BlitzMax: [AUSKLAPPEN]
NeuerSpieler.xPos und NeuerSpieler.yPos erhalten nun ihre PixelKoordinaten ausgehend vom StartFELD!
Hier die Zeichnen Methode:
BlitzMax: [AUSKLAPPEN]
Ich zeichne dort auch ein Rechteck. Dieses soll mir visuell veranschaulichen, auf welchem Map.Feld sich der Spieler momentan befindet (Ändert sich allerdings noch nicht, kommt später )
Jetzt noch die Steuerungs Methode angepasst:
BlitzMax: [AUSKLAPPEN]
und schon bewege ich mich Pixelweise
hier noch der Komplette Code:
BlitzMax: [AUSKLAPPEN]
Jetzt zu den 4 Konstanten OBEN, UNTEN, LINKS und RECHTS.
Ich erstelle eine neue Methode namens Bewegung():
BlitzMax: [AUSKLAPPEN]
Statt nun immer alle koordinatenänderungen in der Methode Steuerung vorzunehmen, möchte ich das auf die Methode Bewegung abschieben.
Drücke ich nun die Rechte Pfeiltaste, Rufe ich die Methode Bewegung() so auf:
BlitzMax: [AUSKLAPPEN]
was passiert dann? die temporäre Speichervariable x bekommt den positiven Wert von Speed zugewiesen. Also ist nun x=2
Da y=0 ist wird nun also am ende von "Select Case" die yPos Variable den wert 0 addiert und die xPos Variable den wert Speed addiert. Also bewege ich mich jetzt 2 pixel nach rechts.
Danach muss ich natürlich den BewegungsTimer wieder auf MilliSecs() setzen.
Anmerkung von mir: Man muss z.B. bei:
BlitzMax: [AUSKLAPPEN]
x nicht den Wert 0 zuweisen, da dieser so oder so beim Aufruf der Methode erstmal 0 ist. Habe es aber erstmal der Vollständigkeit halber trotzdem gemacht. (gleiches gilt natürlich für y)
nun noch die Steuerungs Methode angepasst:
BlitzMax: [AUSKLAPPEN]
und schon klappt alles so wie vorher auch.
Kompletter Code der TSpieler.bmx:
BlitzMax: [AUSKLAPPEN]
Jetzt will ich auch das Feld aktualisieren, wenn der Spieler ein neues Feld betritt. Das erledige ich erstmal ganz simpel, in dem ich eine neue Methode erstelle, welche ich in der Bewegungs Methode aufrufe. Diese schaut vorerst so aus:
BlitzMax: [AUSKLAPPEN]
rufe ich nun diese Methode am Ende der Bewegungs Methode auf, so ändern sich nun auch die Map.Feld Koordinaten.
BlitzMax: [AUSKLAPPEN]
Bewegt man sich nun auf ein anderes Tile der Map, so wird nun auch das Aktuelle Feld geändert. Das passiert zwar nun noch ungenau, da es sich erst ändert, wenn sich der obere linke Punkt (die BezugsKoordinate) des Spielers auf einem neuem Tile befindet, aber das werd ich gleich noch ändern.
Bin da grad am Tüfteln mittels Mod()
So... und das ist dabei rausgekommen und macht auch genau das, was ich will:
BlitzMax: [AUSKLAPPEN]
Sobald man sich über die Hälfte des Feldes hinausbewegt ( (16 Mod 32)=16 also alles was über 16 ist, gilt als über die Hälfte) betritt man ein neues Tile (weiterhin in der Zeichen Methode visuell angezeigt, durch DrawRect)
und hier ein kleines CodeBeispiel, was Mod macht bzw welche Werte es ausspuckt im Wertebereich meiner TileGröße(32)
(neues Fenster in der IDE öffnen, einfügen und laufen lassen )
BlitzMax: [AUSKLAPPEN]
Mod ergibt also den nichtteilbaren Rest. 32 lässt sich durch 32 teilen, darum ergibt 32 Mod 32 = 0
34 lässt sich einmal durch 32 teilen, bleiben allerdings 2 über darum ergibt 34 Mod 32 = 2 usw...
Da nun die FeldAktualisierung korrekt funktioniert, kann ich mich im nächsten Worklog um die Kollision mit der TileMap kümmern.
Da ich ein wenig ArchivSpeicherplatz sparen will und ich lediglich die TSpieler.bmx geändert habe, gibt es diesmal nur den Code der TSpieler.bmx
welcher einfach in diesen Download (der letzte komplette Download):
https://www.blitzforum.de/upload/file.php?id=9377
eingefügt werden kann und die alte TSpieler.bmx dann ersetzt.
Der komplette Code von TSpieler.bmx:
BlitzMax: [AUSKLAPPEN]
Danke fürs Lesen und wie immer gilt:
Ich würde mich übelst über positive wie auch negative Kritik und Verbesserungsvorschläge freuen, Danke
Dazu erhält TSpieler erstmal ein paar neue Field Einträge und ein paar Konstante:
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 xPos :Int 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Int
Field Speed :Int = 2
Const OBEN :Int = 0
Const UNTEN :Int = 1
Const LINKS :Int = 2
Const RECHTS :Int = 3
Field SpielerIMG :TImage 'speichert die Grafik des Spielers
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 10
Neu sind nun XPos und yPos. Diese sind nun für die Position in Pixel für den Spieler zuständig. xFeld und yFeld bleiben allerdings weiterhin wichtig, da ich ja immer noch wissen will, auf welchem Feld der Map sich der Spieler befindet.
Speed habe ich auf 2 gesetzt. Speed gibt an, wieviele Pixel sich der Spieler bei jeder Bewegung fortbewegt.
die 4 Konstanten OBEN, UNTEN, LINKS und RECHTS vereinfachen mir nur wieder die Sache, dass ich nicht mit Zahlen arbeiten muss, sondern aussagekräftige Namen habe... wofür die sind, kommt später.
BewegungsPause habe ich runter auf 10 gesetzt, da wir uns ja nun gleich Pixelweise bewegen wollen und 250 wären ziemlich langsame Schritte
die Erstellen Funktion passe ich ebenfalls an:
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 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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
NeuerSpieler.xPos und NeuerSpieler.yPos erhalten nun ihre PixelKoordinaten ausgehend vom StartFELD!
Hier die Zeichnen Methode:
BlitzMax: [AUSKLAPPEN]
Method Zeichnen()
DrawRect (xFeld*TS,yFeld*TS,TS,TS) 'Zeichnet ein Rechteck auch aktuellem FELD
DrawImage (SpielerIMG,xPos,yPos,0) 'Zeichnet den Spieler an seinen PixelKoordinaten
End Method
Ich zeichne dort auch ein Rechteck. Dieses soll mir visuell veranschaulichen, auf welchem Map.Feld sich der Spieler momentan befindet (Ändert sich allerdings noch nicht, kommt später )
Jetzt noch die Steuerungs Methode angepasst:
BlitzMax: [AUSKLAPPEN]
Method Steuerung() 'Enthält die Steuerungsabfrage
If KeyDown(KEY_UP) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste OBEN gedrückt wird
yPos:-Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_DOWN) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste UNTEN gedrückt wird
yPos:+Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_LEFT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste LINKS gedrückt wird
xPos:-Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste RECHTS gedrückt wird
xPos:+Speed
BewegungsTimer = MilliSecs()
End If
End Method
und schon bewege ich mich Pixelweise
hier noch der Komplette Code:
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 xPos :Int 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Int
Field Speed :Int = 2
Const OBEN :Int = 0
Const UNTEN :Int = 1
Const LINKS :Int = 2
Const RECHTS :Int = 3
Field SpielerIMG :TImage 'speichert die Grafik des Spielers
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 10
Method Steuerung() 'Enthält die Steuerungsabfrage
If KeyDown(KEY_UP) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste OBEN gedrückt wird
yPos:-Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_DOWN) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste UNTEN gedrückt wird
yPos:+Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_LEFT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste LINKS gedrückt wird
xPos:-Speed
BewegungsTimer = MilliSecs()
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste RECHTS gedrückt wird
xPos:+Speed
BewegungsTimer = MilliSecs()
End If
End Method
Method Zeichnen()
DrawRect (xFeld*TS,yFeld*TS,TS,TS)
DrawImage (SpielerIMG,xPos,yPos,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 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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
Jetzt zu den 4 Konstanten OBEN, UNTEN, LINKS und RECHTS.
Ich erstelle eine neue Methode namens Bewegung():
BlitzMax: [AUSKLAPPEN]
Method Bewegung(Richtung:Int)
Local x :Int 'Temporäre Speicher
Local y :Int
Select Richtung
Case OBEN
x=0
y=-Speed
Case UNTEN
x=0
y=+Speed
Case LINKS
x=-Speed
y=0
Case RECHTS
x=+Speed
y=0
End Select
yPos:+y
xPos:+x
BewegungsTimer = MilliSecs()
End Method
Statt nun immer alle koordinatenänderungen in der Methode Steuerung vorzunehmen, möchte ich das auf die Methode Bewegung abschieben.
Drücke ich nun die Rechte Pfeiltaste, Rufe ich die Methode Bewegung() so auf:
BlitzMax: [AUSKLAPPEN]
Bewegung(RECHTS)
was passiert dann? die temporäre Speichervariable x bekommt den positiven Wert von Speed zugewiesen. Also ist nun x=2
Da y=0 ist wird nun also am ende von "Select Case" die yPos Variable den wert 0 addiert und die xPos Variable den wert Speed addiert. Also bewege ich mich jetzt 2 pixel nach rechts.
Danach muss ich natürlich den BewegungsTimer wieder auf MilliSecs() setzen.
Anmerkung von mir: Man muss z.B. bei:
BlitzMax: [AUSKLAPPEN]
Case OBEN
x=0 'braucht nicht auf 0 gesetzt zu werden (kann also weggelassen werden)
y=-Speed
x nicht den Wert 0 zuweisen, da dieser so oder so beim Aufruf der Methode erstmal 0 ist. Habe es aber erstmal der Vollständigkeit halber trotzdem gemacht. (gleiches gilt natürlich für y)
nun noch die Steuerungs Methode angepasst:
BlitzMax: [AUSKLAPPEN]
Method Steuerung() 'Enthält die Steuerungsabfrage
If KeyDown(KEY_UP) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(KEY_DOWN) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(KEY_LEFT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End Method
und schon klappt alles so wie vorher auch.
Kompletter Code der TSpieler.bmx:
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 xPos :Int 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Int
Field Speed :Int = 2
Const OBEN :Int = 0
Const UNTEN :Int = 1
Const LINKS :Int = 2
Const RECHTS :Int = 3
Field SpielerIMG :TImage 'speichert die Grafik des Spielers
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 10
Method Steuerung() 'Enthält die Steuerungsabfrage
If KeyDown(KEY_UP) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(KEY_DOWN) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(KEY_LEFT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End Method
Method Bewegung(Richtung:Int)
Local x :Int '
Local y :Int
Select Richtung
Case OBEN
x=0 'braucht nicht auf 0 gesetzt zu werden (kann also weggelassen werden)
y=-Speed
Case UNTEN
x=0 'braucht nicht auf 0 gesetzt zu werden (kann also weggelassen werden)
y=+Speed
Case LINKS
x=-Speed
y=0 'braucht nicht auf 0 gesetzt zu werden (kann also weggelassen werden)
Case RECHTS
x=+Speed
y=0 'braucht nicht auf 0 gesetzt zu werden (kann also weggelassen werden)
End Select
yPos:+y
xPos:+x
BewegungsTimer = MilliSecs()
End Method
Method Zeichnen()
DrawRect (xFeld*TS,yFeld*TS,TS,TS)
DrawImage (SpielerIMG,xPos,yPos,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 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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
Jetzt will ich auch das Feld aktualisieren, wenn der Spieler ein neues Feld betritt. Das erledige ich erstmal ganz simpel, in dem ich eine neue Methode erstelle, welche ich in der Bewegungs Methode aufrufe. Diese schaut vorerst so aus:
BlitzMax: [AUSKLAPPEN]
Method MapFeld()
yFeld=(yPos/TS)
xFeld=(xPos/TS)
End Method
rufe ich nun diese Methode am Ende der Bewegungs Methode auf, so ändern sich nun auch die Map.Feld Koordinaten.
BlitzMax: [AUSKLAPPEN]
Method Bewegung(Richtung:Int)
Local x :Int ' Temporäre Speicher
Local y :Int
Select Richtung
Case OBEN
y=-Speed
Case UNTEN
y=+Speed
Case LINKS
x=-Speed
Case RECHTS
x=+Speed
End Select
yPos:+y
xPos:+x
MapFeld() 'Aktuelles Map.Feld wird berechnet
BewegungsTimer = MilliSecs()
End Method
Bewegt man sich nun auf ein anderes Tile der Map, so wird nun auch das Aktuelle Feld geändert. Das passiert zwar nun noch ungenau, da es sich erst ändert, wenn sich der obere linke Punkt (die BezugsKoordinate) des Spielers auf einem neuem Tile befindet, aber das werd ich gleich noch ändern.
Bin da grad am Tüfteln mittels Mod()
So... und das ist dabei rausgekommen und macht auch genau das, was ich will:
BlitzMax: [AUSKLAPPEN]
Method MapFeld()
Local yMod :Int = (yPos Mod TS) 'Temporärer Speicher für den yPos modulus von TS (32)
Local xMod :Int = (xPos Mod TS)
If yMod < (TS/2) Then yFeld=(yPos/TS) 'wenn modulus < als 16
If yMod > (TS/2) Then yFeld=(yPos/TS)+1 'wenn modulus > als 16
If xMod < (TS/2) Then xFeld=(xPos/TS) 'wenn modulus < als 16
If xMod > (TS/2) Then xFeld=(xPos/TS)+1 'wenn modulus > als 16
End Method
Sobald man sich über die Hälfte des Feldes hinausbewegt ( (16 Mod 32)=16 also alles was über 16 ist, gilt als über die Hälfte) betritt man ein neues Tile (weiterhin in der Zeichen Methode visuell angezeigt, durch DrawRect)
und hier ein kleines CodeBeispiel, was Mod macht bzw welche Werte es ausspuckt im Wertebereich meiner TileGröße(32)
(neues Fenster in der IDE öffnen, einfügen und laufen lassen )
BlitzMax: [AUSKLAPPEN]
Rem
Mod is a mathematical operator that performs the Modulo function.
End Rem
For i=0 To 32 Step 2
Print i+" Mod 32="+(i Mod 32)
Next
Mod ergibt also den nichtteilbaren Rest. 32 lässt sich durch 32 teilen, darum ergibt 32 Mod 32 = 0
34 lässt sich einmal durch 32 teilen, bleiben allerdings 2 über darum ergibt 34 Mod 32 = 2 usw...
Da nun die FeldAktualisierung korrekt funktioniert, kann ich mich im nächsten Worklog um die Kollision mit der TileMap kümmern.
Da ich ein wenig ArchivSpeicherplatz sparen will und ich lediglich die TSpieler.bmx geändert habe, gibt es diesmal nur den Code der TSpieler.bmx
welcher einfach in diesen Download (der letzte komplette Download):
https://www.blitzforum.de/upload/file.php?id=9377
eingefügt werden kann und die alte TSpieler.bmx dann ersetzt.
Der komplette Code von TSpieler.bmx:
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 xPos :Float 'x und y Koordinaten für Pixelweise Bewegung
Field yPos :Float
Field Speed :Int = 2
Const OBEN :Int = 0
Const UNTEN :Int = 1
Const LINKS :Int = 2
Const RECHTS :Int = 3
Field SpielerIMG :TImage 'speichert die Grafik des Spielers
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 10
Method Steuerung() 'Enthält die Steuerungsabfrage
If KeyDown(KEY_UP) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste OBEN gedrückt wird
Bewegung(OBEN)
ElseIf KeyDown(KEY_DOWN) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste UNTEN gedrückt wird
Bewegung(UNTEN)
ElseIf KeyDown(KEY_LEFT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste LINKS gedrückt wird
Bewegung(LINKS)
ElseIf KeyDown(KEY_RIGHT) And MilliSecs() > BewegungsTimer+BewegungsPause 'wenn Pfeiltaste RECHTS gedrückt wird
Bewegung(RECHTS)
End If
End Method
Method Bewegung(Richtung:Int)
Local x :Int ' Temporäre Speicher
Local y :Int
Select Richtung
Case OBEN
y=-Speed
Case UNTEN
y=+Speed
Case LINKS
x=-Speed
Case RECHTS
x=+Speed
End Select
yPos:+y
xPos:+x
MapFeld() 'Aktuelles Map.Feld wird berechnet
BewegungsTimer = MilliSecs()
End Method
Method MapFeld()
Local yMod :Int = (yPos Mod TS) 'Temporärer Speicher für den yPos modulus von TS (32)
Local xMod :Int = (xPos Mod TS)
If yMod < (TS/2) Then yFeld=(yPos/TS) 'wenn modulus < als 16
If yMod > (TS/2) Then yFeld=(yPos/TS)+1 'wenn modulus > als 16
If xMod < (TS/2) Then xFeld=(xPos/TS) 'wenn modulus < als 16
If xMod > (TS/2) Then xFeld=(xPos/TS)+1 'wenn modulus > als 16
End Method
Method Zeichnen()
DrawRect (xFeld*TS,yFeld*TS,TS,TS)
DrawImage (SpielerIMG,xPos,yPos,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 'Start FELD Koordinaten übergeben
NeuerSpieler.yFeld = yFeld
NeuerSpieler.xPos = xFeld*TS 'Koordinaten für Pixelweise Bewegung füllen
NeuerSpieler.yPos = yFeld*TS
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
Danke fürs Lesen und wie immer gilt:
Ich würde mich übelst über positive wie auch negative Kritik und Verbesserungsvorschläge freuen, Danke
Einige Änderungen des vorigen Worklogs
Mittwoch, 25. August 2010 von KirkZero
EDIT: Dies ist nun die Editierte Version mit Kommentaren und Erklärungen. Ich werde meinen Original Text so stehen lassen, und jeweils dann da unter ein DICKES EDIT einfügen, mit den Korrekturen.
Erstmal Danke an D2006 für die Hinweise, wie ich noch ein wenig mehr Übersicht für mein Projekt bekomme und Danke auch an Lastmayday für den wirklich ausführlichen Kommentar zu meinem Code und die von ihm gegebenen Tipps!
Daraus resultierend nehme ich folgende Änderungen am Code vor:
Zuersteinmal lege ich für alle Dateien, welche ich in der MainGame.bmx durch Include einbinde, ein neues Verzeichnis namens "INCLUDES" im Hauptordner an. Dort kopiere ich alle .bmx Dateien, welche ich einbinde hinein. (das sind z.Z. TKarte.bmx, TFeld.bmx und TSpieler.bmx)
Somit ist mein Hauptordner nun viel übersichtlicher. Noch schnell die Änderung in der MainGame.bmx gemacht:
BlitzMax: [AUSKLAPPEN]
und schon ist das Programm wieder lauffähig.
Ich werde evtl. später, so wie D2006 es selbst auch handhabt, eine extra "includes.bmx", in der alle nötigen Dateien inkludiert werden und das Hauptprogramm inkludiert dann nur eben jene "includes.bmx" einführen. Doch vorerst lasse ich es so, da ich erstmal schauen will, wie viel ich später noch inkludieren werde. Sollten es dann doch mehr Dateien werden, werde ich es ebenso wie D2006 machen.
Nächste Änderung: einen Fenstertitel erstellen. Zur Zeit steht als Fenstertitel nur "BlitzMax Application". Mittels
BlitzMax: [AUSKLAPPEN]
personalisiere ich das ganze ein bissel. Das ganze setze ich direkt unter SuperStrict in der MainGame.bmx (Laut Lastmayday muss der Befehl VOR Graphics stehen!!!)
BlitzMax: [AUSKLAPPEN]
und schon steht im Fenstertitel "Bomberman Klon (Community Tutorial)" eine kleine aber feine Sache werd ich mir unbedingt angewöhnen, dies immer gleich zu beginn mit einzubauen.
EDIT: ###############
Fehlerkorrektur: (Danke @Thunder)
Zitat:
END EDIT #############
Ebenfalls eine kleine, aber dennoch wichtige Sache, welche ich bisher auch immer vernachlässigt habe: Man kann das Programm nur mittels [ESC] beenden. Ein klick auf das Kreuz oben rechts im Fenster bewirkt z.Z. absolut garnix. Aber da es zur guten Schule gehört, dass man Fenster auch auf diese weise schliessen kann, will ich mich da mal nicht quer stellen. In der Hauptschleife (Repeat... Until) nicht nur die bdingung der Escape taste zum beenden der Schleife setzen, sondern ebenfall, wenn man auf das Kreuz klickt.
BlitzMax: [AUSKLAPPEN]
Nächster Punkt. Zitat von Lastmayday:
Zitat:
Ich glaube, dass wäre mir selber nie aufgefallen... junge, junge... was man nicht alles für Mist baut aber das war ja auch einer der Gründe, warum ich das hier mache... möchte meine Fehler ausmerzen. Also änder ich das gleich mal in der TFeld.bmx
Statt:
BlitzMax: [AUSKLAPPEN]
sollte es so richtig sein:
BlitzMax: [AUSKLAPPEN]
Und weiter gehts. Wieder ein Zitat von Lastmayday:
Zitat:
Wahrscheinlich hat er Recht. Ich sollte das ganze vielleicht nicht komplizierter machen, als es sein muss. Hab mir dazu noch mal nen Kopf gemacht und es lässt sich auch ohne Vererben super lösen. Mein Grund, es so zu machen, damit jeder Spieler seine eigen Steuerung bekommt, war also der falsche Ansatz.
Damit ändere ich die TSpieler.bmx wieder und es wird nix mehr vereerbt. Die neue Klasse TSpieler1 verschwindet also wieder.
Erstmal das Original, wie es jetzt noch ist:
BlitzMax: [AUSKLAPPEN]
Und hier die geänderte Version wieder ohne Extends:
BlitzMax: [AUSKLAPPEN]
Jetzt kommt eine Sache, mit der ich noch absolut garnichts zu tun hatte. Zitat von Lastmayday:
Zitat:
nun gut, dann werd ich mir das jetzt mal anschauen, und das Ergebnis folgt dann nach diesem Satz
Zitat:
*grml* ok... da muss ich wohl noch ein bissel suchen...
Ahhh... ok, das Ganze muss ganz am Anfang der MainGame.bmx stehen... ich hatte es unter SuperStrict eingefügt
EDIT: ###############
Fehlerkorrektur (Danke Thunder und Lastmayday):
Zitat:
Zitat:
Mein Fehler war, ich hatte nach SuperStrict noch AppTiltle stehen und dann erst Framework und Import
END EDIT ###############
Also, Sinn der Sache ist es, wie Lastmayday schon sagte, nur die Module in die .EXE datei mit einzubinden, welche auch wirklich gebraucht werden. Ich hätte jetzt nicht gedacht, dass das so einen Unterschied macht, aber statt 1,28 MB ist die .EXE mit Framework und Import nur noch schlanke 442 kb groß... GENIAL
und hier der Code:
BlitzMax: [AUSKLAPPEN]
So, hab mal nen bissel in der Hilfe geschnüffelt und mir nochmals Lastmaydays kommentare angeschaut und dabei haben sich mir folgende Erkentnisse aufgetan (Bitte korrigieren, wenn ich mit irgendetwas falsch liege)
Mein jetziges Framework basiert auf dem Modul brl.Max2D, dieses ist für die arbeit mit DirectX?
Will ich mit OpenGL arbeiten, so wäre es brl.GlMax2D.
EDIT: ###############
Fehlerkorrektur (Danke an Thunder und mpmxyz)
Zitat:
Zitat:
END EDIT ###############
Nun importiere ich alle Module, die ich benötige.
brl.Timer : benötige ich, da ich CreateTimer und WaitTimer im Code benutze
brl.Random : sollte klar sein. Ich arbeite ja mit einigen Zufallsfunktionen (z.B. Rand, SeedRnd, ...)
brl.D3D7Max2D : benötige ich, um später (vor Graphics) den Grafiktreiber zu setzen
brl.PNGLoader : ist dafür da, um Pixmaps im PNG format zu laden ???
Wieder Zitat von Lastmayday:
Zitat:
Nun setze ich den Grafiktreiber (vor Graphics in der MainGame.bmx):
BlitzMax: [AUSKLAPPEN]
Anmerkung von mir: wenn ich den Grafiktreiber nicht setze, also den Befehl "SetGraphicsDriver D3D7Max2DDriver()" einfach weglasse... startet mein Programm trotzdem ohne zu meckern. Meine Frage nun an jemand, der sich auskennt: ist es unbedingt nötig, diesen Befehl zu benutzen, oder setzt BMAX den treiber automatisch, wenn der Befehl fehlt???
EDIT: ###############
Anmerkungen (Danke an Thunder, Lastmayday und BladeRunner)
Zitat:
Zitat:
Zitat:
Ich werde dann auf dx9 umschwenken. Einfach folgendes ändern (in der MainGame.bmx)
brl.D3D7Max2D gegen brl.D3D9Max2D austauschen und
SetGraphicsDriver D3D7Max2DDriver() gegen SetGraphicsDriver D3D9Max2DDriver() austauschen.
END EDIT ###############
So, und hier mal wieder der komplette Code bis hier hin (inklusive .EXE)
die Größe des Downloads ist durch Framework und Import geschrumpft und beträgt nun nur noch feine 207 kb statt 671 kb
https://www.blitzforum.de/upload/file.php?id=9377
Wenn das so weiter geht... reicht mein Speicherplatz im Archiv bestimmt bald nicht mehr aus
Danke für die ganzen Tipps. Ich denke, ich habe heute eine Menge gelernt!!! *freu*
Erstmal Danke an D2006 für die Hinweise, wie ich noch ein wenig mehr Übersicht für mein Projekt bekomme und Danke auch an Lastmayday für den wirklich ausführlichen Kommentar zu meinem Code und die von ihm gegebenen Tipps!
Daraus resultierend nehme ich folgende Änderungen am Code vor:
Zuersteinmal lege ich für alle Dateien, welche ich in der MainGame.bmx durch Include einbinde, ein neues Verzeichnis namens "INCLUDES" im Hauptordner an. Dort kopiere ich alle .bmx Dateien, welche ich einbinde hinein. (das sind z.Z. TKarte.bmx, TFeld.bmx und TSpieler.bmx)
Somit ist mein Hauptordner nun viel übersichtlicher. Noch schnell die Änderung in der MainGame.bmx gemacht:
BlitzMax: [AUSKLAPPEN]
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
und schon ist das Programm wieder lauffähig.
Ich werde evtl. später, so wie D2006 es selbst auch handhabt, eine extra "includes.bmx", in der alle nötigen Dateien inkludiert werden und das Hauptprogramm inkludiert dann nur eben jene "includes.bmx" einführen. Doch vorerst lasse ich es so, da ich erstmal schauen will, wie viel ich später noch inkludieren werde. Sollten es dann doch mehr Dateien werden, werde ich es ebenso wie D2006 machen.
Nächste Änderung: einen Fenstertitel erstellen. Zur Zeit steht als Fenstertitel nur "BlitzMax Application". Mittels
BlitzMax: [AUSKLAPPEN]
AppTitle = "Bomberman Klon (Community Tutorial)
personalisiere ich das ganze ein bissel. Das ganze setze ich direkt unter SuperStrict in der MainGame.bmx (Laut Lastmayday muss der Befehl VOR Graphics stehen!!!)
BlitzMax: [AUSKLAPPEN]
SuperStrict 'zwingt mich, sauber zu programmieren
AppTitle = "Bomberman Klon (Community Tutorial)"
und schon steht im Fenstertitel "Bomberman Klon (Community Tutorial)" eine kleine aber feine Sache werd ich mir unbedingt angewöhnen, dies immer gleich zu beginn mit einzubauen.
EDIT: ###############
Fehlerkorrektur: (Danke @Thunder)
Zitat:
- AppTitle ist nicht ein Befehl sondern eine Variable die von der IDE farblich hervorgehoben wird.
END EDIT #############
Ebenfalls eine kleine, aber dennoch wichtige Sache, welche ich bisher auch immer vernachlässigt habe: Man kann das Programm nur mittels [ESC] beenden. Ein klick auf das Kreuz oben rechts im Fenster bewirkt z.Z. absolut garnix. Aber da es zur guten Schule gehört, dass man Fenster auch auf diese weise schliessen kann, will ich mich da mal nicht quer stellen. In der Hauptschleife (Repeat... Until) nicht nur die bdingung der Escape taste zum beenden der Schleife setzen, sondern ebenfall, wenn man auf das Kreuz klickt.
BlitzMax: [AUSKLAPPEN]
Until (KeyHit(KEY_ESCAPE) Or AppTerminate()) 'Programm wird beendet, sobald Escape oder Kreuz oben rechts im Fenster gedrückt wird
Nächster Punkt. Zitat von Lastmayday:
Zitat:
in TFeld lädst du bei jedem 'new' die Image noch einmal neu. Du kannst auch in einer Type Global benutzen. Dann wird das Image nur einmal geladen.
Ich glaube, dass wäre mir selber nie aufgefallen... junge, junge... was man nicht alles für Mist baut aber das war ja auch einer der Gründe, warum ich das hier mache... möchte meine Fehler ausmerzen. Also änder ich das gleich mal in der TFeld.bmx
Statt:
BlitzMax: [AUSKLAPPEN]
Field BodenTilesIMG :TImage = LoadAnimImage("gfx/boden.png",TS,TS,0,BODENFRAMES)
Field BlockTilesIMG :TImage = LoadAnimImage("gfx/block.png",TS,TS,0,BLOCKFRAMES)
sollte es so richtig sein:
BlitzMax: [AUSKLAPPEN]
Global BodenTilesIMG :TImage = LoadAnimImage("gfx/boden.png",TS,TS,0,BODENFRAMES)
Global BlockTilesIMG :TImage = LoadAnimImage("gfx/block.png",TS,TS,0,BLOCKFRAMES)
Und weiter gehts. Wieder ein Zitat von Lastmayday:
Zitat:
Eine extra Type für jeden einzelnen Tspieler zu machen ist etwas zu viel des guten. Extends ist doch etwas für Fortgeschrittene. Wie wäre es die Tastatur Belegung in Tspieler zu speichern? KEY_LEFT ist auch nur eine variable mit einem wert.
<code>
Field upkey:int, downkey:int, rightkey:int, leftkey:int
</code>
und bei typischen 4 Spielern reicht auch eine kleine array/liste.
<code>
Field upkey:int, downkey:int, rightkey:int, leftkey:int
</code>
und bei typischen 4 Spielern reicht auch eine kleine array/liste.
Wahrscheinlich hat er Recht. Ich sollte das ganze vielleicht nicht komplizierter machen, als es sein muss. Hab mir dazu noch mal nen Kopf gemacht und es lässt sich auch ohne Vererben super lösen. Mein Grund, es so zu machen, damit jeder Spieler seine eigen Steuerung bekommt, war also der falsche Ansatz.
Damit ändere ich die TSpieler.bmx wieder und es wird nix mehr vereerbt. Die neue Klasse TSpieler1 verschwindet also wieder.
Erstmal das Original, wie es jetzt noch ist:
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
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 250
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
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
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
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
Und hier die geänderte Version wieder ohne Extends:
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
Field BewegungsTimer :Int = MilliSecs()
Field BewegungsPause :Int = 250
Method Steuerung() 'Enthält die Steuerungsabfrage
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
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
Jetzt kommt eine Sache, mit der ich noch absolut garnichts zu tun hatte. Zitat von Lastmayday:
Zitat:
das Thema mit Framework und Import ansprechen. Zweck ist das die exe nur mit den Modulen gebaut wird welches das Spiel benötigt:
nun gut, dann werd ich mir das jetzt mal anschauen, und das Ergebnis folgt dann nach diesem Satz
Zitat:
Expecting expression but encountered Framework
*grml* ok... da muss ich wohl noch ein bissel suchen...
Ahhh... ok, das Ganze muss ganz am Anfang der MainGame.bmx stehen... ich hatte es unter SuperStrict eingefügt
EDIT: ###############
Fehlerkorrektur (Danke Thunder und Lastmayday):
Zitat:
- SuperStrict darf am Anfang stehen (ich schreibe Superstrict immer in die erste Zeile und Framework in die zweite), es darf nur keine gewöhnliche Codezeile vor Framework stehen.
Zitat:
Framework muss eben deswegen an erster(oder zweiter -> SuperStrict) stelle im Code stehen um dem Compiler zu sagen das jetzt nur die Module einbinden soll die als nächstes aufgeführt sind
Mein Fehler war, ich hatte nach SuperStrict noch AppTiltle stehen und dann erst Framework und Import
END EDIT ###############
Also, Sinn der Sache ist es, wie Lastmayday schon sagte, nur die Module in die .EXE datei mit einzubinden, welche auch wirklich gebraucht werden. Ich hätte jetzt nicht gedacht, dass das so einen Unterschied macht, aber statt 1,28 MB ist die .EXE mit Framework und Import nur noch schlanke 442 kb groß... GENIAL
und hier der Code:
BlitzMax: [AUSKLAPPEN]
Framework brl.max2d
Import brl.Timer
Import brl.Random
Import brl.D3D7Max2D
Import brl.PNGLoader
SuperStrict 'zwingt mich, sauber zu programmieren
AppTitle = "Bomberman Klon (Community Tutorial)"
'------------------------------ includes ----------
Include "INCLUDES/TKarte.bmx"
Include "INCLUDES/TFeld.bmx"
Include "INCLUDES/TSpieler.bmx"
So, hab mal nen bissel in der Hilfe geschnüffelt und mir nochmals Lastmaydays kommentare angeschaut und dabei haben sich mir folgende Erkentnisse aufgetan (Bitte korrigieren, wenn ich mit irgendetwas falsch liege)
Mein jetziges Framework basiert auf dem Modul brl.Max2D, dieses ist für die arbeit mit DirectX?
Will ich mit OpenGL arbeiten, so wäre es brl.GlMax2D.
EDIT: ###############
Fehlerkorrektur (Danke an Thunder und mpmxyz)
Zitat:
- Das Modul Max2D hat eigentlich nur wenig mit den Treibern zu tun - es ist eher ein Universalaufsatz den man bis jetzt mit 3 offiziellen Treibern verwenden kann: D3D7Max2DDriver(), D3D9Max2DDriver(), GLMax2DDriver() (die module heißen wie die Treiberfunktionen nur ohne "Driver()").
Zitat:
brl.Max2D ist ein komplett abstraktes Modul.
Das heißt, dass es weder etwas mit OpenGl noch mit DirectX zu tun hat.
Die Implementierung erledigen die brl.xyzMax2D-Module.
Wenn du einfach nur so Code wegschreibst, musst du keinen Grafiktreiber setzen, da die Module ihn beim Start des Programmes selbst festlegen.
Das heißt, dass es weder etwas mit OpenGl noch mit DirectX zu tun hat.
Die Implementierung erledigen die brl.xyzMax2D-Module.
Wenn du einfach nur so Code wegschreibst, musst du keinen Grafiktreiber setzen, da die Module ihn beim Start des Programmes selbst festlegen.
END EDIT ###############
Nun importiere ich alle Module, die ich benötige.
brl.Timer : benötige ich, da ich CreateTimer und WaitTimer im Code benutze
brl.Random : sollte klar sein. Ich arbeite ja mit einigen Zufallsfunktionen (z.B. Rand, SeedRnd, ...)
brl.D3D7Max2D : benötige ich, um später (vor Graphics) den Grafiktreiber zu setzen
brl.PNGLoader : ist dafür da, um Pixmaps im PNG format zu laden ???
Wieder Zitat von Lastmayday:
Zitat:
dadurch müsstest du auch den Render setzen:
<code>
SetGraphicsDriver D3D7Max2DDriver()
</code>
<code>
SetGraphicsDriver D3D7Max2DDriver()
</code>
Nun setze ich den Grafiktreiber (vor Graphics in der MainGame.bmx):
BlitzMax: [AUSKLAPPEN]
SetGraphicsDriver D3D7Max2DDriver()
Graphics BREITE , HOEHE , Vollbild 'Bildschirmmodus wird gesetzt
Anmerkung von mir: wenn ich den Grafiktreiber nicht setze, also den Befehl "SetGraphicsDriver D3D7Max2DDriver()" einfach weglasse... startet mein Programm trotzdem ohne zu meckern. Meine Frage nun an jemand, der sich auskennt: ist es unbedingt nötig, diesen Befehl zu benutzen, oder setzt BMAX den treiber automatisch, wenn der Befehl fehlt???
EDIT: ###############
Anmerkungen (Danke an Thunder, Lastmayday und BladeRunner)
Zitat:
- Das Modul D3D7Max2D führt den Befehl SetGraphicsDriver D3D7Max2DDriver() selbst aus, wenn der Treiber korrekt geladen wurde - es sollte also genügen einfach das Modul zu importieren.
Zitat:
Du kannst auch max2d, glmax2d, DX7, DX9 und opengl gesamt importieren. Was dich dann zu SetGraphicsDriver bringt.
Ein beispiel:
<code>
?Win32 'wird nur unter Windows gebaut
SetGraphicsDriver D3D9Max2DDriver()
?MacOS 'wird nur unter Mac gebaut
SetGraphicsDriver GLMax2DDriver()
?Linux 'wird nur unter Linux gebaut
SetGraphicsDriver GLMax2DDriver()
? 'wird wieder normal weiter kompiliert
</code>
so hättest du gleich für jedes OS den richtigen Render. Oder du könntest in den Optionen dem Spieler anbieten es selbst zu Bestimmen, um zum Beispiel Grafik Fehler zu beheben.
Ein beispiel:
<code>
?Win32 'wird nur unter Windows gebaut
SetGraphicsDriver D3D9Max2DDriver()
?MacOS 'wird nur unter Mac gebaut
SetGraphicsDriver GLMax2DDriver()
?Linux 'wird nur unter Linux gebaut
SetGraphicsDriver GLMax2DDriver()
? 'wird wieder normal weiter kompiliert
</code>
so hättest du gleich für jedes OS den richtigen Render. Oder du könntest in den Optionen dem Spieler anbieten es selbst zu Bestimmen, um zum Beispiel Grafik Fehler zu beheben.
Zitat:
Ich würde empfehlen unter Windows den dx9-Treiber zu verwenden, den Thunder schon in seinem Kommentar anführte. Smile
Unter Mac/Linux bist Du zwingend auf OGL angewiesen.
Unter Mac/Linux bist Du zwingend auf OGL angewiesen.
Ich werde dann auf dx9 umschwenken. Einfach folgendes ändern (in der MainGame.bmx)
brl.D3D7Max2D gegen brl.D3D9Max2D austauschen und
SetGraphicsDriver D3D7Max2DDriver() gegen SetGraphicsDriver D3D9Max2DDriver() austauschen.
END EDIT ###############
So, und hier mal wieder der komplette Code bis hier hin (inklusive .EXE)
die Größe des Downloads ist durch Framework und Import geschrumpft und beträgt nun nur noch feine 207 kb statt 671 kb
https://www.blitzforum.de/upload/file.php?id=9377
Wenn das so weiter geht... reicht mein Speicherplatz im Archiv bestimmt bald nicht mehr aus
Danke für die ganzen Tipps. Ich denke, ich habe heute eine Menge gelernt!!! *freu*