Die gute alte Tile engine, diesmal aber mit Arrays

Übersicht BlitzBasic Beginners-Corner

Neue Antwort erstellen

Neoxit

Betreff: Die gute alte Tile engine, diesmal aber mit Arrays

BeitragSa, Okt 01, 2011 11:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Heydiho meine lieben, lange nichts mehr geschrieben Smile

Nach meiner längeren Pause, habe ich mir vorgenommen mein altes Projekt "Grabber" wieder aufzunehmen und von Grund auf neu zu gestalten. Da es dort massige performanceverluste gab, da ich Types genutzt habe für jeden Tile und diese auch jedesmal auf kollision überprüft habe. Nun möchte ich es besser machen, heißt also ich möchte Arrays nutzen, nur habe ich wirklich keine ahnung wie genau ich Arrays in Kombination mit Types am besten nutzen kann. So, das ich sie später allerdings auch Präzise ansprechen kann, es mehr Tiles gibt als das Level auf einer Bildschirmgröße von 1600x900 anzeigt allerdings das was gesehen wird, über einen Array abgerufen wird. Ich habe hier bereits mal einen kleinen versuch gemacht was dies angeht. Jedoch möchte ich von euch vorher wissen, wie ich das alles nachher wirklich am schnellsten (im sinne von rechenleistung) umsetzen kann.


Code: [AUSKLAPPEN]

;Der Init part

;Types
Type TTile
   Field id,x,y,img,name$,desc$,passierbar,sammelbar
End Type


;Globals
Global tile_x = 32   ;Tile Weite
Global tile_y = 32   ;Tile Höhe

Global map_x = 51 ;Map weite
Global map_y = 51 ;Map höhe

;Array

Dim map.TTile(map_x-1,map_y-1)


Code: [AUSKLAPPEN]

;Der "Füllpart"
For x = 0 To screen_x/tile_x
   For y = 0 To screen_y/tile_y
      map.TTile(x,y) = New TTile
      map(x,y)\x = (x*tile_x)
      map(x,y)\y = (y*tile_y)
      map(x,y)\id = 1
      map(x,y)\img = img_block_01
   Next
Next


Code: [AUSKLAPPEN]

;Der Hauptschleifen Drawing Part
;LEVEL ZEICHNEN
For x = 0 To screen_x/tile_x
   For y = 0 To screen_y/tile_y
      
      DrawImage map(x,y)\img,map(x,y)\x,map(x,y)\y
      
   Next
Next



Ich nehme mal stark an das ich hier was die Koordinaten angeht, etwas doppelt gemoppelt habe.
Wie wäre eure Idee dazu? Wie gesagt, es geht mir hauptsächlich um präzision was die Tileansprache angeht (da diese im Spiel nachher abänderbar sein sollen) und auch sehr sehr wichtig um performance.

Falls ihr nicht wisst / nicht mehr wisst, was Grabber mal war auf http://neoxit.tumblr.com könnt ihr ein wenig weiter unten dies nachlesen Smile

Vielen Dank im Vorraus!

Xeres

Moderator

BeitragSa, Okt 01, 2011 11:39
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Reihenfolge, wenn du das Array durchgehst, könntest du noch optimieren:
Code: [AUSKLAPPEN]
For y = 0 To
For x = 0 To
Dann kann der Speicher linear abgearbeitet werden, ohne hin und her zu springen.
Koordinaten sind in der tat doppelt, eigentlich sollte sich alles über die Array ansprechen lassen. Einen Eintrag über die Koordinaten zu suchen ist nicht so prickelnd auf die Dauer.
Ansonsten nur zeichnen was im sichtbaren Bereich liegt... aber ich schätze, das weißt du. Wink
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

Neoxit

BeitragSa, Okt 01, 2011 11:46
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke dir Xeres Wink

Wie schaut das denn aus ich habe wie gesagt vorher nicht mit Arrays gearbeitet (Schande über mein Haupt Smile )

Bei Code: [AUSKLAPPEN]
DrawImage map(x,y)\img,map(x,y)\x,map(x,y)\y
spreche ich ja nun den Array an und die Koordinate des jeweiligen Type eintrages (der doppelte part).

