Gerando mapa de blocos

25

Estou programando um jogo baseado em blocos e tenho alguns blocos básicos (grama, sujeira, etc.), mas não consigo descobrir como gerar uma boa geração aleatória de mapas, porque quando faço uma seleção realmente aleatória, se o bloco deve ser grama / sujeira, eu entendi o seguinte:

Imagem no jogo

Entendo por que isso está acontecendo, mas o que quero é criar algumas áreas contínuas aleatórias de grama ou sujeira. Algo que faria mais sentido, assim:

Resultado desejado

Vilda
fonte
11
Além das respostas propostas, você pode escrever seu próprio mecanismo de autômato celular para gerar esses mapas. Modificando as regras do autômato, você pode gerar comportamentos muito diferentes, levando a tipos muito diferentes de mapas. Por exemplo, usando um autômato 2D semelhante ao Life, as regras de inundação podem levar a "oceano e ilhas" (como na foto acima), e uma regra como 1267/17 pode levar a belos laboratórios.
Manu343726

Respostas:

19

O que você pode fazer é gerar aleatoriamente um mapa de Voronoi como este:

  1. Escolha aleatoriamente center points(veja os pontos pretos) e decida aleatoriamente se são grama ou sujeira.
  2. Em seguida, para ver todos os ladrilhos, verifique se está mais próximo center pointde terra ou grama.
  3. Feito!

Se o que você fez anteriormente foi "jogar uma moeda" para cada ladrilho (ruído), a geração de um diagrama de Voronoi proporcionará um resultado muito melhor.

Você pode melhorar isso dividindo o center pointsem islandscom um algoritmo que:

  1. Seleciona um pequeno grupo de centers pointse os designa como leaders.
  2. Adiciona iterativamente um ponto central indeciso adjacente aleatório a cada turno.
  3. Feito!

insira a descrição da imagem aqui

wolfdawn
fonte
11
Obrigado, mas parece uma solução muito difícil.
Vilda
2
Esta não é uma solução muito difícil. Primeiro escolha aleatoriamente o center points. Depois decida se são grama ou sujeira. Agora passe pela matriz e decida se cada peça está mais próxima de um ponto de terra ou grama. Talvez me diga qual parte desafiadora?
wolfdawn
Medindo a distância. De qualquer forma, tentarei informar você.
Vilda
Ok, então eu consegui gerar alguns pontos com sucesso. ( dropbox.com/s/dlx9uxz8kkid3kc/random_tile_map2.png ) e, portanto, toda a minha classe de geração se parece com isso: dropbox.com/s/pxhn902xqrhtli4/gen.java . Mas ainda não funciona.
Vilda
3
@ViliX seus links estão quebrados
Artur Czajka
24

Você pode usar o ruído perlin, que normalmente é usado para a geração de mapas de altura. Ruído Perlin nos jogos

Depois, você pode usar as alturas como consultor, qual a probabilidade de ocorrência de grama / sujeira em uma região do mapa.

Exemplo (valores de ruído Perlin de 0 a 255): Se o valor for superior a 200, a chance de colocar grama é de 80% (sujeira de 20%). Se o valor estiver entre 100 e 200, a chance de colocar grama é de 50% (sujeira também 50%). Se o valor estiver abaixo de 100, a chance de a grama ser colocada é de 20% (sujeira 80%).

Klitz
fonte
Ok, digamos que eu tenho um array [] [] de float (0-1 de probabilidade) e posso usá-lo para gerar blocos com a probabilidade. Mas como preencher essa matriz de probabilidade? A matriz é (digamos) 400x200, como preenchê-la com valores de probabilidade?
Vilda
Ele está sugerindo preenchê-lo com ruído permanente (em vez de ruído branco como moedas).
wolfdawn
Sim, mas como posso conseguir isso?
Vilda
O link que eu postei poderia esclarecer esta questão. Primeiro, gere um ruído e depois suavize esse ruído. O resultado será uma matriz bidimensional que você poderá usar para gerar mais o mapa de blocos. ligação
Klitz 21/06
É uma resposta muito boa, mas raramente obtém resultados semelhantes aos que você apresentou.
wolfdawn
8

insira a descrição da imagem aqui

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

Aqui está a minha versão do método de autômatos celulares: comece preenchendo a grade aleatoriamente e execute essas regras de autômatos cullulares algumas vezes

  • Se uma célula viva tem menos de dois vizinhos vivos, ela morre.
  • Se uma célula viva tem dois ou três vizinhos vivos, ela permanece viva.
  • Se uma célula viva tem mais de três vizinhos vivos, ela morre.
  • Se uma célula morta tem exatamente três vizinhos vivos, ela se torna viva.

e acaba parecendo uma caverna

o índice pode ser convertido para a posição x & y e voltar com 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);
}

Acabei de retornar uma lista de bools porque eu uso essa lista para muitas coisas: cavernas, árvores, flores, grama, neblina, água, você pode até combinar várias listas de maneiras diferentes aqui, primeiro removo todas as cavernas menores e depois uno duas listas aleatórias

insira a descrição da imagem aqui

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
fonte
2
Explique o que seu código faz, em vez de postar uma amostra do que ele faz, um link e o próprio código. Sua resposta deve ser independente, para que, mesmo que os links quebrem, ainda seja utilizável.
Fund Monica's Lawsuit
6

Selecione um ponto no mapa. Coloque o tipo de ladrilho desejado com um valor base como 40. Mantenha o controle de onde você colocou o ladrilho recém-desejado. Adicione o ponto de partida a uma lista.

Para cada ponto desta lista, você visita todos os vizinhos. Enquanto você tem energia suficiente (iniciada aos 40), adicione um bloco desejado e adicione-o à lista a ser visitada. Dê menos energia ao novo ladrilho, determinado por você. Mais fácil = abaixamento aleatório. Depois de visitar o bloco da lista, remova-o. Comece novamente visitando todos os blocos não visitados, mas criados.

Jaapjan
fonte