Generando proceduralmente un edificio de área específica

Yo y un equipo estamos trabajando en un juego de construcción de fábrica que le da al jugador una fábrica random al comienzo del juego. Para tratar de asegurarse de que haya una sensación de "equidad", idealmente la fábrica generada aleatoriamente tendría un área dentro de unas pocas unidades de (valor de marcador de position) 30.

Es relativamente simple escribir un generador de rectángulo aleatorio básico para cumplir con estas especificaciones, pero nuestro objective es que la fábrica sea más compleja, quizás formada por 2, 3 o incluso 4 rectangularjs que se cruzan, produciendo forms más complejas (piense en L, U, y edificios en forma de O).

Intenté generar un rectángulo aleatorio y luego usar álgebra básica para completar un segundo rectángulo, pero hasta ahora no he tenido suerte implementando más de 2 rectangularjs, y aun así no estoy contento con los resultados de solo un layout de 2 rectangularjs .

Alguna información más relevante: 2D arriba abajo Algunas de las mecánicas son de estilo factorial, por lo que las salas deben tener un largo y ancho razonables para dejar espacio para la maquinaria. Actualmente en Java y Lua (pueden usar bibliotecas integradas si es necesario)

¡Gracias por adelantado!

EDITAR: Cuando digo salidas "buenas" o "malas", una salida mala sería cualquier salida que tenga espacio inutilizable por el jugador. La forma de fábrica limita el lugar donde el jugador puede colocar máquinas de fábrica, como cintas protractoras. Idealmente, la fábrica no debería tener áreas que tienen solo 1-2 bloques de ancho, la forma no debería ser uno o dos rectangularjs grandes con una línea de 1-2 bloques "colgando" hacia un lado. Una buena salida sería cuando todo el espacio del piso es "viable", por lo que todas las áreas tienen al less 3-4 bloques de ancho. Un buen resultado no siempre tiene que ser complejo (1 o 2 rectangularjs está bien), pero debería tener una buena probabilidad si se compone de más de 1 o 2 rectangularjs.

Puede usar polyominoes pregenerados como meta forms para build una variedad de edificios.

Digamos que su distancia mínima aceptable es de 3 cuadras. Entonces la unidad de construcción más pequeña aceptable que consideraremos es 3×3. Por conveniencia, voy a llamar a eso una celda y le da un área de 9 bloques. Luego, toma tu área de inicio objective y divídela por el área de la celda. Usando el valor inicial que dio, obtenemos 3.333; entonces 3 celdas te darán un poco less de lo que quieres y 4 celdas te darán más.

Desde aquí tienes un par de opciones. Si es flexible en su área de inicio, use el método que mejor funcione para que pueda elegir el número de celdas que le dé una cantidad aceptable (es decir, networkingondee al valor más cercano, networkingondee hacia arriba, etc.). Voy a llamar a esto el conteo de células.

A continuación, select aleatoriamente el polyomino con el recuento de células deseado. Reemplaza cada cuadrado en el polyomino con una celda de construcción y tienes tu forma final.

Para ilustrar, digamos que elegimos networkingondear hacia abajo. Aquí están todos los polyominoes de tamaño 3 (sin include rotaciones / volteretas):

enter image description here

Supongamos que seleccionamos aleatoriamente la forma L y aplicamos una rotation aleatoria, su edificio tendría la siguiente distribución:

enter image description here

Un par de problemas. Primero, hay un límite en la cantidad de celdas que puede usar. Wikipedia le dará todos los polyominoes hasta el tamaño 8 ( octomino ). Incluye datos de resumen de hasta el tamaño 12, pero no sé si hay una list en línea para todos ellos. En segundo lugar, la solución anterior solo funciona exactamente para tamaños de edificios que son múltiplos de 9. Hay algunas maneras de solucionar algunos de estos problemas:

1) Use un tamaño de celda diferente. Por ejemplo 3×4, 4×4, etc.

2) Agregue celdas adicionales a un polyomino inicial. Esto puede ser complicado si debes asegurarte de que todas las forms son igualmente probables, pero es probable que para la mayoría de los desarrolladores de juegos no necesites una distribución verdaderamente uniforme de las forms de construcción.

