Generando mapa de mosaico

25

Estoy programando un juego basado en fichas y tengo algunas fichas básicas (hierba, tierra, etc.), pero no puedo entender cómo hacer una buena generación de mapas aleatorios, porque cuando hago una selección realmente aleatoria, si la ficha debería ser hierba / tierra, entiendo esto:

Imagen en el juego

Entiendo por qué sucede esto, pero lo que quiero es crear algunas áreas continuas aleatorias de césped o tierra. Algo que tendría más sentido, como este:

Resultado deseado

Vilda
fuente
1
Además de las respuestas propuestas, puede escribir su propio motor de autómata celular para generar dichos mapas. Modificando las reglas del autómata podría generar comportamientos muy diferentes, lo que llevaría a tipos muy diferentes de mapas. Por ejemplo, si se crea un autómata 2D similar a Life, las reglas de inundación podrían conducir a "océano e islas" (como en la imagen de arriba), y una regla como 1267/17 podría conducir a hermosos laberintos.
Manu343726

Respuestas:

19

Lo que podrías hacer es generar aleatoriamente un mapa de Voronoi como este:

  1. Escoger al azar center points(ver los puntos negros) y decidir al azar si son hierba o tierra.
  2. Luego, para todas las baldosas, verifique si está más cerca center pointde tierra o césped.
  3. ¡Hecho!

Si lo que hizo anteriormente es "lanzar una moneda" por cada ficha (ruido), generar un diagrama de Voronoi proporcionará un resultado mucho mejor.

Podría mejorar esto dividiendo el center pointsen islandsun algoritmo que:

  1. Elige un pequeño grupo de centers pointsy los designa como leaders.
  2. Agrega iterativamente un punto central adyacente indeciso aleatorio cada turno.
  3. ¡Hecho!

ingrese la descripción de la imagen aquí

Wolfdawn
fuente
1
Gracias, pero parece una solución muy difícil.
Vilda
2
Esta no es una solución muy difícil. Primero escoge al azar center points. Luego decida si son hierba o tierra. Ahora pase sobre la matriz y decida si cada mosaico está más cerca de un punto de tierra o de hierba. Tal vez dime qué parte desafiante?
wolfdawn
Medición de la distancia. De todos modos, intentaré hacértelo saber.
Vilda
Ok, he generado con éxito algunos puntos. ( dropbox.com/s/dlx9uxz8kkid3kc/random_tile_map2.png ) y así toda mi clase para generar se ve así: dropbox.com/s/pxhn902xqrhtli4/gen.java . Pero todavía no funciona.
Vilda
3
@ViliX tus enlaces están rotos
Artur Czajka
24

Podría usar el ruido perlin, que normalmente se usa para la generación de mapas de altura. Ruido de Perlin en los juegos

Entonces podría usar las alturas como asesor, qué tan alta es la probabilidad de que ocurra hierba / tierra en una región del mapa.

Ejemplo (valores de ruido de Perlin de 0-256): si el valor es superior a 200, la probabilidad de que se coloque hierba es del 80% (suciedad del 20%). Si el valor está entre 100 y 200, la probabilidad de que se coloque el césped es del 50% (la suciedad también es del 50%). Si el valor es inferior a 100, la probabilidad de que se coloque hierba es del 20% (suciedad del 80%).

Klitz
fuente
Ok, digamos que tengo una matriz [] [] de flotante (0-1 de probabilidad) y puedo usarla para generar fichas con la probabilidad. Pero, ¿cómo lleno esta matriz de probabilidad? La matriz es (digamos) 400x200, ¿cómo llenarla con valores de probabilidad?
Vilda
Sugiere llenarlo con ruido perlin (en lugar de ruido blanco como monedas).
wolfdawn
Sí, pero ¿cómo puedo lograr eso?
Vilda
El enlace que publiqué podría aclarar esta pregunta. Primero genere un ruido y luego suavice este ruido. El resultado será una matriz bidimensional que puede usar para una mayor generación del mosaico. enlace
Klitz
Es una respuesta realmente buena, pero rara vez obtendrá resultados similares a los que presentó.
wolfdawn
8

