Como as masmorras são geradas em Enter The Gungeon

Recentemente, joguei muito em Enter The Gungeon . Este é um jogo incrível e desafiador de balas, que me lembra muito Binding of Isaac . Mas quanto mais eu tocava, mais eu percebia o gênio sutil do design da masmorra.


Existem muitos geradores de procedimentos que criam esquemas de níveis lógicos que garantem o ritmo correto do jogo e recompensam os jogadores, e existem outros geradores que criam níveis com loops e esquemas compactos. Mas é raro encontrar os dois tipos em um jogo. O único jogo que conheço em que houve uma tentativa de implementar uma coisa dessas é o inexplorado .

Então, naturalmente, lancei o descompilador para que o Gungeon me revelasse todos os seus segredos. Neste artigo, compartilharei com você o que consegui encontrar.



À primeira vista, os níveis de Gungeon parecem bastante simples. Aqui está um exemplo típico de mapa.


Cartão Típico de Nível 1

O jogador começa na entrada. atravessa os baús e lojista para coletar itens e, finalmente, derrota o chefe . Se você tropeçar em um longo beco sem saída, poderá usar o teleporte para retornar rapidamente às salas. Obviamente, salas separadas foram criadas à mão e habitadas por vários inimigos que precisam ser atingidos. Ao avançar para os próximos níveis do jogo, o jogador vê o mesmo padrão repetidamente, apenas os estágios se tornam maiores.

Até agora, parece que isso não é nada interessante. Na Internet, você pode encontrar muitos geradores conectando corredores a salas aleatórias.

O recurso gerador se torna visível quando você começa a tocar. Os níveis parecem ... um pouco mais planejados do que se poderia esperar do acaso. A sala do chefe está sempre a uma distância razoável desde o início. Salas com inimigos sempre são razoavelmente intercaladas com salas calmas, bancos e cruzamentos. E o mais importante - muitos baús estão localizados atrás das dobradiças com cruz unidirecional.


A linha vermelha é um corredor de mão única. Se você quiser entrar em uma sala com um baú, precisará percorrer um longo caminho. A grande maioria dos baús está localizada no final de um loop unidirecional, ou profunda o suficiente dentro do nível, o que força o jogador a lutar por muitas salas, apenas para alcançar o baú. Não há recompensa sem risco.

O segredo desta passagem é que os esquemas gerais são criados manualmente. Aqui está o diagrama usado para gerar o nível mostrado acima.


As salas normais são salas selecionadas aleatoriamente com inimigos, salas de interseção ou salas grandes com várias saídas. As recompensas (recompensa) e o chefe (chefe) não precisam ser explicados. Não mostra salas "conectadas", isto é, salas sem inimigos, geralmente com riscos naturais. As salas restantes são predefinidas ou selecionadas em uma tabela de sala especial.

Em Gungeon, existem muitos desses esquemas chamados "fluxos" (fluxo). Nos níveis Hollow, eles são os menos (4), e no Gungeon Proper, os mais (8). Estes não são esquemas simples, seu design é criado com base em um determinado recurso que pode ser percebido com várias passagens. Pode ser um loop gigante, ou um garfo importante de várias maneiras, ou a necessidade de chegar ao banco para passar de nível. Eles são tão perceptíveis que os corredores de velocidade notaram diferenças e criaram horários pelos quais você pode encontrar o chefe o mais rápido possível. Eu preparei uma lista completa de esquemas que podem ser baixados aqui .

Você deve ter notado que o padrão de fluxo e o mapa não correspondem completamente. Sob o banco, há um espaço extra. inconsistente com o esquema, e salas estranhas no corredor . Vamos estudar todo o processo, ele contém muitas idéias inteligentes.

