amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Koordinatentransformation, Überdeckung [ - Suche - Neue Beiträge - Registrieren - Login - ]

-1- 2 3 [ - Beitrag schreiben - ]

28.02.2006, 21:24 Uhr

Reth
Posts: 1858
Nutzer
Hallo zusammen,

ich überlege gerade an nem Algorithmus, wie ich am geschicktesten mehrere Ebenen von grafischen Objekten verwalte, so dass nur die notwendigsten neu geblittet werden müssen (ohne DoubleBuffering).

Hab mir gedacht, eine Liste von Listen zu machen, die den Koordinaten der Hintergrundkacheln entspricht.
Einen Algorithmus zur Rechtecküberdeckung hab ich schon, den kann ich dann dazu benutzen, die Ebenen über den Hintergrundkacheln einzusortieren. Am Ende steht eine Matrix mit Listen an jedem Knoten, in denen die Objekte der Reihe nach entsprechend ihren Schichten stehen.

Etwas speicheraufwändig, aber sollte tun.
Was meint ihr?

@whose
Wir ham uns ja über solche Sachen schon mal unterhalten, habe leider Deine Beiträge gerade nicht zur Hand!

Ciao

[ - Antworten - Zitieren - Direktlink - ]

28.02.2006, 23:13 Uhr

whose
Posts: 2156
Nutzer
@Reth:

Da können wir uns gern per PM weiter drüber austauschen. Als kleinen Tip kann ich Dir gamedev.net nennen, da sind auch ein paar Artikel zu finden, die sich mit Tile-basierten Spielen beschäftigen, darunter auch Rollenspiele alá Zelda, Final Fantasy etc., die ja öfter mal mit mehreren Ebenen in der Grafik funktionieren. Da habe ich recht interessante Anregungen gefunden, vielleicht ist da auch was für Dich dabei, schau mal...

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

01.03.2006, 07:47 Uhr

psd
Posts: 12
Nutzer
Das könnt ihr auch gerne hier diskutieren, dann habe ich auch was davon. :)

[ - Antworten - Zitieren - Direktlink - ]

01.03.2006, 12:56 Uhr

Reth
Posts: 1858
Nutzer
@psd

Gerne!

@whose
Hab mal ein paar Artikel dort gelesen. Z.B. gehen http://www.gamedev.net/reference/articles/article748.asp und http://www.gamedev.net/reference/articles/article727.asp im Prinzip diesen Weg, den ich oben beschrieben habe.

Bleiben mir aber noch 2 Fragen:
1. Kann ich eine Matrix/ein Array vermeiden und meine 2-Dimensionale Landschaft aus Tiles in eine eindimensionales Array abbilden?

2. Was mache ich mit Objekten, die mehr als ein Tile überdecken? Denke mir dass so, dass deren linke untere Ecke (wenn man immer von oben links nach unten rechts blittet) ausschlaggebend ist. Über welchem Tile diese liegt, in dessen Layerliste wird das Objekt eingetragen.

