Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Unity 2D

Solução para atingir alvos em movimento da Unity

by
Difficulty:BeginnerLength:MediumLanguages:

Portuguese (Português) translation by Jonathan Ramos (you can also view the original English article)

Final product image
What You'll Be Creating

Ao desenvolver jogos que envolvem elementos de ação, muitas vezes precisamos descobrir uma maneira de acertar alvos em movimento. Tais cenários geralmente podem ser chamados de "abater um alvo em movimento". Isto é particularmente proeminente em jogos de defesa de torre ou jogos de comando de míssil. Podemos precisar criar um AI ou algoritmo que possa descobrir o movimento do inimigo e disparar contra ele.

Vamos ver como podemos resolver esse problema específico, desta vez na Unity.

1. O jogo de comando de mísseis

Para este tutorial particular, vamos considerar um jogo de comando de mísseis. No jogo, temos uma torre no chão que dispara mísseis em asteroides que estão caindo. Não devemos permitir que o asteroide atinja o chão.

O jogo é baseado em toques na tela, onde precisamos tocar para apontar a torre. Com a assistência humana, a mecânica do jogo é bastante direta, pois a torreta só precisa apontar e disparar.  Mas imagine se a torre deve disparar automaticamente contra os asteroides.

Os Desafios para Auto-Firing AI

A torre precisa descobrir quantos asteroides se aproximam do solo. Uma vez que ela tenha um conjunto de todos os asteroides que se aproximam, então precisaria fazer uma análise de ameaça para determinar qual alvo atacar primeiro. Um asteróide movendo-se lentamente é uma ameaça menor que um asteróide caindo rapidamente. Além disso, um asteróide que está mais próximo do solo também é uma ameaça iminente.

Esses problemas podem ser resolvidos comparando a velocidade e a posição dos asteróides recebidos. Uma vez que determinamos o alvo, nos deparamos com um problema mais complicado. Quando a torreta deve disparar? Em que ângulo? Quando o míssil deve ser explodido após o disparo? A terceira questão torna-se relevante porque a explosão de um míssil também pode destruir o asteróide e tem um maior raio de efeito também.

Para simplificar o problema, a torre pode decidir disparar imediatamente. Então precisamos apenas descobrir o ângulo de disparo e a distância da detonação. Além disso, pode haver o caso em que o asteróide já passou pela área onde poderia ser atingido, o que significa que não há solução!

Você deve baixar a o arquivo Unity fornecido juntamente com este tutorial para ver a solução em ação. Veremos agora como chegamos a essa solução.

2. A Solução

Vamos relembrar a matemática do ensino médio para encontrar a solução. É muito direto e envolve a resolução de uma equação quadrática. Uma equação quadrática é ax^2 + bx + c = 0, onde x é a variável a ser encontrada e ocorre com a maior potência de 2.

Analisando o problema

Vamos tentar representar o nosso problema em um diagrama.

diagram of the incoming asteroid and the predicted path of missile

A linha verde mostra o caminho previsto a seguir pelo asteroide. Como lidamos com movimento uniforme, o asteroide se move em velocidade constante. Nossa torre terá que girar e disparar o míssil ao longo do caminho azul para colidir com o asteroide no futuro.

Para o movimento uniforme, a distância percorrida por um objeto é o produto do tempo e a velocidade do objeto, ou seja, D = T x S, onde D representa a distância, T é o tempo necessário para viajar até D, e S é a velocidade da viagem. Supondo que nosso asteroide e os mísseis vão definitivamente colidir, podemos encontrar a distância da linha azul seguida pelo míssil em termos de tempo t. Ao mesmo tempo t, nosso asteroide também alcançará a mesma posição.

Essencialmente, ao mesmo tempo t, o asteroide atingirá a posição de colisão a partir da sua posição atual, e o míssil também alcançará a mesma posição de colisão no mesmo tempo t. Então, no tempo t, tanto o asteroide quanto o míssil ficariam a mesma distância da torre, pois estariam colidindo.

Insirindo matemática

Podemos equiparar a distância entre a torre, o asteroide e o míssil neste tempo futuro t para derivar nossa equação quadrática com a variável t.  Considere dois pontos em um plano bidimensional com coordenadas (x1, y1) e (x2, y2). A distância D entre eles pode ser calculada usando a equação abaixo.

Se denotarmos a posição da torreta como (Tx, Ty), a velocidade do míssil como s e a posição de colisão desconhecida como (X, Y), então a equação acima pode ser reescrita como:

onde t é o tempo necessário para que o míssil percorra a distância D. Equacionando ambos, obtemos a nossa primeira equação para incógnitas X e Y com outra t desconhecida.

Sabemos que o asteroide também atinge o mesmo local de colisão (X, Y) no mesmo tempo t, e temos as seguintes equações usando os componentes horizontais e verticais do vetor de velocidade do asteroide. Se a velocidade do asteroide pode ser indicada por (Vx, Vy) e a posição atual como (Ax, Ay), então o desconhecido de X e Y podem ser encontrado conforme mostro abaixo.