O processo inicia selecionando aleatoriamente um arquivo de fluxo como o mostrado acima. Essa é a estrutura de dados do “gráfico” , ou seja, armazena as interconexões das salas, mas não sua localização. Cada sala contém metadados sobre o tipo de sala e as conexões que ela deve ter. As conexões têm uma direção - cada diagrama de fluxo começa no nó raiz e forma uma árvore de nós filhos. Em seguida, conexões adicionais quebram a estrutura da árvore para criar loops. Eu acho que isso se deve principalmente às características do desenvolvimento do jogo, mas simplifica o procedimento de análise do mapa, porque todos os loops definiram claramente o começo e o fim.

Conversão de stream


Um arquivo de fluxo pode ser convertido de várias formas. Primeiro, algumas salas específicas serão substituídas por séries de salas de comprimentos aleatórios. Esta função é usada apenas em níveis posteriores e maiores. Além disso, algumas partes do arquivo de fluxo têm caminhos alternativos e um deles é selecionado aleatoriamente. Esta função é usada apenas duas vezes.

Em seguida, alguns nós adicionais são "injetados". Essa função é bastante flexível e é usada para diversos fins.

Cada “injeção” contém dados que determinam que tipo de objeto deve ser inserido, onde deve ser inserido, a probabilidade de criação e quaisquer condições que devem ser atendidas (por exemplo, a presença de uma rodada principal , uma grande maldição ou que o jogador ainda não salvou o personagem). ) Por exemplo, salas secretas geralmente são criadas em becos sem saída, mas têm uma probabilidade de 1/5 de serem anexadas a qualquer sala. Eles têm 90% de chance de ocorrência e não requerem condições adicionais.

Quase todas as salas especiais do jogo são determinadas pela injeção do local, incluindo comerciantes (não incluindo a loja principal), prisões, salas com lareiras e elevadores.


Uma das celas da prisão que pode ser injetada em um nível

No mesmo estágio, o gerador seleciona uma sala específica para cada nó. Isso depende principalmente do estágio atual e do tipo de quarto necessário. Há uma lista enorme de salas - quase 300 na primeira etapa -, mas o gerador tenta não selecionar a mesma sala duas vezes.

Os nós do conector funcionam de maneira diferente. Seus quartos são selecionados mais tarde, enquanto o esquema é criado. Geralmente, esses quartos são longos e estreitos, por isso é muito importante escolher um quarto com a orientação correta.

Objetos compostos


Após a criação do fluxo, ele é dividido em "objetos compostos". Cada objeto composto é um loop separado das salas ou um conjunto de salas conectadas sem loops (ou seja, uma árvore ). Isso é feito encontrando o menor loop no mapa e cortando-o como um objeto composto. A operação é repetida até que não haja loops no mapa. O restante do mapa se torna um conjunto de árvores divididas e conexões entre objetos compostos individuais.


O mesmo fluxo após injeção e divisão

Esquema de Objeto Composto


Cada objeto composto é criado separadamente, em um mapa separado. Eles serão reunidos mais tarde.

Para planejar um objeto composto, a primeira sala é colocada em um local arbitrário. Em seguida, as salas são adicionadas ao circuito, uma a uma, selecionando um par de saídas, uma delas relacionada à nova sala e a outra ao circuito existente. As saídas são locais predefinidos nos metadados de cada sala. Em seguida, a nova sala é colocada para que sua saída seja conectada diretamente à saída da sala anterior. Então o processo se repete.

Mais especificamente, os objetos da árvore composta são colocados atravessando a árvore em profundidade . O algoritmo seleciona apenas os pares de saídas que levam ao aparecimento de uma nova sala sem se cruzar com as anteriores. Em geral, o algoritmo prefere escolher saídas que estão longe das existentes. Se for impossível colocar uma sala, ela voltará e regenerará a escolha das salas, repetindo esse processo até três vezes.

Enquanto isso, objetos de loop composto são colocados adicionando elementos do loop, por sua vez, nos dois lados da linha. Para começar, os pares de saídas são selecionados aleatoriamente (é dada preferência a paredes opostas, leste-oeste ou norte-sul). Quando o loop é criado pela metade, ele começa a dar preferência aos pares de saídas que reúnem duas arestas abertas do loop. Após criar todas as salas, o algoritmo precisa adicionar outra conexão entre as duas últimas salas. Ele escolhe outro par de saídas. Se possível, ele projeta entre essas saídas uma pequena sala retangular. Caso contrário, ele procura um caminho entre as saídas e cria uma “sala”, que é simplesmente um corredor estreito. O comprimento do corredor deve ser de 4 a 30 unidades (em minas até 50).

