Pixellandschaft im Worms-style

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

 

PhillipK

Betreff: Pixellandschaft im Worms-style

BeitragSa, Jun 18, 2011 11:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Halli hallo hallöle Smile

Ich arbeite nu schon ein paar Tage an der Unwissenheit, wie man Veränderbare Pixellandschaften ala Worms erstellt und bearbeitet.
Mein grundproblem ist, das TPixmap zu Zeichnen langsam ist und TImage zu wenig manipulierbar ist.

Die einzige Idee war, eine mischung zu verwenden. Und um häufiges auslesen der Pixmap zu vermeiden, die werte 'vereinfacht' in einem Array einzutragen.

Nun habe ich eine kleines Testprogramm geschrieben, welches eine Landschaft generiert und ein wenig veränderbar macht.
Dies habe ich für euch mal abgespeckt, damit ihr den groben Kern angucken + Kritisieren könnt.

BlitzMax: [AUSKLAPPEN]
SuperStrict

'Const für Bildbreite und höhe. Daraus zeichnet sich auf die Landschaft.
Const ResX:Int = 800
Const ResY:Int = 600

Type TLandschaft
Field image:TImage

Field width:Int = 0
Field Height:Int = 0

Field ground2:Byte[,]
Field changed:Int = 0

'Eine sicherheitsfunktion, die den Byte-wert des pixels wiedergibt.
'Entweder der Bytewert oder -1 für 'ausserhalb der map'
Method Ground:Int(x:Int, y:Int)
If x >= 0 And y >= 0 And x < Self.width And y < Self.Height Then
Return Self.ground2[x, y]
Else
Return - 1
End If
End Method

'Eine methode die mit simpler Technik ein TImage als hintergrundbild erstellt und die Bytewerte einliest.
Method New()
'Hiergrund: Weiß
SetClsColor(255, 255, 255)
Cls

Self.image = CreateImage(ResX, ResY)
SetLineWidth(6)
'Locals für die Forschleife
Local tmpX:Int = 0, tmpY:Int = ResY / 2, newY:Int

For tmpX = 0 Until ResX Step 3
'Schritt 1: Boden zufällig hoch zeichnen
SetColor(20, Rand(145, 155), 0) ' <- Grasfarbe. Etwas random.
newY = tmpY + Rand(-3, 3) '<-zufallshöhe
DrawLine(tmpX, tmpY, tmpX + 3, newY) '<- linienstück zeichnen. Smoothed den oberen teil etwas ab!

Local i:Int = 0
For i = tmpY + 1 Until ResY Step 3
If i - tmpY < Rand(15, 20) Then ' Füllung: Gras.
SetColor(20, Rand(145, 155), 0) 'Grasfarbe!
Else ' füllung: erde
SetColor(Rand(70, 90), Rand(40, 50), 0) ' Erdfarbe!
EndIf
DrawLine(tmpX, i, tmpX + 3, i + 3) ' Bodenteil zeichnen!
Next
tmpY = newY 'Start-y wird zum Rand-errechneten Y wert!
Next

'Boden zeichnen fertig: Grab image. Hintergrund ist im moment WEISS!
GrabImage(Self.image, 0, 0)



Self.width = image.pixmaps[0].width ' ein paar vars zwischenspeichern.
Self.Height = image.pixmaps[0].Height

Self.ground2 = New Byte[Self.width, Self.Height] ' Boden-bytearray anlegen.

Local x:Int = 0, y:Int = 0

For y = 0 Until Self.Height 'komplettes Bild durchgehen!
For x = 0 Until Self.width
'-1 ist weiß, 0 ist schwarz!
If Self.image.pixmaps[0].ReadPixel(x, y) = -1 Then 'abfrage: Pixel ist weiß. Das ist 'Luft' also durchlässtig -> Bytearray kriegt für X,Y eine 0.
Self.ground2[x, y] = 0
Self.image.pixmaps[0].WritePixel(x, y, $ff000000 | (147 Shl 16) | (246 Shl 8) | 255) ' Pixel auf blau ändern!
Else 'alles andere, Boden etc : kriegt eine 1!
Self.ground2[x, y] = 1
EndIf
Next
Next
'Fertig: Bild wurde in den Byte-array eingelesen und gemalt!

Self.image.SetPixmap(0, Self.image.pixmaps[0]) 'pixmap wieder ins bild "eintragen" <- nötig?
End Method


Method Draw()
'Ein Flag, den ich für änderungen nutze. wurde was an der landschaft gemalt, so wird die Pixmap neu eingelesen.
If Self.changed Then
Self.image.SetPixmap(0, Self.image.pixmaps[0])
Self.changed = 0
EndIf
'Landschaft zeichnen!
SetColor(255, 255, 255)
DrawImage(Self.image, 0, 0)
End Method
End Type

'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Graphics(ResX, ResY)

Global Landschaft:TLandschaft = New TLandschaft

Global counter:Int = 0

While Not KeyHit(KEY_ESCAPE)
Cls

'Testfunktion um 'editierbarkeit' der landschaft vorzuführen:
If MouseHit(1) Then Boom(MouseX(), MouseY())

Landschaft.Draw()

Flip 1

Wend

Function Boom(PosX:Int, PosY:Int)
Local radius:Int = 15
Local x:Int = 0, y:Int = 0

'Forschleife um den Umkreis des kreises festzustellen.
For y = PosY - radius - 4 To PosY + radius + 4
For x = PosX - radius - 4 To PosX + radius + 4
If Landschaft.Ground(x, y) = 1 Then 'dieser pixel ist boden!

'Distanzrechnung Per pythagoras, zum Zentrum des Clicks!
Local distanz:Float = Sqr(((y - PosY) * (y - PosY)) + ((x - PosX) * (x - PosX)))
'Distanz innerhalb von radius! Boden 'wegnehmen'
If distanz <= radius Then

Landschaft.image.pixmaps[0].WritePixel(x, y, $ff000000 | (147 Shl 16) | (246 Shl 8) | 255) 'himmel "reinmalen"
Landschaft.ground2[x, y] = 0 'byte-wert ändern!

'Distanz liegt knapp ausserhalb vom Radius-> Etwas abdunkeln - nur grafisch ne kleine änderung
ElseIf distanz <= radius + 4 Then
Local col:Int = Landschaft.image.pixmaps[0].ReadPixel(x, y)
Local newR:Int = (col & $00ff0000) Shr 16
Local newG:Int = (col & $0000ff00) Shr 8
Local newB:Int = (col & $000000ff)

If newR > 20 Then
newR = newR - 20
Else
newR = 0
EndIf
If newG > 20 Then
newG = newG - 20
Else
newG = 0
EndIf
If newB > 20 Then
newB = newB - 20
Else
newB = 0
EndIf

Landschaft.image.pixmaps[0].WritePixel(x, y, $ff000000 | (newR Shl 16) | (newG Shl 8) | newB)
EndIf
EndIf
Next
Next

'Last not least: Der landschaft mitteilen, das sie geändert wurde.
Landschaft.changed = 1

End Function


Grundidee:
Landschaft wird generiert und die Pixmap ausgelesen.
Je nach farbwert (Ich unterscheide zwischen Himmel und nicht-himmel) wird in einem Landschafts-internen 2D array ein wert eingetragen.

Nutzung:
Die Landschaft wird ganz normal als TImage gezeichnet.
Durch den Array kann ich feststellen, wo boden ist und wo nicht.
In meinem Programm hatte ich zb Strichmännchen die darauf gelaufen sind und eine Kanone, die auf Jene geschossen hat.
Traf ein geschoss den Boden -> Boden wegmachen (mit der funktion die im Abgespeckten programm nun 'Boom' heißt)
Traf es ein Menschlein, wurden Blutpixel "weggeschleudert" und, bei einem Treffer auf den Boden, oben draufgelegt.

