O que você está procurando?
Games

Imprevisivelmente divertido: O valor da aleatoriedade no design de jogos

EDUARDO ORIZ / UNITY TECHNOLOGIESSenior Content Marketing Manager
Apr 11, 2022|10 Min
Imprevisivelmente divertido: O valor da aleatoriedade no design de jogos
Esta página da Web foi automaticamente traduzida para sua conveniência. Não podemos garantir a precisão ou a confiabilidade do conteúdo traduzido. Se tiver dúvidas sobre a precisão do conteúdo traduzido, consulte a versão oficial em inglês da página da Web.

Aprenda como injetar aleatoriedade no seu jogo para manter os jogadores envolvidos e ansiosos pela próxima cena. Este é o segundo post de Christo Nobbs em sua série sobre design de sistemas, expandindo suas contribuições para o manual do designer de jogos Unity. Confira o e-book para saber mais sobre como prototipar, criar e testar a jogabilidade no Unity.

Em sua postagemanterior, Christo abordou como os designers podem criar sistemas em seus jogos que resultem em uma jogabilidade intrigante e inesperada. Nesta postagem, ele se aprofunda com exemplos sobre como configurar a randomização.

Imagem com fundo roxo claro com a capa do Ebook GamePlay & Design
A randomização, juntamente com outros tópicos relacionados, são abordados no e-book gratuito, The Unity game designer playbook.
Deixe um rastro de pistas visuais para seus jogadores

Você pode incentivar os jogadores a explorar ainda mais os sistemas do seu mundo de jogo e criar experiências únicas para eles com instruções visuais. O post anterior, Sistemas que criam ecossistemas: Design de jogos emergente, descreveu um espaço de areia onde tudo é feito e construído de madeira, com possibilidade de propagação imprevisível de fogo. Vamos desenvolver esse exemplo dando aos jogadores a capacidade de cortar árvores com um machado.

Suponha que a paisagem onde os jogadores estão seja plana. Eles não sabem em que direção a árvore cairá quando a cortarem. E se algumas árvores fossem “troncos” – ou seja, mortas, mas ainda de pé? Eles podem cair a qualquer momento. Um elemento imprevisível como esse no jogo assustará os jogadores e intensificará seu ambiente de jogo.

Você pode adicionar qualquer número de dicas visuais para mostrar aos jogadores que árvores caindo são perigosas neste mundo e mantê-los alertas. As pistas ajudarão os jogadores a identificar as diferenças entre as árvores mais perigosas e aquelas que são saudáveis e menos ameaçadoras. Eles terão que escolher como ponderar os riscos: Seria mais sensato procurar lenha em árvores que já caíram e evitar ser ferido pelas árvores mortas que estão esperando para cair?

Como designer, certifique-se de mapear onde essas reações sistêmicas em cadeia ocorrem e projetar dentro delas, dando suporte quando os jogadores as desencadeiam, como árvores caindo de forma imprevisível, pegando fogo e, assim, espalhando um caos delicioso.

Gere surpresa com Unity.Engine.Random

A classe de script Random no Unity é uma classe estática que fornece abordagens para gerar dados aleatórios em um jogo. Esta classe tem o mesmo nome da classe System.Random do .NET Framework e tem uma finalidade semelhante, mas difere em alguns aspectos importantes – um deles é que ela é de 20% a 40% mais rápida que System.Random.

Abaixo estão as propriedades e métodos estáticos disponíveis com a classe Random:

Propriedades estáticas

  • insideUnitCircle: Retorna um ponto aleatório dentro ou em um círculo com raio 1,0 (somente leitura)
  • insideUnitSphere: Retorna um ponto aleatório dentro ou em uma esfera com raio 1,0 (somente leitura)
  • onUnitSphere: Retorna um ponto aleatório na superfície de uma esfera com raio 1,0 (somente leitura)
  • Rotação: Retorna uma rotação aleatória (somente leitura)
  • rotationUniform: Retorna uma rotação aleatória com distribuição uniforme (somente leitura)
  • state: Obtém ou define o estado interno completo do gerador de números aleatórios
  • valor: Retorna um float aleatório dentro de [0.0..1.0] (o intervalo é inclusivo) (somente leitura)

Métodos estáticos

  • ColorHSV: Gera uma cor aleatória a partir dos intervalos HSV e alfa
  • InitState: Inicializa o estado do gerador de números aleatórios com uma semente
  • Faixa: Retorna um float aleatório dentro de [minInclusive..maxInclusive] (o intervalo é inclusivo)

A postagem anterior do blog explorou o papel das alavancas de design e o uso de ScriptableObjects para armazenar esses valores. Você pode substituir esses valores por intervalos projetados apropriadamente usando Random.Rangedo Unity, que retorna um float aleatório dentro de [minInclusive..maxInclusive] (o intervalo é inclusivo). Qualquer valor flutuante entre eles, incluindo minInclusive e maxInclusive, aparecerá aproximadamente uma vez a cada 10 milhões de amostras aleatórias.

