Autor Beitrag
aequitas
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16

Win XP Pro; Win 7 Pro
Delphi
BeitragVerfasst: Fr 19.04.13 15:28 
Hallo,

ich habe ein Problem bei der Umsetzung eines kleinen 2D-Spiels, bei welchem mir noch ein Ansatz fehlt.
(Ich hoffe mein Post ist hier richtig platziert, da er ja auf eine Grafikausgabe abzielt.)

Ich möchte ein Spiel erstellen, welches Tile-basiert ist, also quasi dargestellt wird, wie Pokemon oder Zelda.
Das ganze würde ich gerne ganz einfach mit einer Image-Komponente sowie mit Canvas lösen, da dies für meine Zwecke ausreichen würde.

Meine bisherigen Ansätze:

1. Ich erstelle zweidimensionale Records, welche meine Felder darstellen. Diese haben Variablen, welche u.a. die Koordinaten, die Textur und die Begehbarkeit speichern. Zudem habe ich noch ein zusätzliches, zweidimensionales Array, welches alle Felder beinhaltet, welche angezeigt werden,bestehend aus 7x7 Feldern. Ich gehe nun dieses zweite Array durch und lade in die entsprechenden Felder um meine Spielfigur (welche sich ja immer in der Mitte befindet) die entsprechenden Felder meines ersten Arrays. Vor einer Bewegung der Spielfigur prüfe ich auf Begehbarkeit des jeweiligen Feldes und verschiebe, wenn möglich, alle Felder dementsprechend.
Diese Version funktioniert einwandfrei, allerdings springt dabei natürlich die Spielfigur jeweils ein ganzes Feld pro Bewegungsbalauf, von flüssiger Bewegung keine Spur.

2. In meiner zweiten Version habe ich testweise die Spielfigur nicht in der Mitte, sondern sie läuft per Tasten über mein Spielfeld. Ich habe dazu 6 Timer eingerichtet: ein Timer überwacht per Intervall, ob eine Taste gedrückt wird und startet dann einen der Richtungstimer. Die vier Richtungstimer sorgen jeweils für die Verschiebung pixelweise in eine Richtung. Ein sechster Timer stoppt die vier Richtungstimer wieder genau dann, wenn die Spielfigur genau ein Feld gelaufen ist.
Diese Version lässt die Spielfigur pixelweise laufen und stoppt sie genau dann, wenn sie in einem Feld steht, also genau so, wie ich es haben möchte. Allerdings ist die Spielfigur, wie beschrieben, nicht in der Mitte.

3. Das komplette Spielfeld wird direkt gezeichnet und anschließend pixelweise verschoben. Allerdings ruckelt dann das Verschieben der Felder ab einer Größe von etwa 50x50 Feldern. Hier ist also in etwa die Grenze von TCanvas.

Mit OpenGL komme ich nicht wirklich klar, deswegen würde ich eigentlich gerne mit dieser "kleinen" Variante arbeiten.
Hättet ihr denn Tipps, wie ich noch an dieses Problem herangehen könnte?



Gruß
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19272
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 19.04.13 15:42 
Nimm nicht TImage, sondern TPaintBox (zeichne in dessen OnPaint), das dürfte das ganze schon einmal schneller machen.
Jann1k
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 866
Erhaltene Danke: 43

Win 7
TurboDelphi, Visual Studio 2010
BeitragVerfasst: Fr 19.04.13 17:12 
Vorneweg, deine Eingabesteuerung ist nicht wirklich gut, ich habe das immer so gelöst, dass ich in den OnKeyDown bzw. OnKeyUp Events der Form Flags setze, ein einziger Timer überprüft die Flags (also welche Tasten gedrückt sind) und bewegt die Spielfigur dann dementsprechend. Dafür mehrere Timer zu nehmen ist unsauber und fehlerträchtig.