Funktion:
Die Landschaft ist ein Bild, meine änderungen trage ich in die TImage.Pixmaps[0] - TPixmap ein.
Jedesmal, wenn ich das getan habe, setze ich Landschaft.changed = 1, welches die TImage.SetPixmap() funktion aufruft und an index 0 die Pixmap einträgt.
Zum verändern der Pixmap nutze ich nur TPixmap.WritePixel Sad

Da ist fraglich, ob das der Beste weg ist.

--------------

So, genug erklärt.
Jetzt seid ihr dran. Wie ist mein ansatz, die Landschaft zu verändern?
Denke ich zu kompliziert bezüglich der Pixmaps?
Gibt es einfachere wege, auf ein TImage zu zeichnen? Wäre es zb einfacher, das bild einfach neu zu Grabben, nachdem ich es verändert habe und den Ground2[,] array an der entsprechenden Zeichenstelle neuzubauen?
Hat sonst jemand soetwas schonmal umgesetzt? Wie waren eure ideen und Methoden?

Kritik ist erwünscht Razz

Gruß, PhillipK

mpmxyz

BeitragSa, Jun 18, 2011 13:36
Antworten mit Zitat
Benutzer-Profile anzeigen
So viel ich weiß, hat der Entwickler von Carnage Contest das Problem so gelöst, indem er das gesamte Spielfeld in kleinere Bilder aufgeteilt hat. Wenn dann nur die nötigen Bilder geändert werden, müssen nicht so viele Pixeldaten zur Grafikkarte geschickt werden. (Das macht nämlich das Ändern von Bildern ziemlich langsam.)
Man sollte außerdem die Bildpixmap anders bestimmen:
Mit "LockImage" bekommt man auch die Pixmap und das Bild weiß anhand der Parameter, ob die Pixmap verändert wurde/wird. Daher brauchst du dann keinen extra Zustand, dass du das Bild manipuliert hast, und musst außerdem keinen SetPixmap-Aufruf starten. Dadurch wird bei Bildern mit einer zu Maskierenden Farbe ein MaskPixmap-Durchlauf gespart. (Du kannst bei WritePixmap die Undurchsichtigkeit selbst bestimmen.)
Das Auslesen aus einer Pixmap sollte schnell gehen, da dort nur eine Adressenbestimmung und dann eine Fallunterscheidung für die verschiedenen Formate stattfindet.
Alternativ kannst du auch direkt auf den Pixmap-Speicher zugreifen. (Nachteil: Man verwendet hierbei Pointer und muss daher die Pixeladressen selbst bestimmen.)
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
 

PhillipK

BeitragSa, Jun 18, 2011 15:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Mhh, kleine Bilder, das klingt nach einem Plan.
Nur die frage, wie groß sollten diese bilder sein?
10x10 Pixelraster? Einzelne Landteile?

Ich tendiere, so nach dem ersten Lesen, zu 10x10 Pixel-rastern, bzw 8x8 / 16x16 / 32x32
Wobei ich die unteren und rechten ränder jeweils in Teilstücken belasse. Das LockImage ding muss ich mir nochmal angucken, das klingt nach einem Plan^^

Im moment isses ein wenig schlecht, aber ich werde mir heute oder morgen nochmal das ganze anschauen und das ein wenig umbasteln.
Wo ich grade drüber nachdenke, dürfte es unmenschlich lange dauern, 5000x5000 pixel-landschaften zu "erneuern" - grade weil die TPixmap erstmal zu einem TImage convertiert werden muss ^^

Goodjee

BeitragSa, Jun 18, 2011 16:15
Antworten mit Zitat
Benutzer-Profile anzeigen
im codearchiv gibt es ne implementierung die wimre 32x32 pixmaps benutzt
"Ideen sind keine Coladosen, man kann sie nicht recyclen"-Dr. House
http://deeebian.redio.de/ http://goodjee.redio.de/

coolo

BeitragSa, Jun 18, 2011 18:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Meine Tests für Gestrandet ergaben, dass 64*64 die besten Resultate liefern.

Aufjedenfall sollte es eine 2er Potenz sein (alles andere wäre reine Verschwendung).
http://programming-with-design.at/ <-- Der Preis ist heiß!
That's no bug, that's my project!
"Eigenzitate sind nur was für Deppen" -Eigenzitat
 

PhillipK

BeitragSa, Jun 18, 2011 23:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Man. ich bin neidisch, wie einige diese Zufälligen landschaften lösen.
Das sieht ganz krass nach DrawOval() aus, obwohls dennoch so willkürlich und ungleichmäßig aussieht.
Mein größtes problem ist dabei das Texturieren - im moment verwende ich noch Random-SetColor() befehle und kleine linienstücke, die fast Kreismäßig gemalt werden.
Wenn ich allerdings auf Texturen umsteige, wüsste ich nicht, wie ich die zusammenfüge :>

Meine erste intuition wäre: Erstmal erde, dann oberen Rand (mit ner abstandsprüfung zum rand?) und dann evtl noch einen unteren rand hinzuzeichnen.
Da kommt das problem der maske auf: Kann ich stücke der landschaft, evtl per Pixmap, so maskieren, das ich später weiß, was für eine Textur reinkommt?

Oder wäre es ein richtiger ansatz, die erstelle landschaft in 2 (mit unterem Rand 3) stücke aufzuteilen, jedes Image zu texturieren und übereinander zu zeichnen?
 

PhillipK

BeitragSo, Jun 19, 2011 18:05
Antworten mit Zitat
Benutzer-Profile anzeigen
Souu, habe die ersten Test abgeschlossen und stehe direkt wieder vor einem Problem.

Ich kann die genaue arbeitsweise von GrabImage und den Draw befehlen nicht wirklich feststellen.
Zuersteinmal habe ich versucht, ein großes 3200x3200 pixel TImage zu erschaffen, in mein fenster zu malen und das Bild zu grabben.
Das klappte allerdings nicht, was ich darauf schiebe, das grabimage von X,Y until Window Width und Height 'grabbt'.

Mein 2ter versuch wärs gewesen, das bild direkt auf 400 Timages zu grabben, welche je eine höhe und breite von den vorgeschlagenen 64x64 pixeln haben.
Doch auch das wollte nicht so ganz, da ich mit der Zeichnung enorme schwierigkeiten habe.
(Ps: Ich habe vorher mit SetViewPort() das bild auf 64x64 pixeln an koordinate 0,0 beschränkt und dort meine Zeichenoperationen vorgenommen. Danach per Grabimage() in das entsprechende Tile eingefügt.)

Welchen dieser beiden ansätze kann ich nun weiterverfolgen, um eine Landschaft, welche größer und breiter als mein eigentliches Fenster ist, in 20x20 kleine TImages zu zerteilen? (Zumal die auch nahtlos übergehen sollten Smile )

--------------------

Edit 20.06.2011 - 06:47:

Ich kriegs einfach nicht hin, die landschaft in 64x64 pixel-bilder aufzuteilen (bzw so zu erzeugen), sodass sie auchnoch Nahtlose übergänge hat.
Mich regts tierisch auf, das es unter Bmax kein Rendern auf Image gibt Sad
Und dieses doofe drawzeug malt nur innerhalb des bildschirms Very Happy

Es ist einfach, eine landschaft zu erzeugen, und diese danach zu unterteilen. Da ich aber landschaften > bildschirmbreite/höhe anpeile (testzwecke halt ^-^), verlaufe ich mich die ganze zeit in meinen abfragen.