Ich habe mir zwar gestern ca. 10 mal den Part mit Arrays und Types hier im Forum durchgelesen, aber irgendwie fällt mir das schwer das nur das Array anzusprechen. Im prinzip könnte ich doch auch den x,y wert von dem MapArray direkt auslesen können und dann mit der Tile länge / höhe multiplizieren oder so ähnlich? Nur wie würde ich das nun meinem kleinen Programm sagen? Ich hab mich in dem ganzen Type / Array kram glaube ich nämlich ein wenig verheddert :X

das wurgel

BeitragSa, Okt 01, 2011 12:07
Antworten mit Zitat
Benutzer-Profile anzeigen
Im Prinzip ist dein System genau richtig. Die Performance wird auch bei nahezu beliebig großen Karten gering bleiben, wenn du es richtig anstellst.

Das Problem mit den Kooridinaten ist zimlich einfach zu lösen, vielleicht hast du dich verheddert, weil es eigentlich garncicht zum Aspekt Array-Type-Kombi gehört, sondern eher zu tilemaps allgemein.

So grob ohne Scrolling:
Code: [AUSKLAPPEN]
DrawImage map(x,y)\img, x*tilesize, y*tilesize


Die x- und y- koordinate in dem Type schmeißt du am besten direkt raus, die wirst du eh nicht brauchen. Versuche nur dann die ganze Map durchzugehen wenn es unbedingt nötig ist, beim zeichnen brauchst du nur den ausschnitt der Karte zu zeichnen der im Bild liegt, bei Kollision noch weniger.
1 ist ungefähr 3

Neoxit

BeitragSa, Okt 01, 2011 12:56
Antworten mit Zitat
Benutzer-Profile anzeigen
okay das leuchtet mir nun alles noch besser ein Smile

Vielen dank ich werde mal schauen. Wenn ich dich richtig verstanden habe nutze ich einfach die Positionen unabhängig von dem Array/Type index sondern rechne sie simpel runter und greife somit auf diese zu?

Ich werde das mal so ausprobieren wie gesagt klingt logisch.

Vielen Dank bis hierin ersteinmal =)

ToeB

BeitragSa, Okt 01, 2011 14:59
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich würde außerdem bei den Tiles nicht die Tatsächliche X/Y-Position speichern, sondern den Platz im Array. Somit kann man auch schneller auf angrenzende Tiles zurückgreifen und das vereinfacht das ganze wieder etwas. Weiterhin wäre es auch sinnvoll, vor dem Malen zu prüfen ob das Tile an dem Punkt X/Y überhaupt <> Null ist. Denn so kannst du Tiles, die sowieso nur "Luft" darstellen sollen, direkt beim erstellen weglassen und hast somit keine Performance Probelme mehr Wink

mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!

Neoxit

BeitragSa, Okt 01, 2011 23:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke auch für deine Rückmeldung !

Die luft werde ich nachher allerdings als Block benötigen. Da auch dieser verschiedene Eigenschaften besitzen wird.

Und zum thema Tiles meinst du denke ich das er bei dem array Map(x,y) bspw: Map(2,3) wäre also bei einer Tilegröße von 32x32 der Tile auf x=64,y=96. So nehme ich an meintest du das, und ja das würde in der Tat noch einges vereinfachen und eine Rechnung entsprechend entfernen aus der Schleife.

Weitere Ideen bitte immer zu mir =)

Achja um kurz Rückmeldung zu geben, das was bisher gepostet wurde wurde umgesetzt und funktioniert nun auch ohne x,y in den Types. Und ansprechen kann man sie dann ja direkt über bspw Code: [AUSKLAPPEN]
map(15,15)/id = 0 ;du bist jetzt ein luftblock :D

BladeRunner

Moderator

BeitragSo, Okt 02, 2011 10:10
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn Du nur zeichnen willst was zu sehen ist musst Du wissen an welcher Position der Karte deine 'Kamera' sitzt und wieviele Tiles sie erfassen kann. Dann ist der Rest reine Mathe.
Beispiel: Deine Kamera sitzt über Tile 10,10.
Sichtbar sind 5*7 Tiles.
Dann sind die Tiles 10-2.5 bis 10+2.5 auf der X-Achse und
10-3,5 bis 10+3.5 auf der Y-Achse zu berechnen.
Da Brüche in Schleifen nicht funktionieren, rundest Du das Ganze noch. Damit werden eventuell eine Handvoll Tiles unnötigerweise berechnet, aber das ist zu verschmerzen.
Zu Diensten, Bürger.
Intel T2300, 2.5GB DDR 533, Mobility Radeon X1600 Win XP Home SP3
Intel T8400, 4GB DDR3, Nvidia GF9700M GTS Win 7/64
B3D BMax MaxGUI

