Cursos / Jogos Digitais / Inteligência Artificial para Jogos / Aula
Passo 02 – Criando o jogador
Agora que você tem um cenário montado, comece a pensar em como fazer o jogador se deslocar dentro do campo. Sinta-se como o técnico que manda os jogadores se aquecerem, correndo de um lado para o outro. Porém, a ordem a ser dada deve ser no formato de algoritmo.
A melhor forma de começar é definindo um NPC simples, que se desloque de um ponto para o outro. Como você é o técnico, ele precisa te obedecer seguindo os seus comandos e, para isso, você terá de clicar sobre uma posição do campo. Sendo assim, escreva um script para definir esse comportamento.
Comece criando uma classe que herda de MonoBehavior, especificando nela dois atributos públicos: um que armazena a posição para a qual o NPC deve ir, chamada goal, e outro denominado speed, que especifica a velocidade com a qual o NPC consegue se deslocar da posição em que ele se encontra até seu objetivo. O goal precisa ser um atributo da classe Vector2, pois ele conterá as coordenadas x e y, enquanto speed pode ser um valor real (float).
No Unity, uma das formas de definir os movimentos de um NPC, principalmente quando envolve velocidade, é atribuindo-lhe um corpo físico. Para isso, insira o componente Rigidbody2D no NPC. Esse componente, vai servir de quebra, ainda, para dar um “chega pra lá” nos outros jogadores.
Como você está vendo os jogadores “de cima”, altere a gravidade do componente Rigidbody2D para 0, caso contrário, o jogador será puxado pela gravidade, “caindo na tela”. Além dos elementos já descritos, acrescente os métodos Start(), AdjustSpriteRotation(), GoTowardsGoal(), FixedUpdate() e Update() no script, conforme o exemplo a seguir, a fim de que o NPC se desloque para onde o técnico (você) clicar.
Ao ser instanciado, o objeto associado ao script inicia (no método Start()) armazenando o componente de corpo rígido Rigidbody2D para posterior uso, calcula a direção a ser seguida até um ponto-objetivo (GoTowardsGoal()) e gira a imagem do Sprite na direção em que o objeto se encontra (AdjustSpriteRotation()).
O método GoTowardsGoal() calculará qual a direção que o NPC deve girar para ir ao seu objetivo, através da subtração dos vetores, como ilustra a Figura 06.
Como você pode ver na Figura 06, o NPC se desloca no sentido apontado pela seta azul. Quando o usuário clica em um ponto da tela, gera um novo objetivo para ele alcançar. Para que a transição da trajetória do novo objeto seja feita de forma mais “natural”, é necessário calcular um vetor que indique o deslocamento da direção atual para a desejada. Logo, o deslocamento é ajustado para a direção que aponta a seta verde, obtida pela subtração do vetor laranja pelo azul.
Em seguida, o vetor resultante dessa subtração é redimensionado, de modo a especificar no speed a magnitude da velocidade. Faça isso, multiplicando a velocidade pela versão normalizada (que tem tamanho 1) da direção. Atribuindo ao vetor resultante a velocidade do componente body, o NPC se deslocará na velocidade desejada. Na verdade, o movimento do NPC é calculado através do método de Euler, que define de forma simples uma aproximação do cálculo da equação de movimento, após uma sequência de atualizações, usando a fórmula a seguir.
Algoritmo 01 – Método de Euler para aproximação do deslocamento
posição = posição + velocidade
O método AdjustSpriteRotation() tem como objetivo girar o sprite do NPC na direção já calculada em GoTowardsGoal(). Para fazer isso, calcula-se o ângulo entre o eixo X (definido pela constante Vector2.right) e a direção que o NPC se encontra, usando a função Angle(). Essa função retorna sempre o menor ângulo entre os dois vetores (o ângulo agudo entre eles). Como no ângulo retornado não há informação a respeito do sentido ser anti-horário ou horário e como o Sprite precisa ser girado no sentido anti-horário, há necessidade de verificar se o valor da coordenada Y da direção é negativo. Caso seja, gire no sentido anti-horário com mais que 180 graus, fazendo a diferença do ângulo retornado com 360 graus, para conseguir esse resultado.
Por fim, existem dois métodos de atualização: UpdateFixed() e Update(). O primeiro serve para atualizar os elementos do jogo em um intervalo fixo de tempo, ideal para simulações físicas e para que os movimentos do jogo não fiquem lentos. O segundo, por sua vez, é chamado sempre que um novo frame de visualização deve ser renderizado. Assim, insira a atualização do movimento do NPC em UpdateFixed() e a atualização do objetivo (goal) para quando o usuário clicar em um ponto do campo em Update(). Nesse último, sempre que o botão Fire1 for pressionado (isso equivale ao botão esquerdo do mouse), o script atualiza as coordenadas de seu objetivo e vai em direção a ele.
Ótimo! Você já fez o script de comportamento do jogador. Mas onde está a inteligência artificial aí? Bom… por enquanto, em lugar nenhum. Você vai começar a inseri-la no momento em que quiser adicionar mais realismo à cena.
Por exemplo, imagine que há dois jogadores seguindo o mesmo script. Isso significa que quando você clicar na tela, os dois tentarão ir para o mesmo ponto e ficarão um sobre o outro. Aí o juizão vai marcar falta!
Uma solução é adicionar um componente para tratar das colisões dos objetos. Pode-se, então, inserir no objeto ou o componente CircleCollider2D ou o BoxCollider2D. As opções padrões (default) já fazem a configuração necessária para você. Procure fazer isso e você vai ver que não haverá mais sobreposição de jogadores.
Porém, experimente, agora, colocar mais jogadores, cada um com um goal diferente. Você perceberá o quanto esses jogadores são… limitados.O comportamento deles não é nada realista, porque eles tentam ir para os seus destinos por meio de uma reta em direção ao alvo, mesmo que haja obstáculos (outros jogadores) a sua frente e que ninguém em um “estado normal” aja assim. Desse modo, você precisa adaptar os jogadores para que eles saibam como desviar de obstáculos à frente..
Você verá como fazer isso nesta... Não! Na próxima aula. rsrs Vou começar com um pouco de teoria, descrevendo como surgiu o que é chamado atualmente de “comportamentos de navegação” ou, em inglês, steering behaviors.
Versão 5.3 - Todos os Direitos reservados