Bei der pixelgenauen Bewegung der Figur ist es eigentlich ganz einfach: Wann bewegt sich die Figur auf ein anderes Feld? Nehmen wir an deine Tiles haben die Breite von 10 Pixeln, dann kann sich die Figur in den Bereichen 0-9, 10-19, 20-29 usw. frei bewegen, erst wenn sie aus einem Tile herausläuft also von 9 auf 10 oder von 19 auf 20 überprüfst du auf begehbarkeit des anderen Tiles. So solltest du recht einfach eine schöne Bewegung hinkriegen, am besten Bastelst du dir eine Funktion die dir die Pixelkoordinaten der Figur in die Tilekoordinaten umrechnet.
aequitas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16

Win XP Pro; Win 7 Pro
Delphi
BeitragVerfasst: Fr 19.04.13 17:32 
Also meine Tastenabfrage habe ich, glaube ich, genauso gelöst, wie du es meinst. In den OnKeyDown bzw. OnKeyUp Events setze ich jeweils eine Boolean-Variable auf True bzw. False. Die vier verschiedenen Timer sind dafür da, die Figur pixelweise zu verschieben, also im jeweiligen Timer zB:
- Anzeige()
- x = x +1
- Anzeige()
- ...

Auch die Abfrage der Kollision funktioniert in meinen Tests wunderbar.

Mein Problem liegt eher bei der generellen Anzeige. Wenn ich alle Felder, die momentan sichtbar sind, animiert verschiebe, habe ich keine Kontrolle mehr über meine Felder. Bewege ich mich zB nach rechts, heißt das, dass alle sichtbaren Felder pixelweise nach links verschoben werden müssen. Allerdings habe ich dann rechts eine vertikale Reihe, welche leer bleibt. Ich brauche also eine Verbindung zwischen meinen Feldkoordinaten und jenen, welche momentan angezeigt werden...

Wahrscheinlich stehe ich einfach auf dem Schlauch.
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Fr 19.04.13 18:20 
Wenn OpenGL Dir nicht zusagt, vielleicht möchtest Du auf eine fertige Engine zugreifen? Spontan fällt mir da Andorra 2D ein, ein deutsches Tutorial findest Du hier.
rushifell
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: Fr 19.04.13 18:35 
aequitas hat folgendes geschrieben:
Mit OpenGL komme ich nicht wirklich klar, deswegen würde ich eigentlich gerne mit dieser "kleinen" Variante arbeiten.

Lohnt sich aber ;-) . Hatte am Anfang auch meine Schwierigkeiten, letztendlich ist es jedoch sehr einfach. Suche mal im Internet nach OpenGL 2D Tutorial.

Link: wiki.delphigl.com/index.php/Tutorial_2D Ich finde das Tutorial super, auch wenn es etwas veraltet ist.

Für eine flüssige Bewegung ist ein Timebased Movement sinnvoll. Einen Timer brauchst Du nicht. Unter Windows kannst Du für das Timebased Movement den QueryPerformanceCounter nutzen. Das schöne daran ist, dass sich Deine Spielfiguren bei Bedarf auch unterschiedlich schnell bewegen können.

Für das Spielfeld würde ich nur ein zweidimensionales Array verwenden und den sichtbaren Bereich zeichen. Hast Du z.B. ein Spielfeld mit 20 x 20 Feldern und der sichtbare Bereich umfasst 7 x 7 Felder, so musst Du z.B. nur Feld 2..9 (X-Achse) und Feld 4..11 (Y-Achse) zeichnen.
catweasel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 487
Erhaltene Danke: 1

Win 7 64bit
Delphi 7 Second Sedition V7.2
BeitragVerfasst: Di 23.04.13 09:45 
user profile iconaequitas hat folgendes geschrieben Zum zitierten Posting springen:
Hallo,

ich habe ein Problem bei der Umsetzung eines kleinen 2D-Spiels, bei welchem mir noch ein Ansatz fehlt.
(Ich hoffe mein Post ist hier richtig platziert, da er ja auf eine Grafikausgabe abzielt.)

Ich möchte ein Spiel erstellen, welches Tile-basiert ist, also quasi dargestellt wird, wie Pokemon oder Zelda.
Das ganze würde ich gerne ganz einfach mit einer Image-Komponente sowie mit Canvas lösen, da dies für meine Zwecke ausreichen würde.

Meine bisherigen Ansätze:

1. Ich erstelle zweidimensionale Records, welche meine Felder darstellen. Diese haben Variablen, welche u.a. die Koordinaten, die Textur und die Begehbarkeit speichern. Zudem habe ich noch ein zusätzliches, zweidimensionales Array, welches alle Felder beinhaltet, welche angezeigt werden,bestehend aus 7x7 Feldern. Ich gehe nun dieses zweite Array durch und lade in die entsprechenden Felder um meine Spielfigur (welche sich ja immer in der Mitte befindet) die entsprechenden Felder meines ersten Arrays. Vor einer Bewegung der Spielfigur prüfe ich auf Begehbarkeit des jeweiligen Feldes und verschiebe, wenn möglich, alle Felder dementsprechend.
Diese Version funktioniert einwandfrei, allerdings springt dabei natürlich die Spielfigur jeweils ein ganzes Feld pro Bewegungsbalauf, von flüssiger Bewegung keine Spur.

2. In meiner zweiten Version habe ich testweise die Spielfigur nicht in der Mitte, sondern sie läuft per Tasten über mein Spielfeld. Ich habe dazu 6 Timer eingerichtet: ein Timer überwacht per Intervall, ob eine Taste gedrückt wird und startet dann einen der Richtungstimer. Die vier Richtungstimer sorgen jeweils für die Verschiebung pixelweise in eine Richtung. Ein sechster Timer stoppt die vier Richtungstimer wieder genau dann, wenn die Spielfigur genau ein Feld gelaufen ist.
Diese Version lässt die Spielfigur pixelweise laufen und stoppt sie genau dann, wenn sie in einem Feld steht, also genau so, wie ich es haben möchte. Allerdings ist die Spielfigur, wie beschrieben, nicht in der Mitte.

3. Das komplette Spielfeld wird direkt gezeichnet und anschließend pixelweise verschoben. Allerdings ruckelt dann das Verschieben der Felder ab einer Größe von etwa 50x50 Feldern. Hier ist also in etwa die Grenze von TCanvas.

Mit OpenGL komme ich nicht wirklich klar, deswegen würde ich eigentlich gerne mit dieser "kleinen" Variante arbeiten.
Hättet ihr denn Tipps, wie ich noch an dieses Problem herangehen könnte?

Gruß


Ich habe mal eine Tile Engine geschreiben die auf dem TTdrawGrid aufbaut. Ist im Prinzip ganz simpel:
(Als Hex Tiles, aber als Quadratisches Raster gehts natürlich auch..)

www.entwickler-ecke....ewtopic.php?t=110943

Man nimmt ein 2D Array mit denselben Dimensionen wie das Grid (oder andersrum ;) ) Das Array enthält alles was das Tile zur Beschreibung braucht: Ein Index auf ein in einer ImageList und evtl noch infos ob adas Feld betreten werden kann. Evtle Boni, etc...

In dem OnDrawCell Event des Grids dann einfach nur per. DatenArray[ACol,ARow] auf das Array zugreifen und dann das Bild mit Canvas.Draw(Rect) in die Zelle malen.
Ist superbequem. Bei grossen Arrays kann man auch einen Offset dazuaddieren und die Col und RowCounts des Grids auf das Sichtbare beschränken. Scrollen kann man dann per Doppelklick machen

Ey, weisst du wie ich meine? :)

Cheers,
Catweasel

_________________
Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
aequitas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16

Win XP Pro; Win 7 Pro
Delphi
BeitragVerfasst: Di 23.04.13 18:54 
Ich habe mir dein Grid-Programm mal angesehen. Schaut ganz nett aus, aber ich bin mir nicht sicher, ob mir das weiterhilft. Meine 1. Lösung war in etwa so ähnlich, nur statt des Grids male ich meine Bilder in ein Image.
Feldweise meine Figur verschieben ist noch recht einfach: ich prüfe ob das jeweilige Feld neben meiner Figur begehbar ist, und hole mir in mein entsprechendes "Display-Array" die Felder des "Daten-Arrays". Dann wird meine Figur wieder über das Bild in der Mitte gemalt und fertig.