Meine bisherigen versuche laufen darauf hinaus, das ich mir die Koordinaten vorstelle, jeweils im bereich0,0,64,64 zeichne und die Bildslots ausrechne.
Das haut aber alles nicht hin, ist zu langsam, etc etc etc.

Ich brauche einen neuen ansatz.

Hat irgendwer einen vorschlag? Sad

Gruß, ein *verzweifelter* Phillipk

mpmxyz

BeitragMo, Jun 20, 2011 9:23
Antworten mit Zitat
Benutzer-Profile anzeigen
Wie sieht denn dein aktueller Code aus? (wenn möglich etwas, was man auch testen kann)
Denn nach dem vergleichsweise langem Zeichnen am Anfang, sollte das System schnell sein.
Zu deinem Zeichenproblem:
Nutzt du nun SetOrigin? Damit kannst du die Verschiebung sehr elegant lösen.
Du musst notfalls mehrfach zeichnen. (Das geht aber im Gegensatz zum Hochladen von Texturen auf die Grafikkarte schnell, wenn du größere Ausschnitte, die mehrere Bilder enthalten, zusammenfasst.)
mfG
mpmxyz
Moin Moin!
Projekte: DBPC CodeCruncher Mandelbrot-Renderer
 

PhillipK

BeitragMo, Jun 20, 2011 10:04
Antworten mit Zitat
Benutzer-Profile anzeigen
Im moment habe ich garnichts.

So frustierend wie das ganze war, hab ich immer hardcore gelöscht.

Ich kann nur grob die idee zusammenfassen, die ich verfolgt hatte:

BlitzMax: [AUSKLAPPEN]

SetViewport(0,0, 64,64)

Local teile:TImage[,] = New TImage[20,20]

For Local img:TImage = EachIn teile; img = CreateImage(64,64); Next

Local tmpX:Int,tmpY:Int = 32 'Koordinaten angabe.
Local slotX:Int = 0, slotY:Int = 10 ' Slot angabe für den teile - array

Local oldSX:Int = 0, oldSY:Int = 10 'Alte slotsangaben, um festzustellen, wann ein grab nötig ist.

Local newY:Int = 0 ' ein merker für die errechnete Y koordinate

For tmpX = 0 Until 64*20 Step 4 'eine Schleife, die meine Pixel auf der X koordinate durchgeht.
slotX = tmpX / 64 ' slotX sollte aufgrund der Int() abrundung passen!
slotY = tmpY / 64 ' slotY sollte aufgrund der Int() abrundung passen!

If oldSX <> slotX Or oldSY <> slotY Then
GrabImage(teile[oldSX,oldSY], 0,0)
Cls
EndIf

'Schritt 1: Nächste Y koordinate errechnen.
newY = tmpY + Rand(-2,2)

'Schritt 2: Nächstes Linienstück zeichnen.
DrawLine(tmpX Mod 64, tmpY Mod 64, (tmpX Mod 64) + 4, (newY Mod 64))

tmpY = newY




Mh, das habe ich grade aus dem Kopf geschrieben, aber so etwa habe ich es versucht.

Ansatz: Ich versuche lediglich ersteinmal eine Zufällige linie über die Map zu zeichnen. Dazu nutze ich den Random-errechneten Wert für Y, einen X-Koordinaten zähler der von 0 until Landschaft.Width() zählt, sowie Modulardivision um die koordinate auf das eigentlich 64x64 feld runterzurechnen.
Das aktuelle bildstück bestimme ich durch eine normale Division, welche aufgrund der Integer-abrundung stimmen sollte.
In dem beispiel SOLLTE die grobe logik stimmen, es fehlen lediglich noch abgleiche, ob im Teile[,] ein Array index out of bounds auftreten könnte.