3) Rellene un edificio para hacerlo más grande. Volviendo al ejemplo, si usó 3 celdas, su edificio tendría un área de 27 cuadrados que lo dejaría corto por 3. Entonces podría escanear el perímetro de una location para pegar un grupo de cuadrados de tamaño 1×3. Siempre que su grupo de maquillaje sea al less AxB, donde A es al less su distancia mínima aceptable, su resultado no violará su restricción de distancia mínima aceptable. Construyendo el ejemplo anterior, aquí hay una ilustración de un posible resultado:

enter image description here

4) En lugar de rellenar un edificio que es demasiado pequeño, puede recortar un edificio que es demasiado grande. Asegurarse de que se cumpla con la restricción de distancia mínima aceptable es más complejo que la opción de relleno, pero le daría más alternativas para considerar.

Algunos otros comentarios:

El hecho de que pueda usar todos los poliminoides posibles de un tamaño determinado no significa que deba hacerlo. Si algunos de ellos no son divertidos, rompa su tema, son ofensivos para su audiencia (patrones de esvástica), o puede causar algún otro problema, sáquelos. Además, puede ponderar su rutina de selección si algunos patrones son interesantes, pero demasiado extraños para aparecer de forma rutinaria. Finalmente, puede usar esta solución en combinación con su estrategia actual. Tal vez el 70% de las veces generas edificios rectangulares y el 30% del time utilizas el enfoque polyomino. O tal vez comienzas con un edificio rectangular y pegas un pequeño polyomino al exterior.

Una forma simple de build un generador de procedimientos es:

  1. Construir cosas random
  2. Ejecute una function que verifique si el resultado es bueno
  3. Si la salida no es buena, ve al paso 1

Incluso si se necesitan miles de ejecuciones para completar, la mayoría de los generadores simples funcionan bien con este enfoque. La ventaja es que no se requiere mucha inteligencia en el generador, y desde que verificar si algo es bueno es mucho más fácil que build algo que esté bien el 100% del time, este enfoque es muy fácil.

Ha enumerado algunas medidas objetivas sobre si una salida es buena; eso debería ser suficiente para crear un generador rápido y sucio. Coloque rectangularjs random dentro de un área y rechace la salida si, por ejemplo, hay áreas que tienen solo 1-2 bloques de ancho.

Comience con eso, mejore y optimice luego.

Dada la restricción de que "todas las áreas están en al less 3-4 cuadras de ancho", la primera idea que me viene a la mente es algo como lo siguiente:

  1. elige uno de 3×3, 3×4, 4×3 o 4×4
  2. coloque un bloque de ese tamaño en el centro de la cuadrícula
  3. elige una dirección (arriba, izquierda, derecha, abajo)
  4. intenta colocar un bloque de 3×3 junto a los bloques previamente ubicados en esa dirección
  5. si tiene éxito, con cierta probabilidad, intenta expandir el bloque a un bloque de 4×3 en una de las direcciones que no escogiste
  6. con alguna probabilidad, mueva un borde random de los bloques rellenos
  7. repita los pasos 3 a 6 hasta que el área sea lo suficientemente grande

La idea básica es que, dado que desea que todas las áreas tengan al less un tamaño determinado, solo trabaje en áreas de ese tamaño. De manera más general, si desea que algo sea cierto para todas las salidas generadas, vea si puede hacerse realidad para todas las salidas parcialmente generadas.

Considere usar booleans NOT y UNION y elegir entre ellos aleatoriamente.

  1. Coloque un rectángulo random.
  2. Coloque un segundo rectángulo random.
  3. Elija random si UNIONARlos o RESTANTE el segundo de la primera.
  4. Repita para una cantidad de rectangularjs. Aunque, solo dos o tres podrían dar resultados lo suficientemente razonables.

Luego, calculo el área y la escala hacia arriba o hacia abajo para que coincida más estrechamente con el tamaño aproximado que busca, y luego pruebo que no hay dimensiones menores a la cantidad mínima requerida.