[ Dieser Beitrag wurde von Reth am 01.03.2006 um 15:33 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

01.03.2006, 18:02 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:
@psd

Gerne!

@whose
Hab mal ein paar Artikel dort gelesen. Z.B. gehen http://www.gamedev.net/reference/articles/article748.asp und http://www.gamedev.net/reference/articles/article727.asp im Prinzip diesen Weg, den ich oben beschrieben habe.

Bleiben mir aber noch 2 Fragen:
1. Kann ich eine Matrix/ein Array vermeiden und meine 2-Dimensionale Landschaft aus Tiles in eine eindimensionales Array abbilden?


Hm, wie genau meinst Du das jetzt? Ein zweidimensionales Array ist im Grunde (also im Speicher) ja auch nur eindimensional, man spricht es nur zweidimensional an. Die zweite Dimension kommt durch Überspringen einer Zeile (oder Spalte, je nach Sichtweise) zu stande. An der Indexierung ändert sich im Grunde nichts, nur die Sprünge werden größer.

Zitat:
2. Was mache ich mit Objekten, die mehr als ein Tile überdecken? Denke mir dass so, dass deren linke untere Ecke (wenn man immer von oben links nach unten rechts blittet) ausschlaggebend ist. Über welchem Tile diese liegt, in dessen Layerliste wird das Objekt eingetragen.

Prinzipiell eine gute Idee... so kannst Du auch mehrere überlagernde Objekte relativ simpel verwalten, in diesem Fall über die Liste des Tiles. Achte nur drauf, daß Du dadurch nicht zu viele Blits fabrizierst (also nicht platt alles neu zeichnen, auch wenns nicht nötig ist), sonst wirds mächtig langsam bei vielen Überdeckungen.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

01.03.2006, 19:20 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von whose:
Zitat:
Original von Reth:
2. Was mache ich mit Objekten, die mehr als ein Tile überdecken? Denke mir dass so, dass deren linke untere Ecke (wenn man immer von oben links nach unten rechts blittet) ausschlaggebend ist. Über welchem Tile diese liegt, in dessen Layerliste wird das Objekt eingetragen.


Prinzipiell eine gute Idee... so kannst Du auch mehrere überlagernde Objekte relativ simpel verwalten, in diesem Fall über die Liste des Tiles. Achte nur drauf, daß Du dadurch nicht zu viele Blits fabrizierst (also nicht platt alles neu zeichnen, auch wenns nicht nötig ist), sonst wirds mächtig langsam bei vielen Überdeckungen.

Grüße


Hi whose,

ja das hab ich auch schon gedacht. In dem 2. Artikel steht auch was dazu.
Allerdings komme ich wohl um den Dominoeffekt nicht herum. Sobald ich ein Objekt aktualisiere muss ich alle anderen (oder benachbarten) überprüfen, ob sie überdeckt sind und ggf. neu zeichnen dann prüfen, ob sie andere überdecken etc.
Da ich Objekte an den Ecken meiner 6-Ecke hab, überdecken diese automatisch die benachbarten 6-Ecke, wenn an deren Ecken auch wieder Objekte sind, geht das Ganze weiter.

Hab noch keine Ahnung, wie ich darum herumkommen soll immer alle anderen Objekte auf Überdeckung zu prüfen?

[ - Antworten - Zitieren - Direktlink - ]

01.03.2006, 19:48 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:
Zitat:
Original von whose:
Zitat:
Original von Reth:
2. Was mache ich mit Objekten, die mehr als ein Tile überdecken? Denke mir dass so, dass deren linke untere Ecke (wenn man immer von oben links nach unten rechts blittet) ausschlaggebend ist. Über welchem Tile diese liegt, in dessen Layerliste wird das Objekt eingetragen.


Prinzipiell eine gute Idee... so kannst Du auch mehrere überlagernde Objekte relativ simpel verwalten, in diesem Fall über die Liste des Tiles. Achte nur drauf, daß Du dadurch nicht zu viele Blits fabrizierst (also nicht platt alles neu zeichnen, auch wenns nicht nötig ist), sonst wirds mächtig langsam bei vielen Überdeckungen.

Grüße


Hi whose,

ja das hab ich auch schon gedacht. In dem 2. Artikel steht auch was dazu.
Allerdings komme ich wohl um den Dominoeffekt nicht herum. Sobald ich ein Objekt aktualisiere muss ich alle anderen (oder benachbarten) überprüfen, ob sie überdeckt sind und ggf. neu zeichnen dann prüfen, ob sie andere überdecken etc.
Da ich Objekte an den Ecken meiner 6-Ecke hab, überdecken diese automatisch die benachbarten 6-Ecke, wenn an deren Ecken auch wieder Objekte sind, geht das Ganze weiter.

Hab noch keine Ahnung, wie ich darum herumkommen soll immer alle anderen Objekte auf Überdeckung zu prüfen?


Schau noch mal auf gamedev.net, da ist auch irgendwo ein Artikel versteckt, der sich mit hexagonal zeichnenden Engines beschäftigt. Da wird u.A. ein Weg gezeigt, wie sich die hexagonalen Tiles in ein simpels 2D-Array "pressen" lassen. Dann kannst Du auch relativ einfach eine Art "Damage Region"-Verwaltung aufbauen.

Übersetze Objekt-Koordinaten in Dein hexagonales System und Du weißt, wo sich etwas verändert hat, sobald Du irgend etwas mit einem Objekt veranstaltest (Koordinatenänderung z.B. zieht immer ein Neuzeichnen nach sich). In dem Fall wird das Objekt in die Liste des entsprechenden Tiles eingehängt und im Zeichen-State halt mitsamt allen evtl. vorhandenen Objekten neu gezeichnet, stur nach Liste. Die Tiles, die nicht von Veränderungen betroffen sind, tauchen nicht in der "Damage"-Liste auf und werden dann auch nicht neu gezeichnet.

Das Problem der Überdeckung läßt sich damit auch verhältnismäßig einfach lösen, die Höhe und Breite Deiner Objekte ist ja bekannt. Wenn Du für die Hex-Tiles ein 2D-Array hast, läßt sich mit relativ wenig Aufwand berechnen, welche weiteren Tiles von einer Veränderung durch ein Objekt betroffen sind. Das funktioniert dann ähnlich wie bei rechteckigen Tiles (wenn Du meine älteren Mails noch hast, die Geschichte mit der Erweiterung von Koordinaten auf eine z.B. glatt durch 8 teilbare Zahl gehört zu dem Themenkomplex).

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

01.03.2006, 21:04 Uhr

Reth
Posts: 1858
Nutzer
@whose:

Ach ja, wenn ich einen Algorithmus habe, mit dem ich eindeutig zweidimensionale Koordinaten auf einen eindimensionalen Index abbilden kann, kann ich in einer Liste eindeutig auf eine Position zugreifen und weiss damit welche Objekte in allen Layern ich überdecke und ändern muss.

Mit ner HashMap kann ich auch mogeln, indem ich Strings baue mit der x-Koordinate und der y-Koordinate. Diesen String kann ich dann als Schlüssel verwenden.

Aber eigentlich steh ich immer noch ein wenig auf dem Schlauch, wie ich das performant angehen kann, trotz der Artikel von gamedev.net.
Muss den Knoten irgendwie zum Platzen bringen!

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 01:24 Uhr

whose
Posts: 2156
Nutzer
@Reth:

Bekannt sein muß dafür die Anzahl der X-Koordinaten pro Zeile.

Dann ist Eintrag(x, y): Array[y * x]

Simpel, oder?

2D-Arrays sind kein wirkliches Geschwindigkeitsproblem. Der Compiler arbeitet mit 2D-Arrays genau so. Du kannst also beruhigt 2D-Arrays verwenden. Worauf Du unbedingt achten mußt ist, so wenig Zeichenvorgänge wie möglich pro Frame zu erreichen und nicht zu lange durch die Koordinatenberechnungen zu laufen. Die Größe der zu blittenden Bereiche spielt dabei eine eher untergeordnete Rolle, sofern Du nicht aus dem FastRAM heraus ins Bild blittest (da brechen die 68K-Maschinen dann SEHR deutlich ein, Ausnahme PPC-Maschinen/Amithlon und direkter Zugriff auf die Bitmap, da siehts etwas besser aus).

Ich kann Dir auch gern mal Sourcecode zu meiner Sprite-Engine schicken. Die ist zwar derzeit nicht besonders komplex, aber läuft butterweich auf allen Maschinen und zeichnet nur so viel, wie unbedingt nötig ist (also bewegte Objekte vor fixem Tile-Hintergrund, der fixe Hintergrund muß unter jedem Sprite dann ja restauriert werden). Da habe ich sogar noch wesentlich komplizierter gearbeitet, als nötig wäre. Interessanterweise läuft die sogar mittels OS-Doublebuffering, also mit der ChangeScreenBuffer()-Mimik. Das scheint ürigens die einzige Methode zu sein, die sowohl unter CGFX als auch P96 rasterstrahlsynchron läuft.

Einziger Nachteil bei dieser Engine ist bisher nur, daß die noch nicht mit überlappenden Sprites klarkommt, da wird der Hintergrund noch doppelt gezeichnet unnötigerweise. Da müßte ich eine Mimik einbauen, die mittels Damage Regions die neu zu zeichnenden Tiles ermittelt. und vor allem diese Regions "addiert" (also bei einer Überlappung dafür sorgt, daß die zerstörten Bereiche ggf. in mehrere rechteckige Bereiche "zerlegt" werden, damit nichts doppelt gezeichnet wird. Die Überlappungen werden dann zu einem Rechteck zusammengefaßt, die anderen Bereiche werden unabhängig von der Überlappung behandelt). Wenn das implementiert ist, ist es nur noch ne Frage der Zeichenreihenfolge, was die Sprites betrifft, ob das Bild korrekt zusammengesetzt wird oder nicht.

Grüße

(Edit) Vielleicht fällts Dir leichter, wenn Du Dir die Grafik vorstellst wie übereinandergelegte Overhead-Folien. Für jedes Objekt eine eigene Folie, die Hintergrund-Tiles bilden eine einzige Folie. Je nachdem, wie Du die "Folien" der Objekte verschiebst, sind ein oder mehrere Tiles auf der Hintergrund-"Folie" überdeckt.

Die Ermittlung der überdeckten Bereiche ist verhältnismäßig einfach:

+---------------------------- X
| +--+
| | |
| +--+
|
|
|
|
|
Y

Hier bildet jeder "Strich" auf den Achsen die Position eines Hintergrund-Tiles ab.

Das eingezeichnete Objekt ist 4*3 "Tiles" groß. Wenn jedes Tile größer als 1 Pixel ist, kann es zu Überschneidungen zwischen Tile-Array- und Objektkoordinaten kommen (also unvollständige Überdeckung, weil eine Abbildung der Objekt-Koordinaten in Pixeln auf den Tile-Array-Index keine ganzzahlige Angelegenheit mehr ist, sobald ein Tile 2 Pixel pro Richtung groß ist. Eine Objekt-Koordinate in Pixeln kann dann einem "halben" Tile entsprechen).

Man muß also in "ganzen Tiles" den Bereich ermitteln, den das Objekt überdeckt.

Dieser Bereich ermittelt sich wie folgt, wenn die Tiles 8*8 Pixel groß sind:

Startposition des Bereiches in X: (ObjectPosX + 7) &~ 8
Startposition des Bereiches in Y: (ObjectPosY + 7) &~ 8

Anzahl "ganze" Tiles in X, die das Objekt überdeckt: (((ObjectPosX + ObjectSizeX) + 7) &~ 8 ) - Startposition in X

Anzahl "ganze" Tiles in Y, die das Objekt überdeckt: (((ObjectPosY + ObjectSizeY) + 7) &~ 8 ) - Startposition in Y

Die ermittelten Werte sind Indizes innerhalb des Tile-Arrays, also "ganze" Tiles (!). Damit weißt Du, welche Tiles innerhalb des Arrays neu gezeichnet werden müssen. Das funktioniert genauso bei hexagonalen Tiles, vorausgesetzt, Du bekommst die Koordinaten in ein 2D-Array transformiert.

In Deinem Fall ist das Ganze sogar noch ein wenig simpler, fällt mir gerade auf. Bei Deiner Grafik kann ein Objekt maximal 3 Tiles überdecken, da läßt sich das bestimmt noch stark vereinfachen (also nur mit den Objektkoordinaten arbeiten, die Größe des Objekts spielt dann wohl nur eine sehr untergeordnete Rolle).

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 02.03.2006 um 02:38 Uhr geändert. ]