Montagem final


Nesse estágio, pequenas partes separadas da masmorra são conectadas umas às outras, mas os próprios objetos compostos devem ser conectados para criar um mapa completo.


O mesmo mapa dos objetos compostos antes da montagem final

Como você pode ver, os compostos restantes neste caso não oferecem uma seleção muito grande. Mas pode haver casos mais complexos do que antes. O algoritmo ignora o mapa, começando da sala com mais conexões. Como antes, um par de saídas é selecionado para cada conexão criada. Se duas salas estiverem em partes separadas do mapa, essas duas partes do mapa serão alinhadas para criar um caminho curto. Caso contrário, uma pesquisa de rota é usada para criar a rota.

E é aí que a criação do diagrama de níveis termina. Resta apenas escolher inimigos e decorações para os quartos, e esse é um tópico completamente diferente.

Em conclusão


Parece que o principal objetivo dos desenvolvedores era criar um gerador de procedimentos que proporcionasse uma jogabilidade satisfatória. Obviamente, para ser implementado corretamente, eles tiveram que realizar muitas iterações - encontrei uma grande quantidade de código de geração, que, ao que parece, não é usado, porque os desenvolvedores mudaram sua fórmula processual em busca da perfeição.

Um truque curioso é que eles geram as partes mais complexas / importantes do mapa primeiro. O gerador se concentra na criação de loops estreitos e corredores curtos nas partes centrais do nível e, em seguida, tenta conectar tudo o mais com eles.

Como no caso do meu estudo sobre a geração dos níveis de Diablo 1 , fiquei impressionado com a eficiência de gerar parte da masmorra de forma abstrata - nesse caso, é um gráfico sem informações sobre a localização. Tudo se torna mais específico somente mais tarde. A função "injeção" seria simplesmente impossível se imediatamente trabalhassemos com um mapa de blocos. Graças à abstração dos detalhes da localização das salas, permite controlar o estilo do jogo e a escala de níveis.

Além disso, fiquei impressionado com a extensibilidade de todo o sistema. A unidade incentiva uma abordagem ativa orientada por dados . Adicionar uma nova sala, esquema ou até mesmo um comportamento especial pode ser realizado simplesmente adicionando novos objetos às tabelas correspondentes. Isso deve ter sido uma grande ajuda, porque o Dodge Roll já lançou alguns DLCs gratuitos e, sem dúvida, suporta a criação de mods .



Bónus


Estudar esse gerador foi minha primeira chance de pesquisar criando um jogo profissional no Unity. Os desenvolvedores do Dodge Roll deram o melhor de si e escreveram um bom código. É bem lido e, em alguns lugares, bastante engraçado - parece que o amor deles aos trocadilhos se espalhou pelo código. Eu gostei desses:

  • O mecanismo fluido do jogo é chamado DeadlyDeadlyGoopManager
  • O código de geração de masmorra é chamado de Dungeonator
  • As várias etapas são chamadas de CASTLEGEON/GUNGEON/MINEGEON/CATACOMBGEON etc. Gostaria de saber se os desenvolvedores foram inspirados no Diablo 1, que usa um esquema muito semelhante?
  • Literalmente, cada quarto tem seu próprio nome, geralmente na forma de um trocadilho (ou em homenagem a algum Joe; provavelmente este é um artista com grande vaidade).

Percebi também que, inicialmente, o estúdio planejava palcos nos temas do espaço, da selva e do oeste selvagem. Infelizmente, eles não estavam destinados a aparecer. Dodge Roll decidiu que seu trabalho em Gungeon estava concluído . Vou esperar o próximo jogo e espero que eles coloquem tanto amor e atenção nele.

Source: https://habr.com/ru/post/pt462377/


All Articles