Com essa abordagem, você pode extrair um valor do intervalo definido para seu resultado. Você terá que testar vários intervalos para encontrar aquele que funciona melhor para seus objetivos de jogo, mas, novamente, certifique-se de projetar para o intervalo definido por você.

Imagem de um robô branco observando incêndios em galhos de árvores em uma floresta
Saiba mais sobre sistemas modulares no primeiro post do blog da nossa série sobre designers de jogos.
Uma aventura aleatória na floresta

A aleatoriedade proporciona uma melhor imersão. Por exemplo, digamos que cada árvore tenha uma contagem de saúde fixa de 100, e cada golpe de machado tira 25 pontos da saúde de uma árvore. Essa tarefa logo se tornará previsível e, portanto, chata. Mesmo que você dê às árvores uma faixa de saúde de 76 a 100, qualquer árvore estará a quatro golpes de cair. Mas tentar um intervalo menor, digamos, de 75 a 76, oferece uma variedade maior de resultados de jogo, já que uma árvore levará de três a quatro golpes para cair.

Outra maneira de tornar esse cenário interessante é indicar mudanças de saúde por meio de sinais visuais claros em vez de barras de saúde. Isso permitirá que o jogador aprenda, por meio do jogo, aproximadamente quantos golpes de machado serão necessários para que uma árvore caia. Dicas visuais acrescentam alguma imprevisibilidade limitada que pode ser equilibrada e ajustada para a jogabilidade alvo. Usar a classe Random em vez de um valor fixo permite que você transforme uma tarefa monótona em uma divertida.

Para expandir este exemplo, você pode escolher remover um valor aleatório entre 15 e 25 pontos de saúde para cada golpe de machado. Isso faz com que os jogadores não consigam prever facilmente quantos golpes serão necessários para cortar uma árvore. Eles precisarão confiar mais em pistas visuais para avaliar quando uma árvore vai cair; pistas como o tamanho dos pedaços voando da árvore ou rachaduras se formando no tronco, galhos caindo, efeitos sonoros e assim por diante.

Eles não saberão exatamente quando cada árvore cairá, mas com o tempo, à medida que os jogadores cortam mais árvores, eles podem fazer suposições fundamentadas, aumentando suas chances de sobrevivência.

Captura de tela das configurações de dano de acerto aleatório no Inspetor
No manual do designer de jogos do Unity , você encontrará exemplos de como criar alavancas e visualizar campos no Inspetor. Nesta imagem, a Intensidade do Dano é o valor aleatório que afeta o Valor do Dano final – ele é exibido com o atributo Alcance.

A aleatoriedade visa dar aos jogadores desafios imprevisíveis que os levem a calcular riscos e gerenciar o resultado.

Vejamos mais alguns exemplos de como usar a classe Random.

Ponderação de aleatórios em um jogo de cartas

Imagine um jogo de cartas com um inimigo de IA que joga sua carta baseado apenas no movimento do jogador. Esse evento se tornaria rapidamente previsível sem aleatoriedade, pois retornaria o mesmo resultado todas as vezes.

Mesmo definir a probabilidade em 50% é uma aleatoriedade muito simples e logo se tornaria óbvia para o jogador. Em vez disso, tente adicionar camadas de aleatoriedade com base nas ações dos jogadores. Fazer isso criará sistemas complexos que oferecem algo mais dinâmico do que escolher entre duas cartas em um conjunto, ou se essa carta é escolhida entre muitas do conjunto existente.

Você pode adicionar níveis de dificuldade à mesa de cartas fazendo com que o inimigo favoreça certas cartas em detrimento de outras; decisões baseadas no valor que lhe foi dado ou em quão completa está sua composição antes de atacar, por exemplo. A carta de um chefe pode multiplicar sua capacidade de dano quando jogada com outras cartas de poder, então o inimigo espera até que uma certa variedade de cartas de poder esteja na mão para aumentar a dificuldade para o jogador. Você pode adicionar “peso” a tal composição aumentando ou diminuindo a probabilidade da carta do chefe ser jogada com certas outras cartas de poder.

Imagem do jogo de cartas Heartstone
Hearthstone da Blizzard Entertainment continua sendo um dos jogos de cartas mais populares. Foi lançado em 2014 e é feito com Unity.
Ruído de Perlin

Você pode usar aleatoriedade de diferentes formas em seus jogos. O ruído de Perlin, por exemplo, tem qualidades naturais e gera ruído gradiente a partir de uma semente. Tente usá-lo no Cinemachine para criar uma sensação de câmera mais orgânica para câmeras de acompanhamento em terceira pessoa.

Captura de tela do algoritmo de ruído Perlin no Cinemachine
Aproveite o algoritmo de ruído Perlin no Cinemachine para criar movimentos de câmera que pareçam mais orgânicos.

Para experimentar o ruído Perlin, confira os recursos iniciais – Controlador de personagem em terceira pessoaou os pacotes Gaia na Asset Store, junto com a documentação sobre como usar Mathf.PerlinNoise.