Stolzer Gewinner des BAC#48, #52 & #92

Neoxit

BeitragSo, Okt 02, 2011 12:34
Antworten mit Zitat
Benutzer-Profile anzeigen
Okay ich verstehe schon wie du das meinst, meine frage dazu wäre nun eigentlich noch (da eine bildschirmgröße zu wenig ist für das spiel (definitiv zu wenig!)) wie ich nachher die Abfrage dafür mache was gezeichnet werden soll.

Vor allem wird die Mapgröße ja im Array gespeichert, und abgefragt wird sie dann denke ich mal durch 2 schleifen á X und Y.

Wie sieht das nachher für die Schleife aus?

Und an Blade, ich denke ich verstehe dich da schon ganz gut, habe dafür auch eine kleine veranschaulichung gemacht:

user posted image

Also nehme ich an ich muss auch den Map array so groß machen wie die map ansich ist heißt bspw. map(300,200) und dann auf den arraybereich zugreifen der relevant ist um diesen zu zeichnen. Heißt, wo meine Kamera ist in deinem Beispiel auf 10,10

Midimaster

BeitragSo, Okt 02, 2011 12:44
Antworten mit Zitat
Benutzer-Profile anzeigen
Hier mal ein Beispiel, wie man einen "Kamera-Ausschnitt" eines 90x90 Tiles großen Spielfeldes auf einen 400x400pix Bildschirm bringt. Du bewegst das ganze mit den Pfeiltasten. Jedes Tile ist 30x30pix groß.

Was in dem Beispiel fehlt, ist die Map[] selbst. Aber das kannst Du ganz leicht ergänzen. Eigentlich läuft die gesamte Kamerasteuerung immer ohne Berücksichtigung der Map[]. Die Map[] wird beim Zeichnen nur benötigt, um herauszubekommen, welches Image an der Zeichenposition zu zeichnen ist. (siehe auskommentierte Zeile)

BlitzBasic: [AUSKLAPPEN]
Graphics 400,400
SetBuffer BackBuffer()
Global Player_X#=500
Global Player_Y#=500

Const KEY_LEFT=203 , KEY_RIGHT=205 ,KEY_UP=200 ,KEY_DOWN=208

FPS=CreateTimer(60)
Repeat


; Spieler bewegen
If KeyDown(KEY_LEFT) Player_X =Player_X - 0.5
If KeyDown(KEY_RIGHT) Player_X=Player_X + 0.5
If KeyDown(KEY_UP) Player_Y=Player_Y - 0.5
If KeyDown(KEY_DOWN) Player_Y=Player_Y + 0.5
Cls

; Camera-Ecke festlegen
CameraPicture (Player_X-200 , Player_Y-200, 0)


;Umrandung malen
Color 111,111,111
Rect 0,0,900,30
Rect 0,370,900,30
Rect 0,0,30,400
Rect 370,0,160,400
Flip 0
WaitTimer fps
Forever

Function CameraPicture (CamX, CamY, OffX)
Color 1,99,1

; zeichnet den sichtbaren Teil der Map
For j=0 To 90
RealY=j*30-CamY
If RealY>0 And RealY<400
For I=0 To 90
RealX=i*30-CamX
If RealX>0 And RealX<400
Rect OffX + RealX , RealY , 29,29
; oder so:
;DrawImage Map[i,j]\img , OffX+RealX , RealY
EndIf
Next
EndIf
Next

; zeichnet den Spieler
Color 0,0,255
Oval OffX + Player_X-CamX , Player_Y-CamY ,15,15


End Function



In diesem Beispiel wird sogar darauf verzichtet schon auszurechnen, ab welcher Tile-Reihe die Tiles überhaupt erst in die Nähe des Bildschirms kommen. Vielmehr werden einfach alle 8100 Tiles in der FOR/NEXT aufgerufen, die sich aus der Position und der Kamera ergebenden realen Koordinaten erechnet. Und wenn die innerhalb des "Bildschirms" liegen wird gezeichnet:
BlitzBasic: [AUSKLAPPEN]
	For j=0 To 90
