2D Map Editor / Tile Engine von ???
Hi

Ich hab hier mal nen ganz simplen Map Editor gemacht. Ist wirklich nur sehr Simpel und die Map besteht nur aus Grafik Informationen, also keine Map mit mehreren Ebenen oder sowas.

Die Map kann geladen werden oder neu erstellt. Mit den Cursortasten kann
man die Map scrollen. Per Maus kann man die Tiles verändern (einfach draufklicken). Der Editor hat keinerlei Menu oder so und wird per Sourcecode konfiguriert ;)

Was vielleicht das besondere daran ist:
Viele Programmieren Maps mit Arrays, ich persönlich finde die Arrays einfach nicht so toll und manchmal verwirrend. Hab deswegen die Map mit nem Type programmiert.

Hier ist ein link zum downloaden des Editors inkl. Testmap und Tiles.

[url]http://www.zehr.de/bb/map_edit.zip[/url]


Und hier trotzdem mal den Code:

[code:1:130b43088b]
;--- Scroll Editor ------- by Jolinah ----

;Dieser Editor benutzt die Auflösung 800x600
;Die Tile grösse ist 40x40
;Es sollte nichts an der Auflösung oder der Tile grösse geändert werden
;da ich diese nicht mit Variablen programmiert habe.

;Wem dieser Code weiterhilft und ihn benutzen will kann das mit der Auflösung und
;den Tiles natürlich ändern sofern er weiss was er macht.

;Noch was über meinen Programmierstil ;)
;Ich weiss das mein Code vielleicht nicht der schönste ist, und ich denke manches hätte
;ich vielleicht auch einfacher machen können. Aber jeder macht das irgendwie auf
;seine Art, hauptsache man versteht den Code selbst noch.

;Trotzdem habe ich versucht den Code ein bisschen mit Kommentaren zu versehen
;und ein bisschen zu Strukturieren, damit ihr den Faden nicht so schnell verliert :p

;(c) gibt es nicht :), Der Code kann frei verwendet, verändert usw. werden.
;Ich bin froh falls ich mit dem Code jemandem weiterhelfen konnte.


;Grafikmodus 800x600 und Doublebuffering aktivieren.
Graphics 800,600,32,1
SetBuffer BackBuffer()


;Bilder
Global iGras = LoadImage("gfxgamegrass.bmp") ;Tile 1
Global iStein = LoadImage("gfxgamestein.bmp") ;Tile 2
Global iStein2 = LoadImage("gfxgamestein2.bmp") ;Tile 3
Global iBack = LoadImage("gfxgameack.bmp") ;Tile 4


;Types
Type Tile ;Viele Arbeiten mit Arrays (Dim), ich hab diesmal Type vorgezogen.
Field x,y
Field image
End Type

Global map.Tile

;Variablen
Global map_tiles_x = 40 ;Map besteht aus 40 Tiles in der X Achse. 2 Bildschirm, kann beliebig sein.
Global map_tiles_y = 30 ;Map besteht aus 30 Tiles in der Y Achse. 2 Bildschirm, kann beliebig sein.

Global scroll_x = 0 ;Scroll Startwerte für den Editor, am besten so lassen.
Global scroll_y = 0
Global scroll_x_max = (map_tiles_x * 40 * -1) + 800 ;Berechnet anhand der Tiles wie viel gescrollt
Global scroll_y_max = (map_tiles_y * 40 * -1) + 600 ;werden darf.

Global mapname$ = "mapsmap1.map" ;Map die geöffnet wird. "" für neue Map erstellen.

Global newmapname$ = "" ;Falls eine neue Map erstellt wird, hier den Dateinamen angeben.
;Die neue Map wird dann in dieser Datei gespeichert.

;Vorbereitungen...
If mapname$ <> "" ;Falls eine Map angegeben wurde, lade sie.
LoadMap(mapname$)
Else ;Wenn nicht, erstelle eine neue in der Grösse wie oben definiert.
NewMap()
EndIf

MoveMouse(400,300) ;Maus in die Mitte des Bildschirms bewegen.

;\ Haupt Programm Schleife \\\\\\\\\\\\\\\\\\\\
While Not KeyHit(1)
Cls

Gosub Drawtiles
Gosub Eingabe
Gosub Mouse