Imagem da textura amostrada do ruído Perlin (pontos pretos e brancos desfocados)
Veja esta textura amostrada de ruído Perlin. Em vez de valores totalmente aleatórios em cada ponto, o ruído consiste em “ondas” com valores que aumentam e diminuem gradualmente ao longo do padrão. O ruído pode ser usado como base para efeitos de textura e animação, gerando mapas de altura de terreno e muito mais.
Atacando agentes de IA

Em uma entrevista, Chris Butcher, um dos engenheiros-chefes de Halo 2 da Bungie Studios, discutiu a IA do jogo, dizendo: “O objetivo não é criar algo imprevisível. O que você quer é uma inteligência artificial que seja consistente para que o jogador possa dar a ela certas informações. O jogador pode fazer coisas e esperar que a IA reaja de uma determinada maneira.”

Imagem de um robô verde parado no meio de um terreno de baixo polígono, do lado de fora de prédios cúbicos
Esses recursos estão disponíveis no pacote Starter Assets – Third-person Character Controller da Asset Store.

Com isso em mente, como você deve configurar agentes de IA para manter seu jogo imprevisível e vivo?

Uma maneira de experimentar isso é combinar os Ativos Iniciais com ferramentas de IA da Asset Store, como o A* Pathfinding Project Pro, uma ferramenta que permite mover um agente de IA para um determinado ponto.

Quando o agente de IA se move em direção ao jogador, o jogador espera ser atacado. Mas e se isso iniciar uma conversa? Que tal adicionar mais NPCs que se movam e se misturem ao espaço para dar uma sensação mais animada? Esses NPCs podem escolher os pontos dados a eles linearmente, um por um, ou melhor ainda, escolher pontos lógicos com base em um conjunto de regras usando a classe Random.

Digamos que você tenha um agente de IA que atira no jogador com um arco e flecha fracos. Infelizmente para o agente de IA, é preciso estar a uma certa distância do personagem porque o alcance máximo para atirar é de 10 metros. A IA se posiciona na frente do jogador, a 10 metros de distância, e atira. Não é uma configuração empolgante nem ideal, especialmente se você adicionar um segundo atirador lutando pela mesma posição no NavMesh.

Para um cenário mais interessante, escolha uma área onde o inimigo deve se aproximar do jogador. Faça isso usando Random.insideUnitCircle, passando o resultado do vector2 para um vector3 para os eixos X e Z e, em seguida, aproveite RandomRange para ambos para obter uma área com um raio mínimo e máximo ao redor do jogador.

Captura de tela do script usado para um agente de IA selecionar um ponto de ataque próximo ao personagem principal
O script usado para um agente de IA selecionar um ponto de ataque próximo ao personagem principal
captura de tela das alavancas de design no Inspetor
As alavancas de design permitem que você ajuste o comportamento da IA no Inspetor.

O agente de IA deve escolher um ponto dentro de um alcance aceitável ao redor do jogador e atirar, em vez de se aproximar muito do jogador. Para adicionar mais emoção ao jogo com o mínimo de codificação, aplique isso a todos os agentes de IA para que eles ataquem o jogador de vários ângulos. A ação da IA é previsível até certo ponto porque você sabe que os agentes precisam estar a uma certa distância para atacar, mas não é possível prever os ângulos de onde eles atacarão.

imagem de um espaço lowpoly com uma mira branca sobre um círculo cinza e verde
O ponto vermelho simboliza para onde o agente inimigo irá.

Você pode desenvolver esse exemplo dando aos seus agentes de IA a capacidade de atacar corpo a corpo. Use o mesmo ponto aleatório do jogador com um raio mais estreito. Dessa forma, os agentes de IA escolhem entre um conjunto de ataques quando é hora de atacar.

O jogador sabe que pode ser atacado por uma formação corpo a corpo, mas de qual direção? Haveria um ataque de cima para baixo? Ou um amplo movimento da esquerda para a direita? Eles teriam que ler o telegrama na animação para determinar o que está vindo em sua direção.

Editor de Unity

Esse cenário pode ficar complexo se você tiver vários NPCs inimigos tentando atacar o jogador ao mesmo tempo. Mas se você olhar para Far Cry 2 da Ubisoft, por exemplo, o jogador não é atacado por todos os inimigos ao mesmo tempo. Inimigos diferentes atacarão em momentos diferentes, de maneiras aleatórias. Você pode aprender mais sobre este exemplo e outros cenários de IA neste vídeo do Game Maker's Toolkit.

Se você tentasse replicar realisticamente os resultados de ações tomadas no mundo real em seu jogo, seriam necessárias equações complexas e multifacetadas ou um agente de ML bem treinado. No final, tudo pode parecer fora do lugar, levar muito tempo e exigir muita sobrecarga técnica para ser implementado e ainda ser difícil de equilibrar e controlar com compreensão, se for mal arquitetado.

No entanto, ao usar a classe Random do Unity, os designers de jogos podem criar resultados críveis para suas cenas com controle rígido sobre os níveis de excitação, em menos tempo do que levaria de outra forma. A aleatoriedade, é claro, nem sempre é apropriada. A previsibilidade continua sendo essencial. Mas se colocados nas áreas certas, nos momentos mais oportunos, você pode proporcionar experiências únicas aos seus jogadores, que os farão querer jogar repetidamente.