ingrese la descripción de la imagen aquí

http://gamedevelopment.tutsplus.com/tutorials/generate-random-cave-levels-using-cellular-automata--gamedev-9664

Aquí está mi versión del método de autómata celular. Comience rellenando la cuadrícula de forma aleatoria y luego ejecute estas reglas de autómatas cullulares un par de veces

  • Si una célula viva tiene menos de dos vecinos vivos, muere.
  • Si una célula viva tiene dos o tres vecinos vivos, permanece viva.
  • Si una célula viva tiene más de tres vecinos vivos, muere.
  • Si una celda muerta tiene exactamente tres vecinos vivos, se vuelve viva.

y termina pareciendo una cueva

el índice se puede convertir a la posición x & y y volver con este código

public int TileIndex(int x, int y)
{
    return y * Generator.Instance.Width + x;
}
public Vector2 TilePosition(int index)
{
    float y = index / Generator.Instance.Width;
    float x = index - Generator.Instance.Width * y;
    return new Vector2(x, y);
}

Acabo de devolver una lista de bools porque utilizo esta lista para muchas cosas: cuevas, árboles, flores, césped, niebla, agua, incluso puede combinar varias listas de diferentes maneras aquí, primero elimino todas las cuevas más pequeñas y luego unimos dos listas aleatorias

ingrese la descripción de la imagen aquí

private int GetAdjacentCount(List<bool> list, Vector2 p)
{
    int count = 0;
    for (int y = -1; y <= 1; y++)
    {
        for (int x = -1; x <= 1; x++)
        {
            if (!((x == 0) && (y == 0)))
            {
                Vector2 point = new Vector2(p.x + x, p.y + y);
                if (PathFinder.Instance.InsideMap(point))
                {
                    int index = PathFinder.Instance.TileIndex(point);
                    if (list[index])
                    {
                        count++;
                    }
                }
                else
                {
                    count++;
                }
            }
        }
    }
    return count;
}
private List<bool> GetCellularList(int steps, float chance, int birth, int death)
{
    int count = _width * _height;
    List<bool> list = Enumerable.Repeat(false, count).ToList();
    for (int y = 0; y < _height; y++)
    {
        for (int x = 0; x < _width; x++)
        {
            Vector2 p = new Vector2(x, y);
            int index = PathFinder.Instance.TileIndex(p);
            list[index] = Utility.RandomPercent(chance);
        }
    }
    for (int i = 0; i < steps; i++)
    {
        var temp = Enumerable.Repeat(false, count).ToList();
        for (int y = 0; y < _height; y++)
        {
            for (int x = 0; x < _width; x++)
            {
                Vector2 p = new Vector2(x, y);
                int index = PathFinder.Instance.TileIndex(p);
                if (index == -1) Debug.Log(index);
                int adjacent = GetAdjacentCount(list, p);
                bool set = list[index];
                if (set)
                {
                    if (adjacent < death)
                        set = false;
                }
                else
                {
                    if (adjacent > birth)
                        set = true;
                }
                temp[index] = set;
            }
        }
        list = temp;
    }
    if ((steps > 0) && Utility.RandomBool())
        RemoveSmall(list);
    return list;
}
Rakka Rage
fuente
2
Explique qué hace su código, en lugar de publicar una muestra de lo que hace, un enlace y el código en sí. Su respuesta debe ser autónoma, de modo que incluso si los enlaces se rompen, todavía se pueda usar.
Financia la demanda de Mónica el
6

Selecciona un punto en el mapa. Coloque el tipo de mosaico deseado con un valor base como 40. Mantenga un registro de dónde colocó su mosaico recién deseado. Agregue el punto de partida a una lista.

Para cada punto de esta lista, visita a todos los vecinos. Mientras tenga suficiente energía (comenzada en 40), agregue un mosaico deseado y agréguelo a la lista para ser visitado. Dale a la nueva ficha menos potencia, determinada por ti. Más fácil = reducción aleatoria. Después de visitar el mosaico de la lista, elimínelo. Comience de nuevo visitando cualquier mosaico no visitado pero creado.

Jaapjan
fuente