Flip
Wend


If mapname$ <> "" ; Wenn eine Map geladen wurde...
SaveMap(mapname$) ; Speicher die Map in der selben Datei.
Else ; Wenn eine neue Map erstellt wurde...
SaveMap(newmapname$) ; Speicher die Map in einer neuen Datei (welche oben angegeben wurde)
EndIf


SauberMachen() ; ;) Gibt den Speicher wieder frei.

End
;\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\



;-- Unterprogramme ----------------------------------------------------------------------------------


;- Zeichnet die Tiles --
.Drawtiles

For map.Tile = Each Tile
If mapimage > 0 And IsOnScreen(mapx,mapy)
Select mapimage
Case 1
DrawImage iGras, mapx + scroll_x, mapy + scroll_y

Case 2
DrawImage iStein, mapx + scroll_x, mapy + scroll_y

Case 3
DrawImage iStein2, mapx + scroll_x, mapy + scroll_y

Case 4
DrawImage iBack, mapx + scroll_x, mapy + scroll_y

Default

End Select
EndIf
Next

Return


;- Tastatureingabe und Scrollüberprüfung --
.Eingabe

If KeyDown(205)
scroll_x = scroll_x - 2
EndIf

If KeyDown(203)
scroll_x = scroll_x + 2
EndIf

If KeyDown(208)
scroll_y = scroll_y - 2
EndIf

If KeyDown(200)
scroll_y = scroll_y + 2
EndIf

If scroll_x < scroll_x_max Then scroll_x = scroll_x_max
If scroll_x > 0 Then scroll_x = 0
If scroll_y < scroll_y_max Then scroll_y = scroll_y_max
If scroll_y > 0 Then scroll_y = 0

Return

;- Mauseingaben und Sachen zeichnen die mit der Maus zusammenhängen --
.Mouse

For map.Tile = Each Tile
If MouseX() - scroll_x > mapx And MouseX() - scroll_x < mapx + 40 And MouseY() - scroll_y > mapy And MouseY() - scroll_y < mapy + 40
Color 255,255,255
Rect mapx + scroll_x,mapy + scroll_y,40,40,0
If MouseHit(1) Then CycleTile(map.Tile)
EndIf
Next

Color 255,0,0
Rect MouseX() -5,MouseY() - 5, 10, 10

Return




;-- Funktionen --------------------------------------------------------------------------------------

;- LoadMap -- Lädt eine Map -
Function LoadMap(datei$)
file = ReadFile(datei$)
If Not file Then Return

map_tiles_x = ReadInt(file)
map_tiles_y = ReadInt(file)

scroll_x_max = (map_tiles_x * 40 * -1) + 800
scroll_y_max = (map_tiles_y * 40 * -1) + 600

For map.Tile = Each Tile
Delete map.Tile
Next

For x = 1 To map_tiles_x
For y = 1 To map_tiles_y
map.Tile = New Tile
mapx = (x * 40) - 40
mapy = (y * 40) - 40
mapimage = ReadInt(file)
Next
Next

CloseFile(file)

End Function


;- SaveMap -- Speichert eine Map -
Function SaveMap(datei$)

file = WriteFile(datei$)
If Not file Then Return

WriteInt file, map_tiles_x
WriteInt file, map_tiles_y

For map.Tile = Each Tile
WriteInt file, mapimage
Next

CloseFile(file)

End Function


;- NewMap -- Erstellt eine neue (leere) Map -
Function NewMap()

For x = 1 To map_tiles_x
For y = 1 To map_tiles_y
map.Tile = New Tile
mapx = (x * 40) - 40
mapy = (y * 40) - 40
mapimage = 0
Next
Next

End Function


;- CycleTile -- Verändert das Tile (z.Bsp. wenn man mir der maus auf nem Tile klickt) -
Function CycleTile(t.Tile)
timage = timage + 1
If timage > 4 Then timage = 0
End Function


;- IsOnScreen -- Prüft ob ein Tile gezeichnet werden soll oder nicht -
; Tiles zu weit ausserhalb des Bildschirms sollen nicht gezeichnet werden -
Function IsOnScreen(x,y)
onscreen = True
If x * -1 > scroll_x + 40 Then onscreen = False
If x * -1 < scroll_x - 800 Then onscreen = False
If y * -1 > scroll_y + 40 Then onscreen = False
If y * -1 < scroll_y - 600 Then onscreen = False