Ich möchte aber nun, dass wenn ich z.B. ein Feld nach rechts laufe, alle Felder animiert (durch einen Timer) jeweils pixelweise nach links verschoben werden, und zwar um 25 Pixel (wobei ein Feld genau 25x25 Pixel abmisst). Nur die Figur bleibt immer in der Mitte, wird also bei jedem Verschieben in der Mitte behalten.

Mein Problem liegt dabei beim "Nachholen" der Pixel, die noch nicht sichtbar sind. Außerdem verliere ich dadurch den Zugriff auf meine Felder...
catweasel
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 487
Erhaltene Danke: 1

Win 7 64bit
Delphi 7 Second Sedition V7.2
BeitragVerfasst: Di 23.04.13 19:57 
user profile iconaequitas hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe mir dein Grid-Programm mal angesehen. Schaut ganz nett aus, aber ich bin mir nicht sicher, ob mir das weiterhilft. Meine 1. Lösung war in etwa so ähnlich, nur statt des Grids male ich meine Bilder in ein Image.
Feldweise meine Figur verschieben ist noch recht einfach: ich prüfe ob das jeweilige Feld neben meiner Figur begehbar ist, und hole mir in mein entsprechendes "Display-Array" die Felder des "Daten-Arrays". Dann wird meine Figur wieder über das Bild in der Mitte gemalt und fertig.

Ich möchte aber nun, dass wenn ich z.B. ein Feld nach rechts laufe, alle Felder animiert (durch einen Timer) jeweils pixelweise nach links verschoben werden, und zwar um 25 Pixel (wobei ein Feld genau 25x25 Pixel abmisst). Nur die Figur bleibt immer in der Mitte, wird also bei jedem Verschieben in der Mitte behalten.

Mein Problem liegt dabei beim "Nachholen" der Pixel, die noch nicht sichtbar sind. Außerdem verliere ich dadurch den Zugriff auf meine Felder...


Das geht in der Tat mit der DrawGrid Komponente schwierig. Die HEx Komponente kann das im Prinizip.
Schau dir mal den Offsetwert an. Der bestimmt wo die Zelle angezeigt wird. Diesen Wert kannst du dann in einer Schleife verändern (und zwischendurch neu zeichnen). Der neue Inhalt wird dann ganz automatisch generiert.

Was meinst du mit "verlieren den Zugriff auf die Felder" ?

Tip: Nimm statt eines Timers das OnIdle Event. :)

Cheers,
Catweasel

_________________
Pommes werden schneller fertig wenn man sie vor dem Frittieren einige Minuten in siedendes Fett legt.
aequitas Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 16

Win XP Pro; Win 7 Pro
Delphi
BeitragVerfasst: Do 25.04.13 20:33 
Ich habe mir mal das OpenGL-2D-Tutorial, welches rushifell gepostet hat, genauer angeschaut. Hier habe ich glaube etwas hilfreiches gefunden, was ich auch mal ausprobieren werde:

Ich nehme keine 2 Arrays zur Map und zur Darstellung, sondern nur eines. Ich verschiebe nun dieses Array in die jeweilige Richtung und zeichne dabei aber nur die Bilder, welche auch sichtbar sind. Dies prüfe ich, indem ich die x- und y-Koordinaten überprüfe, ob sie im sichtbaren Bereich liegen.

Ich versuche mich mal die Tage daran. Sollte es klappen (oder auch nicht), werde ich mich nochmal melden.

Vielen Dank
und Grüße
rushifell
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 306
Erhaltene Danke: 14



BeitragVerfasst: Fr 26.04.13 19:42 
Für die Bewegungen der Figuren und auch das Scrollen, ist es sinnvoll, ein Timebased Movement zu verwenden (wie ich oben schon erwähnt habe). Dadurch bekommst Du ruckelfreie flüssige Bewegungen, und die Spielgeschwindigkeit ist auf jedem PC gleich. Einfach mal im Wiki, in dem auch das Tutorial zu finden ist nach "Timebased Movement" suchen. Wichtig ist, dass Du zum Berechnen der Pixel Gleitkommazahlen und keine ganzen Zahlen verwendest.

Viele Grüße und viel Erfolg!