Speichern eines Hex-Gitters

10

Ich habe ein kleines Hex-Grid-Framework für Unity3D erstellt und bin auf das folgende Dilemma gestoßen. Dies ist mein Koordinatensystem (von hier übernommen ):

Geben Sie hier die Bildbeschreibung ein

Es funktioniert alles ziemlich gut, bis auf die Tatsache, dass ich keine Ahnung habe, wie ich es aufbewahren soll. Ich wollte dies ursprünglich in einem 2D-Array speichern und Bilder verwenden, um meine Karten zu generieren.

Ein Problem war, dass es negative Werte hatte (dies konnte leicht durch ein wenig Versetzen der Koordinaten behoben werden).

Aufgrund dieses Koordinatensystems müsste ein solches Bild oder eine solche Bitmap jedoch rautenförmig sein - und da diese Strukturen quadratisch sind, würde dies viele Kopfschmerzen verursachen, selbst wenn ich etwas zusammen hacke. Fehlt mir etwas, das das beheben könnte? Ich erinnere mich, dass ich dazu einen Forumsbeitrag in den Unity-Foren gesehen habe, aber ich kann den Link nicht mehr finden.

Ist das Schreiben einer Reihe von Koordinatenübersetzern hier die beste Lösung?

Wenn ihr denkt, dass es hilfreich wäre, kann ich Code und Bilder meines Problems posten.

PeeC
quelle
1
Können Sie nicht einfach PNG-Bilder speichern, die um Sechsecke transparent sind?
Markus von Broady
Mein Hauptproblem beim Speichern in PNGs und Arrays ist die Menge an "Leerzeichen", die sie enthalten müssten, um dieses Koordinatensystem intakt zu halten.
PeeC
1
Wenn "Leerzeichen" transparente Pixel bedeutet, warum ist dann die Menge davon ein Problem?
Markus von Broady
Das ist ein sehr guter Punkt. Die meisten Bildformate verschwenden nicht so viel Speicher, in dem wiederholte Muster gespeichert werden. Aber dennoch, es ärgert mich etwas , dass zu speichern um diese Karte Ich bin mit diesen viel Speicher (graue Pixel sind leeren Raum, andere Farben sind gültig hex Koordinaten).
PeeC
1
Oh, Sie speichern die Rasterdaten, keine Kachelbilder! Warum speichern Sie Ihre Datenstrukturen (Raster) nicht einfach in einer Binärdatei oder codieren sie beispielsweise mit JSON und speichern sie in einer Textdatei? Ich kenne jedoch keine Fähigkeiten von Unity. Vielleicht möchten Sie dies auch bestätigen, aber ich glaube, dass ein Bereich derselben Farbe im PNG-Format optimiert (lose komprimiert) ist.
Markus von Broady

Antworten:

9

Die von Ihnen verwendeten Parallelogrammkoordinaten sind einfacher zu bearbeiten, haben jedoch den Nachteil, dass sie für rechteckige Karten seltsam sind. Ein Ansatz besteht darin, es mit den Versatzkoordinaten zu speichern, aber tatsächlich Parallelogrammkoordinaten in Ihrer Spiellogik zu verwenden.

Beobachtung: In jeder Zeile der Karte sind die Rasterdaten zusammenhängend. Der gesamte verschwendete Platz befindet sich links und rechts.

Lösung: Speichern Sie in dieser Zeile Daten, die in der linken Spalte anstelle der mit 0 gekennzeichneten Spalte beginnen. Berechnen Sie die erste Spalte der rechteckigen Karte in Ihrem Koordinatensystem und subtrahieren Sie diese von der Spaltenkoordinate, um zu bestimmen, wohin sie im Array geht. Dies funktioniert auch für negative Spaltenkoordinaten.

Führen Sie die Konvertierung im Getter und Setter für die Karte folgendermaßen durch:

inline function get(q, r) {
    first_column_in_this_row = -floor(q/2);
    return array[r][q - first_column_in_this_row];
}

Sie müssen dies ändern, um mit der Auswahl der Koordinaten und der Karte zu arbeiten (achten Sie auf einen Unterschied). In einigen Layouts möchten Sie die Spalten um die Zeile versetzen und nicht umgekehrt.

Mit demselben Trick können Sie Karten mit anderen Formen erstellen. Es ist nicht auf Rechtecke beschränkt.

Wenn Sie C oder C ++ verwenden, können Sie Zeigerarithmetik verwenden, um dies zu beschleunigen. Anstatt ein Array von Zeigern auf Arrays zu speichern, speichern Sie ein Array von Zeigern, die von angepasst wurden first_column_in_row. (Dies ist möglicherweise nicht tragbar)

amitp
quelle
Dies funktioniert soweit ich das beurteilen kann, aber die Mathematik war wirklich seltsam. Nachdem ich einige Gleichungen ausprobiert hatte, die in meinem Kopf Sinn machten, entschied ich mich yIndex = y-((x%2==0)?(x/2-x):(-x/2)-1)nach einigem Ausprobieren. Keine Ahnung, wie es hart funktioniert.
PeeC
Mach das yIndex = y-((x%2==0)?(-x/2):(-x/2)-1). x / 2 ist übrigens alles ganzzahlig, so dass kein Boden erforderlich ist.
PeeC
6

Persönlich würde ich Einfachheit dem Speichern von Speicher vorziehen. Nicht optimieren, bis es gebraucht wird!

Wenn Sie immer noch ein paar Bytes sparen möchten, gehen Sie wie folgt vor:

Geben Sie hier die Bildbeschreibung ein

  1. Schneiden Sie das Parallelogramm in zwei Hälften, um zwei rechtwinklige Dreiecke zu bilden
  2. Ordnen Sie die beiden Dreiecke neu an, um ein Rechteck zu bilden.
  3. (Beachten Sie, dass ich den grünen Pufferstreifen hinzugefügt habe, damit die Mathematik gut funktioniert.)

Python-Code zum Zuordnen von Rechteckkoordinaten zu Parallelogrammkoordinaten und zurück:

# Height of rectangle
H = 15

def r2p(x, y):
"rectangle to parallelogram"
if y < -x/2 + H:
    y = y + H
return (x - 1, y)

def p2r(x,y):
"parallelogram to rectangle"
if y >= H:
    y = y - H
return (x + 1, y)
Leftium
quelle
2
Sie können auch einfach die Pixel vertikal nach unten verschieben - auf dem Bild, das wäreoffsetY = Math.floor ( (x+1)/2 )
Markus von Broady
1

Es ist nicht erforderlich, Ihre Karte zu verzerren, da die Konvertierung zwischen rechteckigen und "kanonischen" Koordinaten schnell und einfach ist. Hier ist ein Link zu einem Intro, wie es geht:

Konvertieren zwischen rechteckigen und kanonischen Hex-Koordinaten

Diese Technik kombiniert die verzögerte Auswertung mit dem Caching berechneter Conversions.

Pieter Geerkens
quelle