Return onscreen
End Function


;- SauberMachen -- Gibt den Speicher wieder frei der bezogen wurde... -
Function SauberMachen()

FreeImage iGras
FreeImage iStein
FreeImage iStein2
FreeImage iBack

For map.Tile = Each Tile
Delete map.Tile
Next

End Function
[/code:1:130b43088b]
===
von ???
Hmmm es hat schon einen grund das viele Arrays nehmen: Das ist bei einer Tileengine schneller (ok, bei kleinen Maps ist es egal, aber wenn du Types nimmst wird das Programm bei riesigen Tilemaps sehr langsam da alle Tiles durchgegangen werden müssen. Bei Arrays kann man z.b. zum Zeichnen einfach nur die Tiles durchgehen die man sieht, so dass die Geschwindigkeit immer gleich ist) und viel einfacher. Außerdem kann man direkt auf ein Array zugreifen, was bei Types bei weitem nicht so einfach ist.

Beispiel:
Ändern eines Tile-Wertes bei Tile x|y zu z. (Die Tiles sind 32 Pixel groß)
[code:1:ab6af97b4e]
;Array:
map_array(x/32, y/32)=z

;Type:
for h.tile = each tile
if hx=x and hy=y then
hvalue=z
exit
Endif
Next
[/code:1:ab6af97b4e]

Bei nem Editor ist das noch nicht so dramatisch aber in einem Spiel sollte man das aus Geschwindigkeits und übersichtlichkeits Gründen doch lieber wie üblich mit den Arrays machen.
===
von ???
Hm, ok danke.


Dann werd ich wohl Arrays nehmen. Ich hatte da allerdings schon oft Probleme obwohl alle sagen das es einfacher ist als Types :).

Ausserdem hab ich im obigen Beispiel auch nur die Tiles gezeichnit die Sichtbar sind ;). Was aber stimmt ist das alle Tiles mit der Schleife immer wieder abgefragt werden müssen...

Vielleicht werd ich hier nochmal ein paar Fragen stellen falls ich mit den Arrays irgendwie an ein Problem stosse was ich zwar nicht hoffe :)

Ach ja die erste Frage kommt schon :)

Mit nem Type kann ich ja ziemlich einfach weitere Eigenschaften einbauen, wie zum Beispiel:

[code:1:a876fa9312]
Type Tile
Field x,y ; im array ja nicht nötig
Field image
Field sprengbar ;ob ein block gesprengt werden kann..
Field begehbar ;ob das tile begehbar ist..
End Type
[/code:1:a876fa9312]


Wie würde man das mit nem Array realisieren?


Natürlich könnte ich mit dem Begehbar auch 2 Map Ebenen machen,
die eine ist begehbar, die andere nicht. Aber wenn ich dann noch viele Zusätzliche Infos möchte....
===
von ???
Mit einem Array machst du es genauso

[code:1:159267c4c2]
Type T_Tile
field X
field Y
field Z
; --- usw
End Type

Dim Array.T_Tile(DimX,DimY)

for X=1 to DimX step 1
for Y=1 to DimY step 1
Array.T_Tile(X,Y) = New T_Tile
next
next
[/code:1:159267c4c2]
===
von ???
Dann versteh ich aber nicht wieso es dann auf diese Weise schneller laufen soll...

Jetzt hat man nicht nur 1 Instanz vom Type sondern für jedes Tile eine.

Oder ist das Tempo rein davon abhängig ob man halt nur 1 Eintrag hat oder ob man mehrere Einträge hat die mit ner Schleife durchgegangen werden?
===
von ???
Bingo. Das dauernde Durchlaufen verbraucht unheimlich viel Tempo. Für ein Array wird aber eine Liste von Pointern angelegt, so daß direkt auf die Speicherstelle zugegriffen werden kann.
===
von ???
Achso, danke.

Naja dann mach ich mich mal daran den Editor und das geplante Spiel umzuproggen oder neu zu proggen :)
===
von ???
Hab das ganze nun umgeproggt und benutze ein Array.



Suche:
(unterstützt mySQL Wildcards ala %)
Titel:
Text:
Autor: