Almacenar una cuadrícula hexadecimal

10

He estado creando un pequeño marco de cuadrícula hexadecimal para Unity3D y he llegado al siguiente dilema. Este es mi sistema de coordenadas (tomado de aquí ):

ingrese la descripción de la imagen aquí

Todo funciona bastante bien, excepto por el hecho de que no tengo idea de cómo almacenarlo. Originalmente tenía la intención de almacenar esto en una matriz 2D y usar imágenes para generar mis mapas.

Un problema era que tenía valores negativos (esto se solucionaba fácilmente compensando un poco las coordenadas).

Sin embargo, debido a este sistema de coordenadas, dicha imagen o mapa de bits tendría que tener forma de diamante, y dado que estas estructuras tienen forma cuadrada, esto causaría muchos dolores de cabeza incluso si pirateo algo juntos. ¿Me falta algo que pueda solucionar esto? Recuerdo haber visto una publicación en el foro sobre esto en los foros de la unidad, pero ya no puedo encontrar el enlace.

¿Escribir un conjunto de traductores de coordenadas es la mejor solución aquí?

Si piensan que sería útil, puedo publicar código e imágenes de mi problema.

PeeC
fuente
1
¿No puedes guardar imágenes PNG transparentes alrededor de los hexágonos?
Markus von Broady
Mi principal problema al guardar en pngs y arrays es la cantidad de "espacio en blanco" que tendrían que contener para mantener este sistema de coordenadas intacto.
PeeC
1
Si "espacio en blanco" significa píxeles transparentes, ¿por qué la cantidad es un problema?
Markus von Broady
Ese es un muy buen punto. La mayoría de los formatos de imagen no desperdician tanta memoria almacenando patrones repetidos. Pero aún así, poco me molesta que para almacenar este mapa que estoy usando esta cantidad de memoria (píxeles grises son el espacio vacío, otros colores son válidos coordenadas hexagonales).
PeeC
1
¡Oh, está almacenando los datos de la cuadrícula, no las imágenes en mosaico! ¿Por qué no guardará sus estructuras de datos (cuadrícula) en un archivo binario, o lo codificará utilizando, por ejemplo, JSON y guardará en un archivo de texto? Sin embargo, no conozco las capacidades de Unity. Además, es posible que desee confirmar esto, pero creo que un área del mismo color está optimizada (poco comprimida) en formato PNG.
Markus von Broady

Respuestas:

9

Es más fácil trabajar con las coordenadas de paralelogramo que está utilizando, pero tienen el inconveniente de ser extrañas para los mapas rectangulares. Un enfoque es almacenarlo con las coordenadas de desplazamiento, pero en realidad usar coordenadas de paralelogramo en la lógica del juego.

Observación: en cada fila del mapa, los datos de la cuadrícula son contiguos. Todo el espacio desperdiciado está a la izquierda y a la derecha.

Solución: dentro de esa fila, almacene los datos comenzando en la columna más a la izquierda en lugar de la columna marcada con 0. Calcule la primera columna del mapa rectangular en su sistema de coordenadas , luego reste eso de la coordenada de la columna para determinar a qué parte de la matriz va. Esto también funciona para las coordenadas de columna negativas.

Realice la conversión en getter y setter para el mapa, con algo como esto:

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

Tendrá que modificar esto para trabajar con su elección de coordenadas y mapa (preste atención a las diferencias de uno a uno). En algunos diseños, querrá compensar las columnas por la fila en lugar de viceversa.

Puedes usar el mismo truco para hacer mapas de otras formas; No se limita a los rectángulos.

Si usa C o C ++, puede usar la aritmética de puntero para hacer esto más rápido. En lugar de almacenar una matriz de punteros en matrices, almacene una matriz de punteros que hayan sido ajustados por first_column_in_row. (Esto puede no ser portátil)

amitp
fuente
Esto funciona hasta donde puedo decir, sin embargo, las matemáticas eran realmente extrañas. Después de probar varias ecuaciones que tenían sentido en mi cabeza, me decidí yIndex = y-((x%2==0)?(x/2-x):(-x/2)-1)después de algunas pruebas y errores. No tengo idea de cómo funciona duro.
PeeC
Haz eso yIndex = y-((x%2==0)?(-x/2):(-x/2)-1). x / 2 es todo por cierto basado en números enteros, por lo que no hay necesidad de piso.
PeeC
6

Personalmente, preferiría la simplicidad sobre el ahorro de memoria. ¡No optimices hasta que sea necesario!

Si todavía está decidido a guardar algunos bytes, así es como puede hacerlo:

ingrese la descripción de la imagen aquí

  1. Corta el paralelogramo por la mitad para formar dos triángulos rectángulos
  2. Reorganiza los dos triángulos para formar un rectángulo.
  3. (Tenga en cuenta que agregué la franja de protección verde para que las matemáticas funcionen bien).

Código de Python para asignar coordenadas de rectángulo a coordenadas de paralelogramo y viceversa:

# 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
fuente
2
también podría mover los píxeles verticalmente hacia abajo, en la imagen que seríaoffsetY = Math.floor ( (x+1)/2 )
Markus von Broady
1

No es necesario distorsionar su mapa, ya que la conversión entre coordenadas rectangulares y "canónicas" es rápida y fácil. Aquí hay un enlace a una introducción sobre cómo hacerlo:

Conversión entre coordenadas hexadecimales rectangulares y canónicas

Esta técnica combina la evaluación diferida con el almacenamiento en caché de las conversiones calculadas.

Pieter Geerkens
fuente