[ Dieser Beitrag wurde von whose am 02.03.2006 um 03:19 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 08:08 Uhr

Micha1701
Posts: 938
Nutzer
Hi!

Ich hab in Realms of Power ebenfalls Tiles verwendet. Und diese überlagern meist das darüber liegende Tile (z.B. Berge oder auch Einheiten). Damit ich jetzt nicht alles neu zeichnen mußte, hab ich einfach den zu bemalenden Bereich beschränkt. Dazu einfach mit Region() und InstallClipRegion() den Bereich beschränkt. Dann mußte ich nur den Teil um das zu ändernde Tile neu zeichnen. Alles andere wird dann ja nicht "zerstört".

Vielleicht hilft Dir das weiter.
--
:boing: Micha :boing:

http://www.Silicon-Wizards.com

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 08:49 Uhr

Reth
Posts: 1858
Nutzer
Hi nochmal,

wow, das ist wieder ausführlich!
Danke für Deine Mühen!

Zitat:
Original von whose:
@Reth:

Bekannt sein muß dafür die Anzahl der X-Koordinaten pro Zeile.

Dann ist Eintrag(x, y): Array[y * x]

Simpel, oder?


Aber dann haben die Objekte mit gleichen vertauschten Koordinatenwerten ja denselben Eintrag!
Also x=3 und y=4 bilden auf dieselbe Arrayposition ab wie x=4 und y=3!? Oder meintest Du Array[x, y]?

Zitat:
2D-Arrays sind kein wirkliches Geschwindigkeitsproblem. Der Compiler arbeitet mit 2D-Arrays genau so. Du kannst also beruhigt 2D-Arrays verwenden.
Geschwindigkeitsmäßig ist das natürlich OK. Da ich aber in C++ mit der STL arbeite und so leckere Sachen wie HashMaps habe, wollte ich die gern verwenden, da sie einen schnellen direkten Zugriff auf Objekte erlauben. Wenn ich daher die Koordinaten von 2D nach 1D eindeutig transformieren kann, dann kann ich direkt in der HashMap die entsprechende Position ermitteln. Da ich ja mit Layern arbeite, ist an jeder dieser Positionen eine Liste mit Objekten in der Reihenfolge ihres Layers eingetragen.

Zitat:
Worauf Du unbedingt achten mußt ist, so wenig Zeichenvorgänge wie möglich pro Frame zu erreichen und nicht zu lange durch die Koordinatenberechnungen zu laufen.

Das will ich ja mit den Layerlisten erreichen. Allerdings bei den Koordinatenberechnungen weiss ich noch nicht, wie ich das optimal gestalten kann. Habe mir im Moment diesen Ansatz überlegt:

Wenn ein Objekt seine Position ändert => finden seiner Liste in der Map. Aufnehmen der Layerliste an dieser Position in die Damagelist. Durchgehen aller Objekte in der Liste, prüfen der 4 Eckpunkte jedes dieser Objekte (also jeden Layer an dieser Position), ob diese andere Objekte überlappen (hier wärs halt sehr von Vorteil, wenn ich eindimensional arbeiten könnte, da ich dann direkt in der HashMap die überlappenden Objekte finde). Für jede so gefundene andere Layerliste diese in die Damagelist aufnehmen und den Vorgang wiederholen.
Denke aber nicht, dass das performant ist (Dominoeffekt).
Die Damagelist wird dann Layer für Layer komplett neu gezeichnet (in dem einen Artikel auf gamedev.net steht glaub, dass erst alle Layer eines Bereiches gezeichnet werden, bevor die des anderen Bereiches drankommen, um Abschneiden von Objekten zu verhindern. Also entweder hab ich in dem Artikel was missverstanden oder passiert dadurch doch genau das: Objekte können abgeschnitten werden.

Zitat:
Ich kann Dir auch gern mal Sourcecode zu meiner Sprite-Engine schicken. Die ist zwar derzeit nicht besonders komplex, aber läuft butterweich auf allen Maschinen und zeichnet nur so viel, wie unbedingt nötig ist (also bewegte Objekte vor fixem Tile-Hintergrund, der fixe Hintergrund muß unter jedem Sprite dann ja restauriert werden). Da habe ich sogar noch wesentlich komplizierter gearbeitet, als nötig wäre. Interessanterweise läuft die sogar mittels OS-Doublebuffering, also mit der ChangeScreenBuffer()-Mimik. Das scheint ürigens die einzige Methode zu sein, die sowohl unter CGFX als auch P96 rasterstrahlsynchron läuft.

Gern, immer her damit. Hoffentlich kapier ichs auch (fremder Sourcecode ist nicht immer gleich für Außenstehende verständlich).

Zitat:
Einziger Nachteil bei dieser Engine ist bisher nur, daß die noch nicht mit überlappenden Sprites klarkommt, da wird der Hintergrund noch doppelt gezeichnet unnötigerweise.

Genau das Problem hab ich momentan. Wenns nur ein Objekt überm Hintergrund wäre, wärs einfacher. So aber hab ich Objekte in versch. Ebenen, die sich gegenseitig überdecken können.

Zitat:
(Edit) Vielleicht fällts Dir leichter, wenn Du Dir die Grafik vorstellst wie übereinandergelegte Overhead-Folien. Für jedes Objekt eine eigene Folie, die Hintergrund-Tiles bilden eine einzige Folie. Je nachdem, wie Du die "Folien" der Objekte verschiebst, sind ein oder mehrere Tiles auf der Hintergrund-"Folie" überdeckt.

Genauso ist meine Grafik aufgebaut. Jedes Objekt hat einen Layer zugeordnet. Objekte innerhalb des selben Layers können sich nicht überdecken.

Zitat:
Die Ermittlung der überdeckten Bereiche ist verhältnismäßig einfach:

+---------------------------- X
| +--+
| | |
| +--+
|
|
|
|
|
Y

Hier bildet jeder "Strich" auf den Achsen die Position eines Hintergrund-Tiles ab.

Das eingezeichnete Objekt ist 4*3 "Tiles" groß. Wenn jedes Tile größer als 1 Pixel ist, kann es zu Überschneidungen zwischen Tile-Array- und Objektkoordinaten kommen (also unvollständige Überdeckung, weil eine Abbildung der Objekt-Koordinaten in Pixeln auf den Tile-Array-Index keine ganzzahlige Angelegenheit mehr ist, sobald ein Tile 2 Pixel pro Richtung groß ist. Eine Objekt-Koordinate in Pixeln kann dann einem "halben" Tile entsprechen).

Man muß also in "ganzen Tiles" den Bereich ermitteln, den das Objekt überdeckt.

Dieser Bereich ermittelt sich wie folgt, wenn die Tiles 8*8 Pixel groß sind:

Startposition des Bereiches in X: (ObjectPosX + 7) &~ 8
Startposition des Bereiches in Y: (ObjectPosY + 7) &~ 8

Anzahl "ganze" Tiles in X, die das Objekt überdeckt: (((ObjectPosX + ObjectSizeX) + 7) &~ 8 ) - Startposition in X

Anzahl "ganze" Tiles in Y, die das Objekt überdeckt: (((ObjectPosY + ObjectSizeY) + 7) &~ 8 ) - Startposition in Y

Die ermittelten Werte sind Indizes innerhalb des Tile-Arrays, also "ganze" Tiles (!). Damit weißt Du, welche Tiles innerhalb des Arrays neu gezeichnet werden müssen. Das funktioniert genauso bei hexagonalen Tiles, vorausgesetzt, Du bekommst die Koordinaten in ein 2D-Array transformiert.


Das ist ungefähr das Gleiche wie ich es machen will mit den 4 Eckpunkten pro Objekt, denke ich. Was ist da schneller? Was macht (ObjektPosX +7) &~ 8 nochmal genau? Wird hier mit Nicht-8 UND-verknüpft (also mit 0111)?

Zitat:
In Deinem Fall ist das Ganze sogar noch ein wenig simpler, fällt mir gerade auf. Bei Deiner Grafik kann ein Objekt maximal 3 Tiles überdecken, da läßt sich das bestimmt noch stark vereinfachen (also nur mit den Objektkoordinaten arbeiten, die Größe des Objekts spielt dann wohl nur eine sehr untergeordnete Rolle).

Das ist richtig. Dazu kommen aber noch Überdeckungen von Objekten untereinander (Cursor über Turm usw.). Dafür hab ich die Layer eingeführt. In meiner ersten Version war auch nicht die Überdeckung das Problem, aber wenn mal mehrere animierte Objekte auf dem Schirm waren, wurde das Ganze sehr langsam. Hab noch nicht rausgefunden wieso, denke aber, dass die ganzen Iterationen, die im Animations- und Überdeckungsalgorithmus stattfinden Schuld waren.

Ciao

[ Dieser Beitrag wurde von Reth am 02.03.2006 um 08:55 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 09:12 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von Micha1701:
Hi!

Ich hab in Realms of Power ebenfalls Tiles verwendet. Und diese überlagern meist das darüber liegende Tile (z.B. Berge oder auch Einheiten). Damit ich jetzt nicht alles neu zeichnen mußte, hab ich einfach den zu bemalenden Bereich beschränkt. Dazu einfach mit Region() und InstallClipRegion() den Bereich beschränkt. Dann mußte ich nur den Teil um das zu ändernde Tile neu zeichnen. Alles andere wird dann ja nicht "zerstört".

Vielleicht hilft Dir das weiter.
--
:boing: Micha :boing:

http://www.Silicon-Wizards.com


Wie funktioniert das denn genau? Kannst Du da n kleines Bsp. posten?
Was machst Du wenn die umgebenden Bereiche, die Du neu zeichnest wieder andere Sachen überdecken, die aber über ihnen liegen und daher auch neu gezeichnet werden müssten?

Ciao

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 10:16 Uhr

Micha1701
Posts: 938
Nutzer
Also mit ner Region und Rectangle (siehe graphics.library) kannste angeben welcher Bereich in einem Layer überhaupt überzeichnet werden darf. Das wird einfach in den absoluten Pixel-Koordinaten angegeben.

Das kannst Du Dir als eine Art Schabone oder Maske vorstellen. Alles was nicht innerhalb dieses Bereiches liegt, wird einfach nicht beschrieben. Egal wie oft Du da rummalst.

Hier mal ein Beispiel:
Bild: http://www.lanser-web.com/kram/beispiel.PNG

Wenn man hier das Grüne Tile neu zeichnen würde, dann müste man die darunter liegenden roten und grünen Tiles auch neu zeichnen, was dann wiederum das hellblaue zerstören würde. Mit der Region (schwarzer Rahmen) würde verhindert, daß beim zeichnen des roten und gelben Tiles das hellblaue übermalt wird. Somit sind hier nur 3 Tiles neu zu zeichnen und nicht das hable Bild...

Schau Dir in den Autodocs mal die Infos zu Rectangle und Region an. Das hat mir damals auch schon weitergeholfen...
--
:boing: Micha :boing:

http://www.Silicon-Wizards.com

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 10:32 Uhr

bubblebobble
Posts: 707
Nutzer
Zitat:
Bekannt sein muß dafür die Anzahl der X-Koordinaten pro Zeile.

Dann ist Eintrag(x, y): Array[y * x]

Simpel, oder?


Aua!!! Da zieht es einem ja die E*** zusammen!
Das muss heissen: Array[y * Breite + x]

Ein Geschwindigkeitproblem sehe ich aber nicht.
Es gibt viele Möglichkeiten, eine Tilemap zu machen.
Es hängt stark von der Zielplattform ab, was nun am schnellsten ist.
Wenn es auf Grafikkarte laufen soll, ist es ab besten immer alles neu zu malen, also nichts zu retten.

Noch ein Gedankengang:
Dein Algorithmus muss nicht effizient sein, wenn wenig auf dem Bildschirm los ist, sondern er muss effizient sein, wenn VIEL los ist, denn nur dann bekommst du logischerweise Speed Probleme. Dessen muss man sich erstmal bewusst werden, das hat bei mir eine Weile gedauert...

Z.b. bei der normalen Version von AsteroidsTR wird der gesammte Screen (640x480!) in jedem Frame neu gemalt. Das ist natürlich vollkommen übertrieben wenn sich nur ein kleines Raumschiff bewegt, wo eine Fläche von 30x30 sich verändert. Aber es ist wesentlich schneller, wenn ich 200 Objekte rumwuseln habe, wo ich sonst eben 200x kleine Rechtecke bearbeiten würde. Und Probleme bekomme ich eben nur in solchen Situationen, nicht wenn der Bildschirm fast leer ist.

--
Thilo Köhler, Author von:
HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, TKUnpacker
Homepage: http://www.hd-rec.de


[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 10:52 Uhr

Reth
Posts: 1858
Nutzer
@bubblebobble:

Danke. Aber wie siehts mit dem Ablegen einer solchen Karte
http://people.freenet.de/WizardGrounds/images/Beginn.png
in ein Array aus? Mit der Formel y*Breite + x bekomme ich ne eindeutige lineare Zuordnung.
Allerdings würde ich bei einer Map wie im Bild die weißen Bereiche mit ins Array legen müssen, obwohl die nie verwendet werden.
Du arbeitest mit DoubleBuffering, oder. Aber ist das auch noch ratsam (bezogen auf den ganzen Bildschirm), wenn man mit nem 1024x768x8 Screen arbeitet?

@Micha1701:

Auch danke. Werde mir die diesbezüglichen Dokumente mal reinziehen.

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 11:04 Uhr

bubblebobble
Posts: 707
Nutzer
Zufälligerweise schreibe ich auch gerade eine Tile Engine, die für ISO Grafiken geeignet ist. Die Bodentiles haben auch mehrere Layers, z.B. Wasser, Schnee auf "normalem" Boden. Dann gibt es noch Gegenstände auf den Tiles, Bäume, Häuser etc. die dann natürlich mal vor und mal hinter den Figuren sein können.

Die sauberste Lösung sowas zu implementieren ist, eine Funktion zu schreiben, die den Hintergrund in einem beliebigen Ausschnitt neu zeichnet, incl. aller beweglichen Objekte,
also sowas wie DrawTiles(x1,y1,x2,y2). Die beweglichen Objekte müssen dafür natürlich alle durchprobiert werden, ob sie in das Rechteck hineinfallen. Das kann man aber erstmal Brute-Force machen, also einfach alle druchchecken. Wenn es nicht gerade ein A500 ist, macht das überhaut nichts aus an Speed. Ich weiss ja nicht wieviele Objekte du planst, aber eine For... Schleife von 0 bis 1000 mit ein paar "If"s braucht so gut wie keine Rechenzeit auf einer aktuellen Maschine. Ma blockiert sich da leider oft selbst durch alte Denkweisen, die für einen A500 noch zutrefen, aber heute sehen die Geschwindigkeitsverhältnisse eben komplett anders aus.

Um zu wissen, welche Bereiche sich geändert haben, legst du eine Liste an, eine "DamageList". Wenn sich ein Objekt bewegt, dann fügst du ein Element ein, mit den alten Koordinaten (Das objekt soll ja verschwinden) und mit den neuen Koordinaten (das Objekt soll ja wieder auftauchen). Beim Einfügen kann man ja noch stark überlappende Rechtecke zusammenfassen, z.B. wenn das Objekt sich 1 Pixel bewegt, macht es keinen sinn, zweimal fast den selben Ausschnitt zu zeichnen.

Die Objekte werden also im Gameloop erstmal nicht sofort gezeichnet, sondern nur die DamageList erstellt. Am Ende, wenn sich alle Objekte und Aminmationen eingetragen haben, wird die DamageList mit der o.g. Funktion abgearbeitet.
Ich würde dafür allerdings trotzdem eine Art Doublebuffering benutzen, d.h. du malst deine Refresh Rechtecke erstmal in einen nicht sichtbaren Rastport, und blittest den fertigen Bildausschnitt in den sichtbaren bereich. Alles andere wird nciht akzeptabel aussehen!

Woher weiss ich, ob ein Baum vor oder hinter einer Figur ist?
Bei ISO ist das einfach:
Zuerst entscheidet das Tile, auf der Baum steht, ob er vor oder hinter der Figur ist. Ist das Tile der Figur "weiter vorne", dann ist auch die Figur weiter vorne. Probleme gibt es nur, wenn die Figur auf dem gleichen Tile steht wie der Baum. Daher definiert man für jedes Ojekt einen "Hotspot", beim Baum z.B. ein Pixel auf dem Baumstumpf, bei der Figur der Boden zwischen dein Beinen. (wie aus Papier ausgeschnittene Figuren, die eine Nadel am boden haben, mit denen sie "aufgepinnt" sind. Bei gleichem Tile enstscheidet dann die Y Koordinate des Hotspots, ver vorne liegt.
Dadruch lassen sich ohne Probleme Bäume, Zäune, Häuser, Torbögen etc. realisieren. Ein Haus, wo man heineingene kann, oder ein Tempel mit Säulen muss dann allerdings aus mehreren Objekten bestehen, aber das muss er soweiso.


--
Thilo Köhler, Author von:
HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, TKUnpacker
Homepage: http://www.hd-rec.de


[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 11:14 Uhr

bubblebobble
Posts: 707
Nutzer
Die weissen Randbereiche würde ich einfach mitspeichern. Ansosnten könntest du das Koordinatensystem quasi drehen, aber damit machst du es nur kompliziert. Wie gross soll den die Karte maximal werden ? Wenn es tatsächlich nur ein Bildschirm werden soll, bracht man sich darüber keine Gedanken machen.

Warum du unbedingt eine eindimensionales Array haben willst und was du mit Hash Werten vorhast ist mir noch nicht ganz klar. Im Array findest du jede Element sofort mit dem Aufwand 1. Wenn du feststehende Objekte einsetzt, hängt sie einfach an eine Liste dran auf dem Tile wo sie stehen. Bewegliche Objekte würde ich immer alle durchscannen, so viele werden es ja nicht werden, oder ?


--
Thilo Köhler, Author von:
HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, TKUnpacker
Homepage: http://www.hd-rec.de


[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 11:16 Uhr

bubblebobble
Posts: 707
Nutzer
@Doublebuffering

Double Buffering heiss nicht zwangsläufig, dass du den kompletten Screen refreshen musst. Bei einer hohen Auflösung wäre das zu langsam. Aber du kannst den zu refreshenden Grafikbreich auf einer unsichbaren Bitmap zusammenbauen, und dann auf einen Rustch rüberblitten. Das brauchst du natülrich nur, wenn du mehr als einen Layer hast. Alles andere wird nicht zufriedenstellen aussehen und flackern wie wild, glaub mir.

--
Thilo Köhler, Author von:
HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, TKUnpacker
Homepage: http://www.hd-rec.de


[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 11:26 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:

Zitat:
Original von whose:
@Reth:

Bekannt sein muß dafür die Anzahl der X-Koordinaten pro Zeile.

Dann ist Eintrag(x, y): Array[y * x]

Simpel, oder?


Aber dann haben die Objekte mit gleichen vertauschten Koordinatenwerten ja denselben Eintrag!
Also x=3 und y=4 bilden auf dieselbe Arrayposition ab wie x=4 und y=3!? Oder meintest Du Array[x, y]?


Argh! Jetzt weiß ich, was mir die ganze Zeit an dem Posting nicht gefiel...

Da fehlt ein "+ x". Eintrag(x, y) = Array[y * x + x]

Zitat:
Zitat:
Worauf Du unbedingt achten mußt ist, so wenig Zeichenvorgänge wie möglich pro Frame zu erreichen und nicht zu lange durch die Koordinatenberechnungen zu laufen.

Das will ich ja mit den Layerlisten erreichen. Allerdings bei den Koordinatenberechnungen weiss ich noch nicht, wie ich das optimal gestalten kann. Habe mir im Moment diesen Ansatz überlegt:

Wenn ein Objekt seine Position ändert => finden seiner Liste in der Map. Aufnehmen der Layerliste an dieser Position in die Damagelist. Durchgehen aller Objekte in der Liste, prüfen der 4 Eckpunkte jedes dieser Objekte (also jeden Layer an dieser Position), ob diese andere Objekte überlappen (hier wärs halt sehr von Vorteil, wenn ich eindimensional arbeiten könnte, da ich dann direkt in der HashMap die überlappenden Objekte finde). Für jede so gefundene andere Layerliste diese in die Damagelist aufnehmen und den Vorgang wiederholen.
Denke aber nicht, dass das performant ist (Dominoeffekt).


Da kann die von Micha angeregte Verwendung von ClipRects helfen. Zumindest entgehst Du damit dem unnötigen Neuzeichen von Objekten auf den umliegenden Tiles. Verstehst, was ich meine?

Wenn Du ein Objekt neu zeichnen mußt, welches ein Tile überdeckt, auf dem eigentlich keine Objekte neu gezeichnet werden müßten, mußt Du ohne Clipping diese Objekte trotzdem neu zeichnen, weil ja das Tile neu gezeichnet werden muß. Das zieht dann ein Neuzeichnen weiterer Tiles nach sich, auf dem möglicherweise wieder Objekte sind, die dann neugezeichnet werden müssen...

Das ist der von Dir angesprochene Domino-Effekt, weil sich das im ungünstigen Fall so auswirken kann, daß Du wegen einem Objekt das gesamte Bild neu aufbauen mußt.

Das kannst Du verhindern, indem Du das Zeichnen auf den Bereich, den das Objekt berührt, mittels ClipRect begrenzt. Dann reicht es, einfach das Tile neu zu zeichnen, welches von einem Objekt überdeckt wird. Die weiter entfernt liegenden Objekte auf diesem Tile werden davon dann nicht berührt (weil durch das Clipping das Tile quasi zerschnitten wird) und müssen dann auch nicht neu aufgebaut werden.

Dazu wäre es nützlich, wenn Du Dir einen Algorithmus einfallen läßt, der die von einem Neuzeichnen betroffenen Koordinaten ermittelt. Alle Tiles und Objekte, die sich mit ihrer Basis in dem Bereich befinden, müssen eh neu gezeichnet werden und ggf. die Tiles, die diesen Bereich schneiden. Wenn Du den ermittelten Bereich gleichzeitig als ClipRect verwendest, wird das Zeichnen auf die tatsächlich betroffenen Objekte sowie die unmittelbar betroffenen Tiles begrenzt.

Objekte, deren Basis außerhalb dieses Bereichs liegt, brauchen dann nicht neu gezeichnet zu werden, da die Zeichenperation deren "Gebiet" nicht betrifft.

Du solltest dabei aber darauf achten, daß sich Objekte benachbarter Tiles nicht in zu großer Zahl und wenn dann nur in geringer Entfernung zueinander überschneiden können, sonst artet der Domino-Effekt in anderer Weise aus (Ermittlung der ClipRects).

Zitat:
Die Damagelist wird dann Layer für Layer komplett neu gezeichnet (in dem einen Artikel auf gamedev.net steht glaub, dass erst alle Layer eines Bereiches gezeichnet werden, bevor die des anderen Bereiches drankommen, um Abschneiden von Objekten zu verhindern. Also entweder hab ich in dem Artikel was missverstanden oder passiert dadurch doch genau das: Objekte können abgeschnitten werden.

Es kann Dir passieren, daß Objekte "aus Versehen" von Objekten einer unteren Ebene übermalt werden, wenn Du die Reihenfolge nicht korrekt einhältst. Das kann so weit gehen, daß ein neu zu zeichnendes Tile ein gerade neu gezeichnetes Objekt eines Nachbartiles übermalt. Das wäre dann abgeschnitten.

Zitat:
Zitat:
Einziger Nachteil bei dieser Engine ist bisher nur, daß die noch nicht mit überlappenden Sprites klarkommt, da wird der Hintergrund noch doppelt gezeichnet unnötigerweise.

Genau das Problem hab ich momentan. Wenns nur ein Objekt überm Hintergrund wäre, wärs einfacher. So aber hab ich Objekte in versch. Ebenen, die sich gegenseitig überdecken können.


Bei Dir ist es ein wenig komplizierter, weil die Überdeckungen quasi "weitergereicht" werden können und ggf. zum Schluß das ganze Bild betreffen.

Bei den Sprites ist es einfacher, da nerven nur möglicherweise doppelt erneuerte Tiles (wenn sich mehrere Sprites überlappen, würde ein Teil der darunter liegenden Tiles mehrfach gezeichnet, obwohl das unnötig ist).

Zitat:
Zitat:
(Edit) Vielleicht fällts Dir leichter, wenn Du Dir die Grafik vorstellst wie übereinandergelegte Overhead-Folien. Für jedes Objekt eine eigene Folie, die Hintergrund-Tiles bilden eine einzige Folie. Je nachdem, wie Du die "Folien" der Objekte verschiebst, sind ein oder mehrere Tiles auf der Hintergrund-"Folie" überdeckt.

Genauso ist meine Grafik aufgebaut. Jedes Objekt hat einen Layer zugeordnet. Objekte innerhalb des selben Layers können sich nicht überdecken.


Diese Beschränkung ist weise ;)

Damit machst Du Dir das Leben leichter, weil die Überdeckungen dann nicht auf allen Ebenen weitergereicht werden können, sondern höchstens von Ebene zu Ebene in einem beschränkten Bereich. Da helfen ClipRects dann mit Sicherheit weiter (s.O.).

Zitat:
Zitat:
Dieser Bereich ermittelt sich wie folgt, wenn die Tiles 8*8 Pixel groß sind:

Startposition des Bereiches in X: (ObjectPosX + 7) &~ 8
Startposition des Bereiches in Y: (ObjectPosY + 7) &~ 8

Anzahl "ganze" Tiles in X, die das Objekt überdeckt: (((ObjectPosX + ObjectSizeX) + 7) &~ 8 ) - Startposition in X

Anzahl "ganze" Tiles in Y, die das Objekt überdeckt: (((ObjectPosY + ObjectSizeY) + 7) &~ 8 ) - Startposition in Y

Die ermittelten Werte sind Indizes innerhalb des Tile-Arrays, also "ganze" Tiles (!). Damit weißt Du, welche Tiles innerhalb des Arrays neu gezeichnet werden müssen. Das funktioniert genauso bei hexagonalen Tiles, vorausgesetzt, Du bekommst die Koordinaten in ein 2D-Array transformiert.


Das ist ungefähr das Gleiche wie ich es machen will mit den 4 Eckpunkten pro Objekt, denke ich. Was ist da schneller? Was macht (ObjektPosX +7) &~ 8 nochmal genau? Wird hier mit Nicht-8 UND-verknüpft (also mit 0111)?


(char angenommen) Es wird mit 11111000 UND-verknüpft. Der Gag dabei ist die vorherige Addition von 7. Mit der Mimik erreichst Du, daß Du nur ganze Zahlen erhältst, die durch 8 teilbar sind. Wenn Du z.B. ein Objekt auf der Koordinate x = 9 liegen hast, muß diese Koordinate für die Umrechnung in einen Array-Index irgendwie auf "ganze" Indizes erweitert werden. Mit dem Krempel von oben käme dann (9 + 7) = 16 heraus, das &~8 hätte darauf keinen Einfluß. 16 läßt sich gut durch 8 teilen...

Was passiert, wenn das Objekt auf Koordinate x = 10 steht? (10 + 7) = 17. Schlecht durch 8 teilbar... das &~8 sorgt dann dafür, daß daraus wieder 16 wird. Dieses Spielchen bleibt so bis x = 16 ( (16 + 7) = 23 &~8 = 16), bei x = 17 "springt" das auf den Wert 24 und bleibt so bis x = 24, bei x = 25 auf den Wert 32 etc. Wenn Du das in Gedanken auf ein Raster überträgst (also ein Array) wirst Du feststellen, daß dadurch immer das richtige "Kästchen" des Rasters angesprochen wird oder eben der richtige Index eines Arrays, wenn Du das Ergebnis durch 8 teilst (die Größe eines Tiles in Pixel).

Zitat:
Zitat:
In Deinem Fall ist das Ganze sogar noch ein wenig simpler, fällt mir gerade auf. Bei Deiner Grafik kann ein Objekt maximal 3 Tiles überdecken, da läßt sich das bestimmt noch stark vereinfachen (also nur mit den Objektkoordinaten arbeiten, die Größe des Objekts spielt dann wohl nur eine sehr untergeordnete Rolle).

Das ist richtig. Dazu kommen aber noch Überdeckungen von Objekten untereinander (Cursor über Turm usw.). Dafür hab ich die Layer eingeführt. In meiner ersten Version war auch nicht die Überdeckung das Problem, aber wenn mal mehrere animierte Objekte auf dem Schirm waren, wurde das Ganze sehr langsam. Hab noch nicht rausgefunden wieso, denke aber, dass die ganzen Iterationen, die im Animations- und Überdeckungsalgorithmus stattfinden Schuld waren.


Ich denke eher, daß da der Domino-Effekt ins Spiel kam, weil dann wohl jedesmal, wenns etwas ungünstig lief, das gesamte Bild neu gezeichnet wurde (s.O.). Da helfen die ClipRects.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 11:48 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:
@bubblebobble:

Danke. Aber wie siehts mit dem Ablegen einer solchen Karte
http://people.freenet.de/WizardGrounds/images/Beginn.png
in ein Array aus? Mit der Formel y*Breite + x bekomme ich ne eindeutige lineare Zuordnung.
Allerdings würde ich bei einer Map wie im Bild die weißen Bereiche mit ins Array legen müssen, obwohl die nie verwendet werden.
Du arbeitest mit DoubleBuffering, oder. Aber ist das auch noch ratsam (bezogen auf den ganzen Bildschirm), wenn man mit nem 1024x768x8 Screen arbeitet?

@Micha1701:

Auch danke. Werde mir die diesbezüglichen Dokumente mal reinziehen.


Zu dem Thema ist auf gamedev.net der Artikel, von dem ich sprach. Ich weiß jetzt nicht mehr genau, welcher das war, aber da gings auch um Hextiles und deren Anordnung in einem 2D-Array. Wenn ich mich recht erinnere, war das so gelöst, daß die Tiles einer Reihe auch in die entsprechende Reihe des 2D-Arrays eingetragen wurden und bei Berechnungen/Zeichenoperationen der Zeichen-Offset berücksichtigt wurde.

Du hast da ja immer eine Verschiebung um einen festen Betrag drin, wenn Du Dir die Hextiles als Rechtecke denkst. In Deinem Fall findet diese Verschiebung seitlich statt, das Nachbartile rechts oder links ist immer um einen bestimmten Betrag (untere/obere Kantenlänge eines Tiles) versetzt gezeichnet. Wenn Du diesen Offset bei Berechnungen berücksichtigst, kannst Du Hextiles genau wie rechteckige Tiles behandeln und auch so in einem Array ablegen. Die "leeren" Bereiche sind dabei völlig uninteressant.

Alles, was dabei "leer" bleibt, sind die nicht durch ein Tile besetzten Indizes in dem Map-Array. Die kannst Du aber recht einfach "überlesen", da die Anzahl der Tiles pro Zeile jeweils bekannt ist. Wahlweise kannst Du auch das Array um einen Eintrag in X-Richtung größer machen und in Array[0, y] die Anzahl der enthaltenen Tiles vorhalten. So riesig fällt das Array bei Dir ja nicht aus und selbst bei größeren Arrays fällt ein Eintrag mehr oder weniger nicht so sehr ins Gewicht. Die ungenutzten Einträge tun da auch nicht so sehr weh, finde ich.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 11:59 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von whose:
Zitat:
Original von Reth:
Die Damagelist wird dann Layer für Layer komplett neu gezeichnet (in dem einen Artikel auf gamedev.net steht glaub, dass erst alle Layer eines Bereiches gezeichnet werden, bevor die des anderen Bereiches drankommen, um Abschneiden von Objekten zu verhindern. Also entweder hab ich in dem Artikel was missverstanden oder passiert dadurch doch genau das: Objekte können abgeschnitten werden.


Es kann Dir passieren, daß Objekte "aus Versehen" von Objekten einer unteren Ebene übermalt werden, wenn Du die Reihenfolge nicht korrekt einhältst. Das kann so weit gehen, daß ein neu zu zeichnendes Tile ein gerade neu gezeichnetes Objekt eines Nachbartiles übermalt. Das wäre dann abgeschnitten.


Darum meinte ich ja, dass man alle Bereiche Ebene für Ebene zeichnen muss und zwar auf einmal. Nicht Bereich1 alle Ebenen, dann Bereich2 alle Ebenen, etc. Dann sollte es klappen, denke ich.

Zitat:
(char angenommen) Es wird mit 11111000 UND-verknüpft.

Aber wie kommt da das NICHT (~) zum tragen?

Zitat:
Der Gag dabei ist die vorherige Addition von 7. Mit der Mimik erreichst Du, daß Du nur ganze Zahlen erhältst, die durch 8 teilbar sind. Wenn Du z.B. ein Objekt auf der Koordinate x = 9 liegen hast, muß diese Koordinate für die Umrechnung in einen Array-Index irgendwie auf "ganze" Indizes erweitert werden. Mit dem Krempel von oben käme dann (9 + 7) = 16 heraus, das &~8 hätte darauf keinen Einfluß. 16 läßt sich gut durch 8 teilen...

Ich nehm dafür immer Ganzzahl-Division ohne Rest (/).
Ist das von Dir beschriebene Verfahren schneller?
Also wenn ich den Index im Array zu einer Koordinate ermitteln will nehm ich die Koordinatenwerte dividiert durch 8 ohne Rest.
Z.B. (x,y) = (10,10) => Arrayindex = (10/8=1,10/8=1)
also an Position (1,1) im Array (dieses beginnt bei (0,0)).

Ciao

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 12:32 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von whose:
Zu dem Thema ist auf gamedev.net der Artikel, von dem ich sprach. Ich weiß jetzt nicht mehr genau, welcher das war, aber da gings auch um Hextiles und deren Anordnung in einem 2D-Array. Wenn ich mich recht erinnere, war das so gelöst, daß die Tiles einer Reihe auch in die entsprechende Reihe des 2D-Arrays eingetragen wurden und bei Berechnungen/Zeichenoperationen der Zeichen-Offset berücksichtigt wurde.


Den hab ich gelesen, aber nicht sosehr auf mich gemünzt, da deren Tiles immer am linken und oberen Rand beginnen, ich aber ja die weißen Bereiche habe, aber die kann ich ja ignorieren und die entspr. Felder leer lassen.

Ciao

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 12:35 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:
Zitat:
Original von whose:
Zitat:
Original von Reth:
Die Damagelist wird dann Layer für Layer komplett neu gezeichnet (in dem einen Artikel auf gamedev.net steht glaub, dass erst alle Layer eines Bereiches gezeichnet werden, bevor die des anderen Bereiches drankommen, um Abschneiden von Objekten zu verhindern. Also entweder hab ich in dem Artikel was missverstanden oder passiert dadurch doch genau das: Objekte können abgeschnitten werden.


Es kann Dir passieren, daß Objekte "aus Versehen" von Objekten einer unteren Ebene übermalt werden, wenn Du die Reihenfolge nicht korrekt einhältst. Das kann so weit gehen, daß ein neu zu zeichnendes Tile ein gerade neu gezeichnetes Objekt eines Nachbartiles übermalt. Das wäre dann abgeschnitten.


Darum meinte ich ja, dass man alle Bereiche Ebene für Ebene zeichnen muss und zwar auf einmal. Nicht Bereich1 alle Ebenen, dann Bereich2 alle Ebenen, etc. Dann sollte es klappen, denke ich.


Genau, immer fein von unten nach oben alles behandeln, was neu gezeichnet werden muß. Interessant ist eigentlich nur, wie Du die zu zeichnenden Bereiche ermitteltst.

Wenn Du ClipRects verwendest, begrenzt Du die Anzahl der Zeichenoperationen pro Ebene auf das wirklich notwenige. Denk Dir die ClipRects als Schablone beim Lackieren, dann verstehst Du das leichter. Die Schablone muß so groß gewählt werden, daß sie alle von einer Zeichenoperation betroffenen Objekte umschließt. Die Tiles werden dabei beschnitten (und die sind das eigentliche Übel bei Dir, denn die Tiles "reichen die Überlappungen weiter").

Zitat:
Zitat:
(char angenommen) Es wird mit 11111000 UND-verknüpft.

Aber wie kommt da das NICHT (~) zum tragen?


8 ist Binär 00000111. Du würdest Zahlen >8 dann auf 8 begrenzen, wenn Du mit 8 statt ~8 UND-Verknüpfst. Rechne das mal mit unterschiedlichen Zahlen durch, dann verstehst Du, wie das funktioniert.

Zitat:
Zitat:
Der Gag dabei ist die vorherige Addition von 7. Mit der Mimik erreichst Du, daß Du nur ganze Zahlen erhältst, die durch 8 teilbar sind. Wenn Du z.B. ein Objekt auf der Koordinate x = 9 liegen hast, muß diese Koordinate für die Umrechnung in einen Array-Index irgendwie auf "ganze" Indizes erweitert werden. Mit dem Krempel von oben käme dann (9 + 7) = 16 heraus, das &~8 hätte darauf keinen Einfluß. 16 läßt sich gut durch 8 teilen...

Ich nehm dafür immer Ganzzahl-Division ohne Rest (/).
Ist das von Dir beschriebene Verfahren schneller?
Also wenn ich den Index im Array zu einer Koordinate ermitteln will nehm ich die Koordinatenwerte dividiert durch 8 ohne Rest.
Z.B. (x,y) = (10,10) => Arrayindex = (10/8=1,10/8=1)
also an Position (1,1) im Array (dieses beginnt bei (0,0)).


Und was passiert bei, sagen wir, 12/8? Das ist 1.5. Wie wird das gerundet?

Das ist implementierungsabhängig ;) Je nach Compiler/Typ der Operanden geht das in die Hose und Du bekommst 2 statt 1. Richtig kritisch wirds ab 13...

Mit dem Verfahren oben bekommst Du immer die (fast) korrekt für unsere Zwecke gerundete Ganzzahl. Bei x=9 käme dabei 2 raus, was dem richtigen Index+1 (!) entspricht. Bei x=17 gäbe das 3, was ja auch richtig ist, da die Koordinate 17 das dritte Tile berührt (immer davon ausgegangen, daß ein Tile 8 Pixel groß ist). Einziger Fallstrick hierbei ist die in C/C++ verwendete Indexierung, die nun einmal bei 0 beginnt und nicht bei 1. Daher mußt Du das Ergebnis um 1 verringern, um den korrekten Index im Array zu erhalten.

Aber das eigentlich wichtige: Du bist dadurch unabhängig vom Rundungsverhalten des Compilers im Zusammenhang mit Ganzzahlen.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 12:36 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:
Zitat:
Original von whose:
Zu dem Thema ist auf gamedev.net der Artikel, von dem ich sprach. Ich weiß jetzt nicht mehr genau, welcher das war, aber da gings auch um Hextiles und deren Anordnung in einem 2D-Array. Wenn ich mich recht erinnere, war das so gelöst, daß die Tiles einer Reihe auch in die entsprechende Reihe des 2D-Arrays eingetragen wurden und bei Berechnungen/Zeichenoperationen der Zeichen-Offset berücksichtigt wurde.


Den hab ich gelesen, aber nicht sosehr auf mich gemünzt, da deren Tiles immer am linken und oberen Rand beginnen, ich aber ja die weißen Bereiche habe, aber die kann ich ja ignorieren und die entspr. Felder leer lassen.


Genau. Ich denke mal, dann läßt sich die ganze Geschichte deutlich leichter rechnen (und vor allem überschauen ;) ).

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 12:47 Uhr

Reth
Posts: 1858
Nutzer
Zitat:
Original von whose:

8 ist Binär 00000111.


Halt! 8 ist binär 00001000 !
D.h. Du verknüpfst mit 11110111.

Zitat:
Und was passiert bei, sagen wir, 12/8? Das ist 1.5. Wie wird das gerundet?

Das ist implementierungsabhängig ;) Je nach Compiler/Typ der Operanden geht das in die Hose und Du bekommst 2 statt 1. Richtig kritisch wirds ab 13...


Halt, halt! Von Runden hab ich nichts gesagt. Es ist eine reine Ganzzahldivision von Integerwerten ohne Rest.
D.h. alles geteilt durch 8, was einen Rest ergibt ergibt die Zahl vorm Komma, also:

...
9/8 = 1
10/8 = 1
11/8 = 1
12/8 = 1
...
15/8 = 1
16/8 = 2
...

Zitat:
Das bedeutet, es wird immer automatisch zum richtigen Index umgeschalten, wenn Deine Tiles 8 Pixel breit sind.

Mit dem Verfahren oben bekommst Du immer die (fast) korrekt für unsere Zwecke gerundete Ganzzahl. Bei x=9 käme dabei 2 raus, was dem richtigen Index+1 (!) entspricht. Bei x=17 gäbe das 3, was ja auch richtig ist, da die Koordinate 17 das dritte Tile berührt (immer davon ausgegangen, daß ein Tile 8 Pixel groß ist). Einziger Fallstrick hierbei ist die in C/C++ verwendete Indexierung, die nun einmal bei 0 beginnt und nicht bei 1. Daher mußt Du das Ergebnis um 1 verringern, um den korrekten Index im Array zu erhalten.


Und eben hier hast Du keine Probleme mit dem von mir beschriebenen Verfahren, denn alles < 8 (also 0 bis 7) geteilt durch 8 gibt damit immer 0.

Ciao

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 14:23 Uhr

bubblebobble
Posts: 707
Nutzer
Also ich habe mir mal die Tuts reingelesen, kann ich nicht uneingeschränkt empfehlen, es sei denn du hast vor, dass sich die Figuren nur Blockweise bewegen. Wenn du eine wirklich "freie" ISO Grafik haben willst, mit vorder und Hintergrund, muss man das ein wenig anders machen.

Die vorgehensweise vom ersten Tut entspricht auch nicht wie man es mit der Amiga API machen würde.

Vergiss auch die Listen! Heute hat man genug Speicher, das ist nur umständlich und schwer zu implementieren.

Beschreibe doch nochmal genau, was die Anforderungen sind.

Zum Doublebuffering:
Du allocierst den Screen und einen unsichtbaren Rastport, der genauso gross ist wie der Screen.
Wenn du eine Fläche refreshen willst, dann zeichne sie einfach auf den unsichtbaren Rastport, und wenn du fertig bist swappe es auf den Screen.

Mach dir keinen so grossen Kopf wegen dem Rereshen. Schreibe einfach wie ich oben beschrieben habe eine Funktion, die einen beliebigen Ausschnitt komplett zeichnet, und benutze eine DamageList und InstallClipRegion() zum clippen.
Bewegliche Figuren kannst du in einem eigenen Array/Liste halten, und alle abfragen für jedesmal zeichnen, das braucht kaum Rechenzeit,
denn wenn viel los ist musst du soweiso fast alle neu zeichnen, und wenn wenig los ist dann spielt der overhead keine Rolle.

@whose
Nein, nicht y * x + x !!!!
y * Breite +x !!!!

--
Thilo Köhler, Author von:
HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, TKUnpacker
Homepage: http://www.hd-rec.de


[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 16:16 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:
Zitat:
Original von whose:

8 ist Binär 00000111.


Halt! 8 ist binär 00001000 !
D.h. Du verknüpfst mit 11110111.


Ich seh schon, ich sollte nicht posten, wenn ich grad arbeite, da gerät sonst einiges durcheinander... Du hast Recht. Der Effekt bleibt allerdings. Ich schicke Dir gleich mal die Quellcodes zu der Simpel-Sprite-Geschcihte, da kannst Du das dann auch ausprobieren.

Zitat:
Zitat:
Und was passiert bei, sagen wir, 12/8? Das ist 1.5. Wie wird das gerundet?

Das ist implementierungsabhängig ;) Je nach Compiler/Typ der Operanden geht das in die Hose und Du bekommst 2 statt 1. Richtig kritisch wirds ab 13...


Halt, halt! Von Runden hab ich nichts gesagt. Es ist eine reine Ganzzahldivision von Integerwerten ohne Rest.
D.h. alles geteilt durch 8, was einen Rest ergibt ergibt die Zahl vorm Komma, also:

...
9/8 = 1
10/8 = 1
11/8 = 1
12/8 = 1
...
15/8 = 1
16/8 = 2
...


Probier das mal weiter aus, mit anderen Typgrößen beispielsweise. Oder einem älteren Compiler...

Zitat:
Zitat:
Das bedeutet, es wird immer automatisch zum richtigen Index umgeschalten, wenn Deine Tiles 8 Pixel breit sind.

Mit dem Verfahren oben bekommst Du immer die (fast) korrekt für unsere Zwecke gerundete Ganzzahl. Bei x=9 käme dabei 2 raus, was dem richtigen Index+1 (!) entspricht. Bei x=17 gäbe das 3, was ja auch richtig ist, da die Koordinate 17 das dritte Tile berührt (immer davon ausgegangen, daß ein Tile 8 Pixel groß ist). Einziger Fallstrick hierbei ist die in C/C++ verwendete Indexierung, die nun einmal bei 0 beginnt und nicht bei 1. Daher mußt Du das Ergebnis um 1 verringern, um den korrekten Index im Array zu erhalten.


Und eben hier hast Du keine Probleme mit dem von mir beschriebenen Verfahren, denn alles < 8 (also 0 bis 7) geteilt durch 8 gibt damit immer 0.


Nicht immer. Spätestens, wenn eine Float-Zahl als Teiler ins Spiel kommt, wird implementierungsabhängig gerundet. Bei einfachen Algorithmen mag das so noch funktionieren, spätestens bei komplizierteren Sachen kommst Du da ins Rudern. Aber mach ruhig einstweilen so, solange Du einfache Rechnungen laufen hast. Solange nur Ganzzahlen verwendet werden, funktioniert das so...

@bubblebobble:

Hektik und Übermüdung, man möge mir verzeihen. In meinen Programmen stehts korrekt ;)

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 02.03.2006 um 16:35 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 16:27 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von bubblebobble:
Also ich habe mir mal die Tuts reingelesen, kann ich nicht uneingeschränkt empfehlen, es sei denn du hast vor, dass sich die Figuren nur Blockweise bewegen. Wenn du eine wirklich "freie" ISO Grafik haben willst, mit vorder und Hintergrund, muss man das ein wenig anders machen.

Die vorgehensweise vom ersten Tut entspricht auch nicht wie man es mit der Amiga API machen würde.

Vergiss auch die Listen! Heute hat man genug Speicher, das ist nur umständlich und schwer zu implementieren.


In C++ nicht unbedingt... dort sind simple Arrays wesentlich komplizierter zu handhaben, wenn man den Sinn der Sprache nicht außer Acht lassen mag. Aber das hätte Reth besser dazu geschrieben, daß er in C++ arbeitet.

Zitat:
Beschreibe doch nochmal genau, was die Anforderungen sind.

Zum Doublebuffering:
Du allocierst den Screen und einen unsichtbaren Rastport, der genauso gross ist wie der Screen.
Wenn du eine Fläche refreshen willst, dann zeichne sie einfach auf den unsichtbaren Rastport, und wenn du fertig bist swappe es auf den Screen.


Und wie swapt er das? ChangeVPBitmap()? Den ganzen Screen blitten? ScrollVP()? Das solltest Du vielleicht noch dazu sagen. Wenn er rasterstrahlsynchron bleiben will und nicht absolute Top-Speed braucht, tuts ChangeScreenBuffer().

Zitat:
Mach dir keinen so grossen Kopf wegen dem Rereshen. Schreibe einfach wie ich oben beschrieben habe eine Funktion, die einen beliebigen Ausschnitt komplett zeichnet, und benutze eine DamageList und InstallClipRegion() zum clippen.
Bewegliche Figuren kannst du in einem eigenen Array/Liste halten, und alle abfragen für jedesmal zeichnen, das braucht kaum Rechenzeit,
denn wenn viel los ist musst du soweiso fast alle neu zeichnen, und wenn wenig los ist dann spielt der overhead keine Rolle.

@whose
Nein, nicht y * x + x !!!!
y * Breite +x !!!!


Wie ich oben schon schrieb, Hektik und Übermüdung... genauer heißts: (y * Anzahl Spalten pro Zeile + x). Ich hoffe, das konnten wir jetzt so weit klären, das keine Aufregung mehr nötig ist ;)

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 23:11 Uhr

Reth
Posts: 1858
Nutzer
Hm, jetzt hab ich mein Hauptproblem (?) wieder entdeckt.
Ich habe meine Animationsklassen so entworfen, dass sie mit flexiblen Framegrößen umgehen können und ihre aktuelle Höhe und Breite kennen.
Es gibt dazu noch eine maximale Höhe und Breite.
Eine Animation kann aus beliebig vielen Frames mit unterschiedlichen Größen bestehen.

Das macht das Ganze nicht unbedingt leichter (im Hinblick auf Umsetzung von Pixelkoordinaten auf Arraykoordinaten).

Am besten erklär ich mal mein System, so wie es derzeit bei WizardGrounds zum Einsatz kommt:

Es gibt eine Frameklasse, die das eigentliche Bild beherbergt (Bitmap). Jedes Bild gibts nur einmal im Speicher.
Dann gibt es Animationsklassen, die beliebig viele Frames mit unterschiedlichen Größen enthalten können (zur Vereinfachung beim Blitten wird die maximale Größe über alle Frames bestimmt).
Darüber gibt es die Animationsklasse, die beliebig viele Animationen beherbergen kann (z.B. ein Gebäude kann untersch. Animationen haben für den Aufbau, den Ausbau, beschädiger Zustand, zerstörter Zustand etc.).
Abschließend gibt es noch die Verwalterklasse, die alle Animationsobjekte verwaltet.
Dieser Aufbau gilt für alle Elemente, auch die Hintergrundtiles, die animiert sein können. Damit geht das ganze Konzept mit Tilearray usw. flöten!

Das ist das ganze Prinzip. Warum einfach, wenns auch kompliziert geht!?

Naja, bin ja selbst schuld!

Ciao

[ Dieser Beitrag wurde von Reth am 02.03.2006 um 23:55 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

02.03.2006, 23:57 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Reth:
Hm, jetzt hab ich mein Hauptproblem (?) wieder entdeckt.
Ich habe meine Animationsklassen so entworfen, dass sie mit flexiblen Framegrößen umgehen können und ihre aktuelle Höhe und Breite kennen.
Es gibt dazu noch eine maximale Höhe und Breite.
Eine Animation kann aus beliebig vielen Frames mit unterschiedlichen Größen bestehen.

Das macht das Ganze nicht unbedingt leichter (im Hinblick auf Umsetzung von Pixelkoordinaten auf Arraykoordinaten).

Hm, muss ich mir nochmal reinziehen.


Nein, im Grunde ists auch dann genau das Gleiche. Du nimmst als Berechnungsgrundlage halt die dann aktuellen Größen (Position X/Y, Höhe und Breite des Animationsframes) und weißt, was so alles überdeckt wird davon. Unter anderem erfährst Du dann auch, ob dieses Objekt bereits in einem Damage-Bereich (ClipRect später!) liegt und ob es da noch ganz reinpaßt. Paßts nicht mehr ganz rein, ists an der Zeit, den Damage-Bereich zu vergößern

Nimm Dir dazu auch mal Michas, Thilos und meinen Rat zu Herzen, informier Dich über Sinn und Zweck von ClipRects. Wenn Du diese ClipRects in ihrer Größe so berechnest, daß alle Objekte auf ihren jeweiligen Positionen und in ihren aktuellen Größen da reinpassen, kannst Du für die Ermittlung der betroffenen Tiles (also die unterste Ebene!) sogar ganz simpel die ClipRect-Koordinaten nehmen.

Die Tiles müssen im Refresh dann ja als erstes gezeichnet werden und eben auch durch Clipping beim Zeichnen begrenzt werden, damit nicht am Refresh beteiligte Objekte unbehelligt bleiben.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]


-1- 2 3 [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Koordinatentransformation, Überdeckung [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.