RealY=j*30-CamY
If RealY>0 And RealY<400
For I=0 To 90
RealX=i*30-CamX
If RealX>0 And RealX<400
;....

Die Performance bricht dadurch nicht ein.

Neoxit

BeitragFr, Okt 07, 2011 18:24
Antworten mit Zitat
Benutzer-Profile anzeigen
Sooooooo zurück aus Kiel Smile

Also hier haben wir mal meinen derzeitigen Fortschritt was die HAUPTSCHLEIFE angeht (also das Drawen ansich)

BlitzBasic: [AUSKLAPPEN]

If KeyDown(KEY_RIGHT) Then camera_x = camera_x + 1
If KeyDown(KEY_LEFT) Then camera_x = camera_x - 1
If KeyDown(KEY_UP) Then camera_y = camera_y - 1
If KeyDown(KEY_DOWN) Then camera_y = camera_y + 1


;LEVEL ZEICHNEN

x_screen = -tile_x ; Resette den Screen_zähler x auf -32 pixel
For x = (camera_x-50) To (camera_x+50) ;Tile X

x_screen = x_screen + tile_x ; Adde den Screen_zähler x um 32 Pixel
For y = (camera_y-28) To (camera_y+28) ; Tile Y
y_screen = y_screen + tile_y ; Adde den Screen_zähler y um 32 Pixel

;DrawImage baum\img,x_screen,y_screen
DrawImage map(x,y)\img,x_screen,y_screen
Text map(x,y)\name$,x_screen*32,y_screen*32

Next
y_screen = -tile_x ; Resette den Screen_zähler y auf -32 pixel
Next


Und hier hab ich noch ein ganz besonderes Herzstück, es wird für viele vllt sehr interessant sein was eine Rnd Levelgeneration angeht, ich weiß das es nicht die beste ist, aber meine Erste. Was sagt ihr dazu? Sollte man das etwas anders machen? (Daten werden später noch aus dateien automatisch ausgelesen)

BlitzBasic: [AUSKLAPPEN]

;/////////////////////////////////////////////
;//////(c) by Maik Pätzmann aka Neoxit////////
;/////////////////////////////////////////////
;///////Grabber//World//Generator/////////////
;/////////////////////////////////////////////

For x = 0 To (map_x-1) ; MAP (Nicht Kamera!)
For y = 0 To (map_y-1) ; MAP (Nicht Kamera!)
map.TTile(x,y) = New TTile

;Luft
If y <= (30+Rnd(4)) Then
map(x,y)\id = 0
map(x,y)\img = img_block_00
map(x,y)\name$ = "Luft"
map(x,y)\desc$ = "Luft"
map(x,y)\passable = 1
map(x,y)\mineable = 0
map(x,y)\liquid = 0

;Wasserspiegel
If y >= map_wasserspiegel And map(x,y)\id = 0 Then
map(x,y)\id = 9
map(x,y)\img = img_block_09
map(x,y)\name$ = "Wasser"
map(x,y)\desc$ = "Einfach nur Wasser"
map(x,y)\passable = 1
map(x,y)\mineable = 0
map(x,y)\liquid = 1
EndIf

Else

;Erde
map(x,y)\id = 1
map(x,y)\img = img_block_01
map(x,y)\name$ = "Erde"
map(x,y)\desc$ = "Einfache Erde, welche überall gefunden werden kann"
map(x,y)\passable = 0
map(x,y)\mineable = 1
map(x,y)\liquid = 0

;Grass
If map(x,(y-1))\id = 0 Then
map(x,y)\id = 2
map(x,y)\img = img_block_02
map(x,y)\name$ = "Grass"
map(x,y)\desc$ = "Grass welcher überirdisch gefunden werden kann"
map(x,y)\passable = 0
map(x,y)\mineable = 1
map(x,y)\liquid = 0
EndIf



EndIf

;Gestein
;EBENE 2
If y >= (50+Rnd(3)) Then

;ERZWERTE FESTLEGEN
map_create_kohle = Rnd(35)
map_create_eisen = Rnd(60)
map_create_kupfer = Rnd(70)
map_create_zinn = Rnd(70)