Die idee mit SetOrigin hat mich grade auf die idee gebracht, das ich mit meinen SlotX und SlotY den origin errechne.
Etwa so: SetOrigin(-(SlotX*64), -(SlotY*64), das die modular division spart und somit evtl eine fehlerquelle ausmerzt Smile Smile

-------

Edit 20.06.2011 - 11:40

So, ich habe nun mal ein bissl getippert.
Ist zwar ziemlich peinlich, weil ich so dreckig programmiere, aber naja ^^

BlitzMax: [AUSKLAPPEN]
SuperStrict

Graphics 800, 600

Local land:TImage[,] = New TImage[20, 20]

Local initX:Int = 0, initY:Int = 0
For initX = 0 Until 20
For initY = 0 Until 20
land[initX, initY] = CreateImage(64, 64)
Next
Next

SetViewport(0, 0, 64, 64)

Local tmpX:Int, tmpY:Int = 64 * 10 + 32 'Koordinaten angabe.
Local slotX:Int = 0, slotY:Int = 10 ' Slot angabe für den teile - array

Local oldSX:Int = 0, oldSY:Int = 10 'Alte slotsangaben, um festzustellen, wann ein grab nötig ist.

Local newY:Int = 0 ' ein merker für die errechnete Y koordinate
SetClsColor(128, 128, 128)
Cls
SetColor(255, 0, 0)
For tmpX = 0 Until 64*20 Step 4 'eine Schleife, die meine Pixel auf der X koordinate durchgeht.
slotX = tmpX / 64 ' slotX sollte aufgrund der Int() abrundung passen!
slotY = tmpY / 64 ' slotY sollte aufgrund der Int() abrundung passen!

SetOrigin(slotX * 64, slotY * 64)

If oldSX <> slotX Or oldSY <> slotY Then
GrabImage(land[oldSX, oldSY], 0, 0)
Print "SlotX: " + slotX + " SlotY: " + slotY + " OldY: " + oldSY + " OldX: " + oldSX
oldSX = slotX
oldSY = slotY
Cls
EndIf

'Schritt 1: Nächste Y koordinate errechnen.

If slotY < 2 Then 'nach unten weitermachen!
newY = tmpY + Rand(1, 3)
ElseIf slotY > 18 Then 'nach oben weitermachen!
newY = tmpY + Rand(-3, -1)
Else 'normales rand!
newY = tmpY + Rand(-2, 2)
EndIf

'SetColor(100, 100, 100)
'DrawRect(0, 0, 64, 64)
'SetColor(255, 0, 0)
'Schritt 2: Nächstes Linienstück zeichnen.
DrawLine(tmpX, tmpY, (tmpX) + 4, (newY))

tmpY = newY

Next

SetOrigin(0, 0)
SetViewport(0, 0, 800, 600)
SetClsColor(0, 0, 0)
Local oriX:Int = 0, oriY:Int = 0


While Not KeyHit(KEY_ESCAPE)

oriX:+KeyDown(KEY_A) * 10 - KeyDown(KEY_D) * 10
oriY:+KeyDown(KEY_W) * 10 - KeyDown(KEY_S) * 10

SetOrigin(oriX, oriY)
Cls
Local posX:Int, posY:Int

SetColor(255, 255, 255)

For posY:Int = 0 Until 20
For posX:Int = 0 Until 20

DrawImage(land[posX, posY], posX * 64, posY * 64)

Next
Next
SetBlend(ALPHABLEND)
SetAlpha(0.5)
SetColor(0, 255, 255)
For posY:Int = 0 Until 20
For posX:Int = 0 Until 20


DrawLine(posX * 64, posY * 64, (posX + 1) * 64, posY * 64)
DrawLine(posX * 64, posY * 64, posX * 64, (posY + 1) * 64)
DrawLine((posX + 1) * 64, posY * 64, (posX + 1) * 64, (posY + 1) * 64)
DrawLine(posX * 64, (posY + 1) * 64, (posX + 1) * 64, (posY + 1) * 64)
Next
Next
SetAlpha(1.0)
SetBlend(MASKBLEND)

Flip 1
Wend


Wie es funktioniert:

Am anfang wird ein Tile-TImage array initialisiert und dann anhand diverser DrawLine() befehle gefüllt. Sollte zumindest.
Mit WSAD kann man bei Laufzeit SetOrigin() verstellen und sich die landschaft so 'angucken'

Im über das raster werden 4 linien gezeichnet, die anzeigen, wo ein Bildstück sein sollte.

Mittig auf der Y achse erkennt man eine große grade fläche, das sind bilder die mit DrawLine() bemalt worden sein sollten, sind sie aber nicht -.-
Die graue farbe kommt durch das SetclsColor() was ich debugweise auf grau eingestellt hab. Dh alles was einen grauen hintergrund hat, wurde von meiner Zeichenroutine bearbeitet und am ende gegrabbt.

Ich vermute einen denkfehler dort, wo ich das image grabben wollte.

Midimaster

BeitragMo, Jun 20, 2011 13:15
Antworten mit Zitat
Benutzer-Profile anzeigen
ich würde dir gerne auch helfen, aber ich verstehe immer nur "bahnhof" bei dem, was du da schreibst....

ich verstehe schon dein Problem nicht:

Bekommst du es nun nicht hin eine Landschaft zu malen?

oder

Bekommst Du es nicht hin, diese Landschaft zu grabben?

oder

Bekommst Du es nicht hin, diese Lanschaft wieder anzuzeigen?


Im ersten Beitrag hattest du doch schon etwas abgeliefert, was schon sehr ordentlich aussah. Wo war dein Problem dabei? War es dein Code?

Ich kann auf dem Programm, das du zuletzt eingestellt hast nicht wirlkich etwas Sinnvolles erkennen...
Vielleicht solltest Du Deine Probleme in Teilbereiche aufsplitten und jeden für sich lösen.


Das mit dem Grabben ist doch ganz einfach. Ich hab da neulich jemandem im engl. Forum geholfen:


im ersten code scrollt eine Landschaft waagrecht:
BlitzMax: [AUSKLAPPEN]
SuperStrict
Graphics 600,400
Global BackGround:TImage[100] , Position%
'
' this is only to simulate a set of 100 background strips:
' you will replace this with a set of (3-100) images
' For i%=0 to 99
' BackGround[i]=Loadimage(....
' Next
'
Local NewRandom#, LastRandom#, i%
LastRandom=250
SeedRnd MilliSecs()
For I% = 0 To 99
'sky
SetColor 0,0,55
DrawRect 0,0,10,300
'stars
SetColor 255,255,255
For Local j%=0 To 5
Plot Rand(0,10),Rand(0,300)
Next
'gras
SetColor 0,55,0
DrawRect 0,300,10,400
'mountain
SetColor 111,111,111
NewRandom = Rnd(LastRandom-10,LastRandom+10)
If NewRandom>300 Then NewRandom=300
Print NewRandom
If I=99 Then NewRandom=250
Local tri#[]=[0.0,300.0 , 10.0,300.0 , 10.0,NewRandom , 0.0,LastRandom]
DrawPoly Tri
SetColor 255,255,255
LastRandom = NewRandom
BackGround[i]=CreateImage(10,400,DYNAMICIMAGE)
GrabImage BackGround[i],0,0
Next


' here is the main program:

Global WorldWidth%=1000
Global NumberOfStrips%=100
Global StripWidth%=10
Repeat
Cls
Position = (Position+1) Mod WorldWidth
Print Position
For Local i%=0 To NumberOfStrips-1
Local ImagePos% = -Position + i*StripWidth
If ( ImagePos > -StripWidth ) And ( ImagePos<600 )
DrawImage Background[i] , ImagePos, 0
EndIf
If ( WorldWidth+ImagePos > -StripWidth ) And ( WorldWidth+ImagePos < 600 )
DrawImage Background[i] , WorldWidth+ImagePos , 0
EndIf
Next
Flip
Until KeyHit(Key_Escape)


im ersten code scrollt eine Landschaft in beide Richtungen (von oben gesehen):
BlitzMax: [AUSKLAPPEN]
SuperStrict
Graphics 600,400
Global tiles:TImage[20,20] , PositionX% , PositionY%
'
' this is only to simulate a set of 400 tiles:
' you will replace this with a set of tiles of your images
' For i%=0 to 19
' For j%=0 to 19
' Tiles[i,j]=Loadimage(....
' Next
' Next
'
Local NewRandom#, LastRandom#, i% , j%
LastRandom=250
SeedRnd MilliSecs()
For I% = 0 To 19
For j% = 0 To 19
Cls
SetColor Rand(200),Rand(100,200),Rand(200)
DrawRect 0,0,100,100
Tiles[i,j]=CreateImage(100,100,DYNAMICIMAGE)
GrabImage Tiles[i,j],0,0
Next
Next


' here is the main program:

Global WorldWidth%=1000
Global NumberOfTiles%=20
Global StripWidth%=100
Repeat
Cls
PositionX = (PositionX+1) Mod WorldWidth
PositionY = (PositionY+1) Mod WorldWidth
Print PositionX
For Local i%=0 To NumberOfTiles-1
Local ImagePosX% = -PositionX + i*StripWidth
If ( ImagePosX > -StripWidth ) And ( ImagePosX<600 )

For Local j%=0 To NumberOfTiles-1
Local ImagePosY% = -PositionY + j*StripWidth
If ( ImagePosY > -StripWidth ) And ( ImagePosX<600 )
DrawImage Tiles[i,j] , ImagePosX, ImagePosY
EndIf
Next
EndIf
Next
Flip
Until KeyHit(Key_Escape)



da mußt du eigentlich nur noch sinnvolle Grab-Bilder erstellen.

So nun schreib mal, was man da noch verändern müßte, bis es zu deinem Projekt passt.

Wir finden sicherlich eine Lösung!
 

PhillipK

BeitragMo, Jun 20, 2011 17:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo Midimaster!

Nun, das ding aus meinem ersten Beitrag war ein 'komplettes' bild.

Die überlegung, das eine größere Landschaft zu updaten sicherlich enorm leistung braucht, hatte ich nicht getätigt.
Nun wurde mir nahe gelegt, die Landschaft in mehrere Bildchen aufzuteilen, wie es in anderen Bmax spielen auch getan wird.
Doch genau hier ist der Knackpunkt - es will mir einfach nicht nicht in den Kopf rein, wie ich die Landschaft ordentlich zeichnen kann.

Ich habe diverse Tests gemacht, immer habe ich irgendwo kleinere Probleme.

Als neuste lösung versuche ich nun, ein Landschafts-type zu schreiben, was Untergeordnete Tile-Types enhtält, mit angaben, wie ich die Landschaft aufbauen muss.
Darüber hinaus werde ich die Draw-befehle neuschreiben, welche alle betreffenden Bilder bemalen.
Das ganze ist allerdings Zukunftsmusik, in Wahrheit habe ich immernoch keine ahnung, wie ich Nahtlose Landschafts-tiles erstelle.

----

Nun mal übergeordnet das erste Problem:

Wie unterteile ich die Landschaft? Anfangs größere bildteile zeichnen und sie zb in 3x3 kleinere Bilder zerschneiden, ränder zum neuen Bereich wieder Zeichnen und weiter Zeichnen?
ODer direkt auf die 64x64 pixel-kacheln gehen und versuchen, die übergänge darzustellen? Sad

Edit:

Deinen Beispielcode kann ich grade nicht durcharbeiten, bin ein wenig fertig und meine Freundin hat Priorität Smile Aber ich guck ihn mir bei gelegenheit noch an! Smile

Midimaster

BeitragMo, Jun 20, 2011 18:16
Antworten mit Zitat
Benutzer-Profile anzeigen
kannst Du denn die Landschaft (rein theoretisch) bereits endlos weiterzeichnen?

Wir machen das jetzt schrittweise:

Zeichne von der Landschaft einen kompletten Bildschirm 1280x1024 voll. Daraus grappst Du gleich mal 1 Bild a 64x64pix. Nämlich bei 0/0!


Gelingt Dir das?


Dann mach es so weiter:

Zeichne von der Landschaft einen kompletten Bildschirm 1280x1024 voll. Daraus grappst Du gleich mal 80 Bilder a 64x64pix. Nämlich 10 waagrechte x 8 senkrechte.


Gelingt Dir das?


Dann mach es so weiter:

Zeichne von der Landschaft einen kompletten Bildschirm 1280x1024 voll, aber ziehe von den X-Koordinaten vor dem Zeichnen immer 1280 ab, male dafür bis X=2560.


Gelingt Dir das?


P.S.

eine Frage hast Du noch nicht beantwortet, es ist aber wichtig für die weitere Arbeit: War dein erster Code-Beitrag von Dir alleine geschrieben worden?
 

PhillipK

BeitragMo, Jun 20, 2011 20:02
Antworten mit Zitat
Benutzer-Profile anzeigen
So.
Ich kann zwar immernochnicht weiterarbeiten, war aber gespannt auf weitere Antworten Smile

Dein Step-by-Step werde ich wohl morgen früh mal durcharbeiten. Ich fürchte fast, damit wirds klappen, obwohl ich grade im ersten moment schmunzeln musste.
Ich halte leider recht viel auf meine fähgikeiten, die quasie überall nur ansatzweise bestehen. Ich denke ich übersehe wieder ein paar kleinere Details. Nun, ich überwinde meinen stolz und lasse mich an die Hand nehmen Smile

Und ja, der erste Code ist komplett selbstgeschrieben.
Es ist ein Bruchstück eines Test-spiels was ich geschrieben hatte, um mir eine Idee der Kollision auf Selbstgemalter Pixellandschaft zu realisieren. Die echtzeitmanipulation von Pixellandschaften wie in Worms und Carnage Contest haben mich schon länger fasziniert Smile Smile

Gruß, Phillipk

Midimaster

BeitragMo, Jun 20, 2011 20:05
Antworten mit Zitat
Benutzer-Profile anzeigen
ich hab da noch was für dich:

BlitzMax: [AUSKLAPPEN]
Graphics 800,600
Global LastY%=64
Global Zeit%
SetLineWidth 6
Global OffX%
Global Tile:TImage[1000]
Repeat
Cls
If OffX Mod 8=0
MalAbschnitt Nr
nr=nr+1
EndIf

SetColor 255,255,255
For Local i%=0 To nr-1
DrawImage Tile[i],i*8+780-OffX,300
Next
offx=offX+1
Flip 0
Until KeyHit(Key_Escape)

End

Function MalAbschnitt(Nr%)

Local i%, X% , Y% , Zeit%

Zeit=MilliSecs()
Tile[Nr]=CreateImage(8,128)
For X=0 To 8 Step 3
SetColor 20, Rand(145, 155), 0
Y = LastY + Rand(-3, 3)
DrawLine X, LastY, X + 3, Y

For i = Y + 1 To 128 Step 3
If i - Y < Rand(15, 20) Then
' Gras.
SetColor 20, Rand(145, 155), 0
Else
' Erde
SetColor Rand(70, 90), Rand(40, 50), 0
EndIf

DrawLine X, i, X+3, i+3
Next
LastY = Y
Next
GrabImage Tile[Nr],0,0

End Function


 

PhillipK

BeitragDi, Jun 21, 2011 5:57
Antworten mit Zitat
Benutzer-Profile anzeigen
So, Master Midimaster Wink

Ich habe mich einmal an die Arbeit gemacht.
Habe ein Programm geschrieben, was eine Simple Landschaft Zeichnet und sie als großes Bild abpacket.
Danach wird jedes Tile davon gegrabbt (hab dem extra eine Methode gegönnt Razz)

Hier der Code:
BlitzMax: [AUSKLAPPEN]
SuperStrict

'2 Globale, zum verändern der Bilschirmbreite / Höhe
Global ResX:Int = 1280, ResY:Int = 960

ResX = ResX - (ResX Mod 64) 'sicherstellen, das die Auflösung durch 64 teilbar ist!
ResY = ResY - (ResY Mod 64)

Graphics ResX, ResY ' init der Grafic

Global Land:TLandschaft = New TLandschaft ' Neue landschaft - yay!

Global oriX:Int = 0, oriY:Int = 0 '2 variablen zum verschieben der SetOrigin() koordinaten!
Global ZeigeModus:Int = 0 'mit ENTER umschaltbar - Soll zwischen 'Gesamtbild' und 'TileBilder'-drawing umschalten!

'#################################################
'Zurücksetzen der einstellungen, falls benötigt.
SetOrigin(0, 0)
SetColor(255, 255, 255)
SetClsColor(0, 0, 0)

'#################################################
'init abgeschlossen - Die Teile Grabben!
Local posX:Int = 0, posY:Int = 0
For posX = 0 Until ResX Step 64
For posY = 0 Until ResY Step 64
Land.GrabTile(posX, posY)

Next
Next

'#################################################
'Hauptschleife :)
While Not KeyHit(KEY_ESCAPE)
Cls

'Auf druck von ENTER wird ZeigeModus zwischen 0 und 1 umgeschaltet.
If KeyHit(KEY_ENTER) Then ZeigeModus = 1 - ZeigeModus

'Anhand von Zeigemodus wird entweder das komplette Bild gemalt, oder seine Tiles.
If ZeigeModus = 0 Then
DrawImage(Land.Komplett_Bild, 0, 0)
Else
Local x:Int = 0, y:Int = 0
For x = 0 Until ResX / 64
For y = 0 Until ResY / 64
'Das Rect ist zum Debuggen: Es zeichnet etwas über den Rand eines Tiles hinaus, sodass später Linien sichtbar bleiben, wo das Tile denn ist.
DrawRect(x * 64 - 2, y * 64 - 2, 68, 68)
DrawImage(Land.ImgTeile[x, y], x * 64, y * 64)
Next
Next
EndIf
Flip 1
Wend

Type TLandschaft
Field Komplett_Bild:TImage = CreateImage(ResX, ResY) ' Hält testweise meine gesamte 'Landschaft' als Bild.
Field ImgTeile:TImage[,] = New TImage[ResX / 64, ResY / 64] ' Hält die Tiles der 'Landschaft'

Field FirstY:Int = 0 '2 Zeiger für Testzwecke später, grund: Weiterzeichnen der Landschaft.
Field LastY:Int = 0

'############################################
'New: Generiert die Landschaft und Initialisiert die ImgTeile-TImages
Method New()
'Generieren der Landschaft, direkt ins New() rein!
SetClsColor(60, 150, 255)
Cls

'Variablen. Ich deklariere sie IMMER vor for-schleifen,das spart einfach Zeit :)
Local slotX:Int = 0, slotY:Int = 0

'Init der Bildteile um ein Nullobj vorzubeugen.
For slotX:Int = 0 Until ResX / 64
For slotY:Int = 0 Until ResY / 64
Self.ImgTeile[slotX, slotY] = CreateImage(64, 64)
Next
Next

'Variablen. Mal wieder.
Local posX:Int = 0, oldY:Int = ResY * 0.75, newY:Int = 0

Self.FirstY = oldY 'einen zeiger den ich halte, um die landschaft evtl nach links weiterzuzeichnen und damit einen "weicheren" übergang zu schaffen.

'Schritt1: Boden!
SetLineWidth(10)

'Idee: Grobes durchspringen der X koordinate um hier und da mal ein stück boden zu malen. Nicht wirklich wild, nicht wirklich wichtig.
' nur eine Simple routine die irgendwas Sichtbares Zeichnet
For posX = 0 Until ResX Step 8
SetColor(0, Rand(220, 240), 0) ' RandomColor - ich steh einfach drauf :)
If posX Mod 16 = 0 Then
newY = oldY + Rand(1, 3)
Else
newY = oldY + Rand(-3, -1)
End If


'DrawLine zeichnet die Gras'oberfläche'
DrawLine(posX, oldY, posX + 8, newY)
oldY = newY
'Und draw Rect zeichnet das Bodenstück darunter, bis zum Boden!
DrawRect(posX, oldY + 3, 8, ResY - oldY)
Next

'Alles fertig? Okay, dann mal als Komplettbild grabben!:)
GrabImage(Self.Komplett_Bild, 0, 0)

Self.LastY = newY 'ein weiterer Zeiger, diesmal zum zeichnen nach rechts.

End Method

Method GrabTile(posX:Int, posY:Int)
'Diese Method soll mir ein Teilstück des bildes Grabben!
SetOrigin(-posX, -posY) 'das 'Tile' an die obere Linke ecke zeichnen..
SetViewport(0, 0, 64, 64) '.. und dieses Tile auf 64x64 eingrenzen, Per Viewport.
Cls
DrawImage(Self.Komplett_Bild, 0, 0)
GrabImage(Self.ImgTeile[posX / 64, posY / 64], 0, 0) 'Grabben - die Division sollte den entsprechenden Slot errechnen.

'Und natürlich wieder zurücksetzen =)
SetOrigin(oriX, oriY)
SetViewport(0, 0, ResX, ResY)
End Method
End Type



Hinweise:
Im Mainloop gibt es 2 Drawmöglichkeiten - Bildteile einzeln zeichnen oder das Komplettbild.
Umgeschalten wird mit einem druck auf ENTER - dann sollten weiße Linien zu erkennen sein, welche um die Kacheln rum gezeichnet wurden (DrawRect mit x-2,y-2, width=68 und height=68!)

Das Ganze baut auf 2 Variablen auf, ResX und ResY - leider konnte ich sie nicht Konstant machen, da ich sie evtl ändern muss. Sie werden auf die nächstmögliche vielfache von 64 'runtergerechnet'- einfach irgendwas eintragen Smile
Res steht für 'Resolution' - bedeutet auflösung. Array-größe und slots etc werden damit berechnet.

GrabMethode:
Zum grabben habe ich 2 Programmteile.
BlitzMax: [AUSKLAPPEN]
Local posX:Int = 0, posY:Int = 0
For posX = 0 Until ResX Step 64
For posY = 0 Until ResY Step 64
Land.GrabTile(posX, posY)

Next
Next


Das ruft meine Grabmethode auf.

posX und posY werden immer ein vielfaches von 64 sein, aufgrund des Step parameters.

Und das hier:
BlitzMax: [AUSKLAPPEN]
	Method GrabTile(posX:Int, posY:Int)
'Diese Method soll mir ein Teilstück des bildes Grabben!
SetOrigin(-posX, -posY) 'das 'Tile' an die obere Linke ecke zeichnen..
SetViewport(0, 0, 64, 64) '.. und dieses Tile auf 64x64 eingrenzen, Per Viewport.
Cls
DrawImage(Self.Komplett_Bild, 0, 0)
GrabImage(Self.ImgTeile[posX / 64, posY / 64], 0, 0) 'Grabben - die Division sollte den entsprechenden Slot errechnen.

'Und natürlich wieder zurücksetzen =)
SetOrigin(oriX, oriY)
SetViewport(0, 0, ResX, ResY)
End Method


Ist meine 'vorerst' lösung zum Grabben.
Ich habe mich dazu entschieden, den Ursprungspunkt (Origin) um PosX und PosY nach links/oben zu verschieben, sodass mein gewünschtes Teil (was an PosX und PosY beginnen sollte!) auf 0,0 liegt.
Dann schränke ich den zu Grabbenden bereich mit SetViewPorT(0,0,64,64) ein, Zeichne das Komplett_Bild und grabbe es in den entsprechenden Array eintrag.


-----------------------

Jetzt kommt die erweiterung dieser Landschaft Sad

Ich habe mir direkt beim schreiben von TLandschaft 2 variablen gesichert, die die Aktuelle Y höhe beinhalten. Vllt wirds ja damit was ^-^

Midimaster hat Folgendes geschrieben:
Zeichne von der Landschaft einen kompletten Bildschirm 1280x1024 voll, aber ziehe von den X-Koordinaten vor dem Zeichnen immer 1280 ab, male dafür bis X=2560.


Gelingt Dir das?


Das ist mein jetziges Ziel, natürlich nach Kaffe aufsetzen und was essen Smile

Ich bedanke mich auf jedenfall erstmal recht herzlich für die mühe! Ich muss wohl wirklich an die hand genommen werden.

Das ist aber auch mistig, immerzu habe ich ideen, baue mir KB große Quellcodes im Kopf zusammen und 80% davon sind nur warme luft, die anderen 20% alleine nicht zu gebrauchen und aus dem was überbleibt (==Null) fange ich ein Projekt an! <.<

---------------

Edit 21.06.2011 - 07:02:

So ein mist. Ich stelle grade fest, das ich das ganze nicht dynamisch genug durchdacht habe.
Ich schreibe nun weite Teile neu, da ich sonst bei größeren Landschaften wie der Bildschirmbreite/höhe wieder probleme bekomme.
Die grobe Logik bleibt bestehen, allerdings werde ich mehr darauf achten, in Methoden auszulagern, der ich sagen kann, welche TileimageSlots ich zeichnen möchte.

Midimaster

BeitragDi, Jun 21, 2011 8:21
Antworten mit Zitat
Benutzer-Profile anzeigen
das Gesamtbild komplett zu zeichnen und daraus dann einen Ausschnitt zu grabben, kann nicht die Lösung sein. Dies dauert zu lang.

Es muss Dir gelingen das Grabben direkt mit dem Random-Zeichnen zu verknüpfen. Nur so sparst Du Zeit.

Oder, wenn Du schon alles zeichnest, dann musst du auch alles zur Verfügung stehende Bildmaterial gleich in mehrere Grabs zu sichern. Der SetViewport sollte sich ja auch auf die DrawLines einsetzen lassen...

sieh dir mal mein letztes Beispiel an, ich habe es gestern nochmal überarbeitet.

Wirst du in dem Spiel später auch senkrecht scrollen? oder nur dann, wenn die Landschaft zu hoch wird?

d.h. wird es Spielzüge geben, bei der die Figur lange senkrecht nach oben oder unten laufen wird. Oder ist da immer der Übergang zwischen Wiese und Himmel zu sehen?
 

PhillipK

BeitragDi, Jun 21, 2011 8:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Dein letztes beispiel gefiel mir sehr gut Wink Abgesehen von nem kleinen Array index out of bounds, sobald etwa 8000 frames durchgelaufen sind (nr >= 1000 -> booms Very Happy)

Nun, ein wirkliches Spiel ist daraus nicht geplant. Es ist eher eine Spielerei und lernerei.
Ich habe mich von anfang an mit 3D beschäftigt, da ist mir nie aufgefallen, wie einfach und grandios 2D sein kann. Das möchte ich nun ein wenig nachholen.
Das scrollen ist so ne sache. Mir wärs am liebsten, wenn man in alle richtungen 'Scrollen' kann, oder zumindest eine relativ große Landkarte besitzt.
Ich hatte sogar schon überlegungen angestellt, den RandomSeed für Landschaftsteile zu speichern, um es so später zu Rekonstruieren, aber das lasse ich lieber einmal.

Im moment schreibe ich eine Funktion, die mir eine simple map mit boden malt, welche auf jedenfall größer wie der Bildschirm ist.
Das ganze plane ich Rekursiv, dh eine funktion die jedesmal einen "Bildschirm" voll genereriert und in die entsprechenden Slots packt und sich danach erneut aufruft.

Ps: Wenn ich das System soweit beherschen kann, wird es evtl doch ein kleines spielchen geben Smile

Edit 21.06.2011 - 09:37:

So, mit ach und krach habe ich nun endlich etwas mehr hinbekommen.
Hab den kompletten denkansatz nochmal verworfen, die alte idee und ein paar eindrücke durch Midimaster zusammengemixt, und nach zahllosen kleinen Bugs etwas entworfen.

Leider immernoch verbuggt.. Wenn ich in TLandschaft zb die LastY variable zu "hoch" ansetze, wird überwiegend nur erde gezeichnet.

Dieser code ist so gut wie unkommentiert, das war einfach nur ein schnelles niederschreiben. :/

BlitzMax: [AUSKLAPPEN]
SuperStrict

Const ResX:Int = 1280, ResY:Int = 960
Const TileSize:Int = 64

Const TileCountX:Int = 32, TileCountY:Int = 32

Global OriX:Int = 0, OriY:Int = 0

Graphics(ResX, ResY)

Global Land:TLandschaft = TLandschaft.Create()

SetClsColor(100, 150, 255)
SetColor(255, 255, 255)
SetOrigin(0, 0)
SetViewport(0, 0, ResX, ResY)



While Not KeyHit(KEY_ESCAPE)
Cls

OriX:+KeyDown(KEY_A) * TileSize / 2 - KeyDown(KEY_D) * TileSize / 2
OriY:+KeyDown(KEY_W) * TileSize / 2 - KeyDown(KEY_S) * TileSize / 2

If OriX > (TileCountX * TileSize) Then OriX = TileCountX * TileSize
If OriY > (TileCountY * TileSize) Then OriY = TileCountY * TileSize

SetOrigin(OriX, OriY)

Land.Draw()

Flip 1
Wend

Type TLandschaft
Field Tiles:TTile[,] = New TTile[TileCountX, TileCountY]

Field LastY:Int = TileCountY * TileSize / 3

Function Create:TLandschaft()
Local a:TLandschaft = New TLandschaft

Local slotX:Int = 0, slotY:Int = 0

For slotX:Int = 0 Until TileCountX
For slotY:Int = 0 Until TileCountY
a.Tiles[slotX, slotY] = TTile.Create()
Next
Next

a.GenerateLandscape([0, 0])

Return a
End Function

'Rekursive funktion - ruft sich solange auf, wie die landschaft noch zu erstellen ist!
Method GenerateLandscape:Int[] (offset:Int[])
'Rekursionsende: OffsetX und Y erreichen "Maprand"
If offset[0] >= TileCountX * TileSize And offset[1] >= TileCountY * TileSize Then
Print "Offset ist zu hoch -return! :)"
Return offset
EndIf
If offset[0] >= TileCountX * TileSize Then
'ich habe das ende der map auf der Rechten seite erreicht! offset X auf 0 und offsetY erhöhen!
offset[0] = 0
Print "X offset hat maximum erreicht"
offset[1]:+(ResY - (ResY Mod TileSize))
End If

'Beginn der Zeichnung eines Bildschirms - FAST - ^^ voll :)
Cls

Local sizeX:Int = ResX - (ResX Mod TileSize)
Local sizeY:Int = ResY - (ResY Mod TileSize)

SetViewport(0, 0, sizeX, sizeY) ' beschränkt den viewport auf ein Vielfaches der Kachelgröße.
SetLineWidth(6)

Local posX:Int = 0, oldY:Int = Self.LastY, newY:Int = 0
Local y:Int

If oldY < offset[1] Then 'wenn die alte Y koordinate über meinem sichtfeld ist - erde!
' Print "Erde wird gezeichnet."
For posX = 0 Until sizeX Step 4
For y = -4 To sizeY Step 4
SetColor(Rand(70, 90), Rand(40, 50), 0)
DrawLine(posX, y, posX + 4, y + 4)
Next
Next
Else
' Print "Gras-reihe ist dran!"
For posX = 0 Until sizeX Step 4
SetColor(20, 150, 0)
newY = oldY + Rand(-4, 4)

DrawLine(posX, oldY, posX + 4, newY)
For y = oldY To sizeY Step 4
If y - oldY < Rand(15, 20)
' Gras.
SetColor 20, Rand(145, 155), 0
Else
' Erde
SetColor Rand(70, 90), Rand(40, 50), 0
EndIf
DrawLine(posX, y, posX + 4, y + 4)
Next
oldY = newY
Next
EndIf
'Zuweisen der Letzten höhe!
Self.LastY = newY

'Alles fertig - Bildschirm in seine Tiles packen!
'offsetX und Y geben an, welchen slotbereich ich nun zu grabben habe!

Local slotX:Int, slotY:Int
Local x:Int = 0
Local cnt:Int = 0
For slotX:Int = (offset[0] / TileSize) Until ((offset[0] + sizeX) / TileSize)
y = 0
For slotY:Int = (offset[1] / TileSize) Until ((offset[1] + sizeY) / TileSize)
If slotX >= TileCountX Or slotY >= TileCountY Then Continue
cnt:+1
Self.Tiles[slotX, slotY].GrabTile(x, y)
y:+TileSize
Next
x:+TileSize
Next
Print "anzahl grabs: " + cnt
offset[0]:+sizeX
' offset[1]:+sizeY

Return GenerateLandscape(offset)
End Method

Method Draw()
'OriX und OriY müssen zur berechnung der sichtbaren 'kacheln' herhalten!
' Local visCntX:Int = ResX / TileSize
' Local visCntY:Int = ResY / TileSize
Local posX:Int = 0
Local posY:Int = 0

' For Local x:Int = OriX / TileSize Until (OriX / TileSize) + visCntX
' posY = 0
' For Local y:Int = OriY / TileSize Until (OriY / TileSize) + visCntY
' DrawImage(Self.Tiles[x, y].img, posX, posY)
' posY:+TileSize
' Next
' posX:+TileSize
' Next
For Local x:Int = 0 Until TileCountX
For Local y:Int = 0 Until TileCountY
' DrawRect(x * TileSize - 2, y * TileSize - 2, TileSize + 4, TileSize + 4)
DrawImage(Self.Tiles[x, y].img, x * TileSize, y * TileSize)
Next
Next

End Method

End Type

Type TTile
Field img:TImage = CreateImage(TileSize, TileSize)

Function Create:TTile()
Return New TTile
End Function

Method GrabTile(posX:Int, posY:Int)
SetViewport(posX, posY, TileSize, TileSize)
GrabImage(Self.img, posX, posY)

' Print "Pixmap size: " + Self.img.pixmaps[0].Capacity
End Method
End Type


Ich werde mich nun dranmachen und ein Simpleres Zeichensystem schreiben, welches keine Images speichert, sondern aus jedem tile einen Seedwert zieht und ihn danach "füllt" - unterstützt werden nur simplere DrawLine geschichten.
  • Zuletzt bearbeitet von PhillipK am Di, Jun 21, 2011 9:43, insgesamt einmal bearbeitet

Midimaster

BeitragDi, Jun 21, 2011 9:39
Antworten mit Zitat
Benutzer-Profile anzeigen
das array mit 8000 reicht ja wohl erstmal für das demo.... Wink

das mit dem RandomSeed ist gar keine so blöde Idee, dadurch bist du in der Lage jeden Landschaftsteil zu rekonstruieren. Also. z.b. die Fortsetzung der Landschaft, wenn der Spieler an ihre Grenzen kommt.


Ich habe mal versucht, was passiert, wenn man den Boden nur 1x zeichnet und dann als Textur in alle weiteren Streifen einsetzt. -> es ist ab 16px Breite nichts Nachteiliges zu sehen

Auch den Himmel braucht man ja nicht mit in die Tiles zu speichern. So kannst Du die Geschwindigkeit zum Zeichnen eines Tiles nochmal um 25% drücken. bei meinem alten NoteBook messe ich Zeiten um 30-40msec. Wie sieht es bei Dir aus?
BlitzMax: [AUSKLAPPEN]

Global GrabBreite%=32


Graphics 800,600
Global LastY%=300
Global Zeit%
SetLineWidth 6
Global OffX% ,MitHimmel%
Global Tile:TImage[1000] , Textur:TImage
Global WoY%[1000]


PrePaintTextur


Repeat
Zeit=MilliSecs()
'SetClsColor 199,222,255
Cls
If OffX Mod GrabBreite=0
MalAbschnitt Nr
nr=nr+1
EndIf
If KeyHit(Key_H) Then
MitHimmel=1-MitHimmel
EndIf
SetColor 255,255,255
For Local i%=0 To nr-1
DrawImage Tile[i],i*GrabBreite+780-OffX,WoY[i]
Next
offx=offX+1
Flip 0
'Print "Zeit Gesamt=" + (MilliSecs()-Zeit)
Until KeyHit(Key_Escape)

End

Function MalAbschnitt(Nr%)

Local i%, X% , Y% , Zeit%

Zeit=MilliSecs()
SetColor 199,222,255
WoY[Nr]=LastY-10
DrawRect 0,0,GrabBreite-1,LastY+12
SetColor 255,255,255
DrawImage Textur,0,LastY+12
For X=0 To GrabBreite Step 3
SetColor 20, Rand(145, 155), 0
Y = LastY + Rand(-3, 3)
DrawLine X, LastY, X + 3, Y

For i = Y + 1 To y+30 Step 3
If i - Y < Rand(15, 20) Then
' Gras.
SetColor 20, Rand(145, 155), 0
Else
' Erde
SetColor Rand(70, 90), Rand(40, 50), 0
EndIf

DrawLine X, i, X+3, i+3
Next
LastY = Y
Next
If LastY-10 < WoY[Nr]
WoY[Nr]=LastY-10
EndIf
If MitHimmel=1
woY[Nr]=0
EndIf
Tile[Nr] = CreateImage( GrabBreite, 600-WoY[Nr])
GrabImage Tile[Nr],0, WoY[Nr]
Print "Zeit Grab=" + (MilliSecs()-Zeit)
End Function



Function PrePaintTextur()
Textur=CreateImage(GrabBreite,600)
For X=0 To GrabBreite Step 3
Y = LastY + Rand(-3, 3)
For i =0 To 600 Step 3
' Erde
SetColor Rand(70, 90), Rand(40, 50), 0

DrawLine X, i, X+3, i+3
Next
LastY = Y
Next
GrabImage Textur,0,0
SetColor 255,255,255
DrawText "<- Textur ready!",100,100
DrawText "Press H im Demo to switch 'Himmel'",100,130
DrawText " press any key to continue...",100,160
Flip
WaitKey
End Function


ps.
und schreib mir nicht gleich, dass du einen Fehler im Himmel gefunden hast. Das ist Absicht, damit man die Tile-Grenzen sieht Wink
 

PhillipK

BeitragDi, Jun 21, 2011 10:36
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich schau es mir mal an Very Happy

Das mit dem Fehler war keinesfalls eine ankreidung, ich bin froh das mir jemand hilft Smile Das war nur meine art zu sagen, das ichs mir angeschaut habe Smile

Ich überlege noch, wie ich die Rndseed eigenschaft nutzen kann, um meine Landschaft zu speichern. Das neu generieren der Flächen wäre aber nur mit einigen Unter-werten möglich Sad Evtl sollte ich mir einen Byte-Array zu nutze machen, um die draw-operationen das feld betreffend einzuspeichern.
Somit hätte ich zb 0-255 als "index", was für eine operation kommt und eine beliebig bestimmbare anzahl an werten, wie gedrawt wurde.

Sollte ich das ganze die Tage mal in ein halbwegs anschauliches Packet geschnürrt haben, werd ichs mir als Type abpacken und der Community zur verfügen stellen *g*

--------

So, ich verfolge nun einen weiteren Ansatz, den ich aus den bisherigen Erfahrungen gebastelt habe.
Ich wollte ein System nutzen, was Teile vorfertigt und diese nach einem bestimmten system ablegt.
Hintergrundgedanke ist, das ich eine Kachel in mehrere gleiche Teile unterteile, im moment peile ich 3x3 teile an. Nun kann von jedem dieser punkte eine linie zum anderen führen.

Das ist schwer zu erklären, darum hier mal ein Bild dazu:
user posted image

Von jedem punkt wird eine linie zu jedem anderen punkt gezogen und gegrabt.

Nun bastel ich shortWerte die für die bilder stehen und packe sie in einen Array[,] - welcher für die Kacheln der Landschaft stehen.
Ein byte für X, ein byte für Y des Tiles-arrays.
Beim generieren der map muss ich nun nurnoch darauf achten, das jede Kachel die zb auf 4 endet, neben sich eine hat, die mit 11 beginnt.
Ebenso wie kacheln die mit einer 1 enden über sich eine kachel haben müssen, die mit 8 beginnt.

Durch den vorteil der Frames könnte ich beim erstellen gleich mal 3-4 gleiche Tiles erstellen, die aber alle etwas anders gemalt sind, zb Unregelmäßiger oder ganz flach.
Diese werte könnte ich mit in den Short-Array packen, indem ich ihn einfach auf Int aufstocke Smile
Ausserde könnte jedes Tile gleich noch einen Array anfertigen, Wo Kollision auf den entsprechenden Bildern existieren würde, bei bedarf werden sie einfach dort ausgelesen.

Sollte es nun zu dem Fall kommen, das ein Tilestück verändert wird, könnte ich eine Kopie des Tile-bildes anfertigen und zb in eine TMap übertragen, wobei der Key mit der Short-zahl verknüpft wird Smile

Soviel zu meiner zukunftsmusik.. *grml*

Klingt das nach einem Halbwegs brauchbaren system, eine größere 2D map zu erschaffen, welche dynamisch in alle richtungen beweglich ist? :3 Oder könnte es von mir noch nicht bedachte Schwachstellen geben? Smile
Hab bis jetzt die Tilezeichnung geschrieben, die allerdings mit DrawLine eine grade linie zwischen ihren Start und Zielpositionen schreibt.

Wenn ich das soweit fertig hab, poste ich mal den Code Smile

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group