Substituindo estes na equação anterior nos dá uma equação quadrática com um único t desconhecido.

Expandindo e combinando termos semelhantes:

Representar a potência de dois como ^2 e o símbolo de multiplicação como * pode ter feito o cálculo acima parecer hieróglifos, mas basicamente se resume à equação quadrática final ax^2 + bx + c = 0, onde x é a variável t, a é Vxˆ2 +Vyˆ2 - sˆ2, b é 2* (Vx* (Ax - Tx) + Vy* (Ay - Ty)) e c é (Ay - Ty)^2 + (Ax - Tx)^2. Usamos as equações abaixo na derivação.

Resolvendo a Equação Quadrática

Para resolver uma equação quadrática, precisamos calcular o D discriminante usando a fórmula:

Se o discriminante for inferior a 0, então não há solução, se for 0, então há uma única solução e, se for um número positivo, há duas soluções. As soluções são calculadas utilizando as fórmulas apresentadas abaixo.

Usando essas fórmulas, podemos encontrar valores para o tempo futuro t quando a colisão acontecerá. Um valor negativo para t significa que perdemos a oportunidade de disparar.  As incógnitas X e Y podem ser encontradas substituindo o valor de t em suas respectivas equações.

Uma vez que conhecemos o ponto de colisão, podemos rotacionar a nossa torre para disparar o míssil, o que definitivamente atingiria o asteroide móvel após t segundos.

Implementando na Unity

Para o projeto de exemplo na Unity, usei o recurso de criação de sprite da versão Unity mais recente para criar os assets necessários. Isso pode ser acessado com Create > Sprites >  como mostrado abaixo.

Implementing in Unity

Nós temos um script de jogo chamado MissileCmdAI que está anexado à câmera de cena. Ele contém a referência ao sprite da torre, o prefab do míssil e o prefab do asteróide. Estou usando o SimplePool feito por quill18 para manter um pool de objetos para mísseis e asteroides. Pode ser encontrado no GitHub. Existem scripts de componentes para mísseis e asteroides que estão anexados aos seus prefabs e manipulam seu movimento uma vez que são lançados.

Os asteroides

Os asteroides são gerados aleatoriamente em altura fixa, mas uma posição horizontal e velocidade de lançamento aleatória. A frequência de aparição dos asteroides é controlada usando um AnimationCurve. O método SpawnAsteroid no script MissileCmdAI está escrito assim:

O método Launch na classe Asteroid funciona assim:

Conforme visto no método Update, uma vez que o asteroide percorreu a distância predeterminada ao chão, deployDistance, ele retornaria ao seu pool de objetos. Essencialmente, isso significa que ele colidiu com o chão. Isso faria o mesmo no caso de colisão com o míssil.

A mira

Para que a mira automática funcione, precisamos chamar frequentemente o método correspondente para encontrar e segmentar o asteroide recebido. Isso é feito no script MissileCmdAI em seu método Start.

O método FindTarget acompanha todos os asteroides presentes na cena para encontrar os asteroides mais próximos e mais rápidos. Uma vez encontrado, ele então chama o método AcquireTargetLock para aplicar nossos cálculos.

AcquireTargetLock é onde a mágica acontece enquanto aplicamos nossas habilidades de resolução de equações quadráticas para encontrar o tempo de colisão t.

Uma vez que encontramos o ponto de impacto, podemos calcular facilmente a distância da viagem do míssil para atingir o asteroide, que é transmitido através da variável deployDist para o método LockOn do míssil. O míssil usa este valor para retornar ao seu pool de objetos uma vez que ele percorreu essa distância da mesma maneira que o asteróide. Antes disso, teria atingido definitivamente o asteróide e os eventos de colisão teriam sido desencadeados.

Conclusão

Uma vez que a implementamos, o resultado parece quase mágico. Ao reduzir o valor aiPollTime, podemos torná-lo uma torre com inteligência invencível que derruba qualquer asteroide, a menos que a velocidade do asteroide se torne próxima ou superior à velocidade do míssil. A derivação que seguimos pode ser usada para resolver uma variedade de problemas semelhantes que poderiam ser representados na forma de uma equação quadrática.

Gostaria que você experimentasse ainda mais, adicionando o efeito da gravidade ao movimento do asteróide e do míssil. Isso mudaria o movimento do projétil, e as equações correspondentes mudariam. Boa sorte.

Note-se também que a Unity tem uma economia ativa. Existem muitos outros produtos que o ajudam a desenvolver seu projeto. A natureza da plataforma também torna uma ótima opção a partir da qual você pode melhorar suas habilidades. Seja qual for o caso, você pode ver o que temos disponível no Mercado Envato.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.