;Gesteinblock
map(x,y)\id = 3
map(x,y)\img = img_block_03
map(x,y)\name$ = "Einfaches Gestein"
map(x,y)\desc$ = "Einfaches Gestein der oberen Erdschicht"
map(x,y)\passable = 0
map(x,y)\mineable = 1
map(x,y)\liquid = 0


If map_create_kohle = 30 Then

;Kohleblock
map(x,y)\id = 4
map(x,y)\img = img_block_04
map(x,y)\name$ = "Steinkohle"
map(x,y)\desc$ = "Grundstoff für viele verschiedene Dinge und ein mittlerer Energieträger"
map(x,y)\passable = 0
map(x,y)\mineable = 1
map(x,y)\liquid = 0





;EBENE 3
ElseIf y >= (100+Rnd(5)) Then

If map_create_eisen = 30 Then

;Eisenblock
map(x,y)\id = 5
map(x,y)\img = img_block_05
map(x,y)\name$ = "Eisenerz"
map(x,y)\desc$ = "Eisenerz welches benötigt wird, um Metall herzustellen"
map(x,y)\passable = 0
map(x,y)\mineable = 1
map(x,y)\liquid = 0


;EBENE 4 - 5
ElseIf y >= (150+Rnd(15)) Then

;Granitblock
map(x,y)\id = 8
map(x,y)\img = img_block_08
map(x,y)\name$ = "Granit"
map(x,y)\desc$ = "Granit ist eine weitaus stabilere Gesteinsart"
map(x,y)\passable = 0
map(x,y)\mineable = 1
map(x,y)\liquid = 0

If map_create_kupfer = 30 Then

;Kupferblock
map(x,y)\id = 6
map(x,y)\img = img_block_06
map(x,y)\name$ = "Kupfererz"
map(x,y)\desc$ = "Kupfererz ist ein Rohstoff für viele Legierungen und Werkzeuge"
map(x,y)\passable = 0
map(x,y)\mineable = 1
map(x,y)\liquid = 0

EndIf

If map_create_zinn = 30 Then

;Zinnblock
map(x,y)\id = 7
map(x,y)\img = img_block_07
map(x,y)\name$ = "Zinnerz"
map(x,y)\desc$ = "Zinnerz ist ein Rohstoff für viele Legierungen"
map(x,y)\passable = 0
map(x,y)\mineable = 1
map(x,y)\liquid = 0

EndIf
EndIf
EndIf
EndIf


Next
Next


[EDIT]

Achja, Performance bei einer Map mit einem Array von 1000-x und 1000-y einträgen, 3-5 % auslastung.

Xeres

Moderator

BeitragFr, Okt 07, 2011 19:12
Antworten mit Zitat
Benutzer-Profile anzeigen
Du generierst viele male die gleichen Daten - das würde ich in eine Klasse/Extra Type umlagern:
BlitzBasic: [AUSKLAPPEN]
Type TTile_Class
Field name$,desc$,passierbar,sammelbar
End Type

Local Tile_Luft.TTile_Class = CreateTile_Class("Gras")
Local Tile_Wasser.TTile_Class = CreateTile_Class("Wasser")

Type TTile
Field Typ.TTile
End Type


;Luft
If y <= (30+Rnd(4)) Then
;Wasserspiegel
If y >= map_wasserspiegel Then
map(x,y)\typ = Tile_Wasser
Else
map(x,y)\typ = Tile_Luft
EndIf
;[...]
EndIf

Function CreateTile_Class.TTile_Class(n$,d$="",p=0,s=0)
Local t.TTile_Class = New TTile_Class
t\name = n
t\desc = d
t\passierbar = p
t\sammelbar = s
Return t
End Function

Die Referenz sollte deutlich weniger Speicher brauchen. Alles, was nur diesen einen Block betrifft, bleibt in TTile aber Dinge wie "Erde" und ob sie flüssig ist, sollten sich eigentlich nicht für Blöcke unterscheiden -> übergeordnete Struktur.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

Neoxit

BeitragFr, Okt 07, 2011 19:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Okay mit Klassen in diesem sinne habe ich irgendwie noch nie gearbeitet, aber man ist ja willig zu lernen nich wahr? =D

Ich werds mir mal anschauen und rumprobieren wie das genau funktioniert, gibts genau zu diesem bereich vllt eine richtig gute Erklärung? Ich meine Grundlegendes darüber?

Neue Antwort erstellen


Übersicht BlitzBasic Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group