Compendium - Projéteis em jogos 3D

Nesse documento você vai aprender a criar projéteis 3D para o seu jogo de Plataforma ou Top Down Shooter 3D. Você vai aprender a como trabalhar com instâncias de objetos dentro das cenas no Godot.

Em alguns jogos em 3D, tanto o personagem quanto o inimigo podem possuir habilidades de atirar projéteis na fase. Nesse documento você vai aprender a como criar e utilizar projéteis em cena em jogos estilo:

O jogo My Friend Pedro é um shooter plataforma 3D

     

Já o jogo Capital Zombies é um shooter top down 3D

Criando o projétil

Vamos começar criando uma nova cena onde vai ficar o projétil. Para isso precisamos criar uma estrutura de nodes dessa maneira (Renomeie os nodes):

Area (Projectile)

Crie uma malha para o seu objeto selecionando o node MeshInstance e depois o atributo Mesh na aba Inspector. Não se esqueça do colisor com o node CollisionShape e de diminuir o tamanho da mesh do objeto para que ele não fique tão grande.

Depois salve a sua cena e adicione um script no node raiz. Dentro dele vamos criar duas variáveis: uma para armazenar o valor da variável de velocidade e outra para armazenar o vetor de direção para onde o objeto deve se mover:

Agora dentro da função _physics_process(delta) precisamos aplicar a força de movimento ao projétil com a função global_translate(). Dentro multiplicamos com a variável de direção a velocidade junto com delta:

Salve a sua cena. O projétil não vai funcionar, pois é preciso ainda identificar qual será a direção da bala, e isso será feito dentro do script do personagem quando o jogador criar o projétil.

Instanciando projéteis

Com a cena do projétil criado, podemos começar a utilizá-lo dentro de outras cenas. Antes o personagem deve possuir a mecânica de movimento plataforma já construída (Obs.: Veja o Compendium - Movimento Plataforma 3D caso não tenha a mecânica criada). A estrutura da cena do personagem deve ser essa (Renomeie os node):

 

KinematicBody (PlayerPlatform)

É importante que o SpawnPoint fique no início do cano de onde serão criados os projéteis. Depois dentro do script do personagem podemos inserir o código que vai fazer ele atirar.

Primeiro devemos criar a variável que vai armazenar a cena do projétil. É importante que ela possua o load para carregar a cena dentro da variável junto com o path (caminho) do projétil:

Criado a variável com a cena do projétil, vamos criar a condição que vai disparar os projéteis na cena. Podemos criar uma tecla de ação indo na aba Project > Project Settings > Input Map. Vamos utilizar a tecla X para disparar:

Dentro do _physics_process(delta) vamos criar a condição que vai fazer o personagem disparar usando o input que criamos anteriormente:

Para que os tiros sejam criados, dentro da condição deve existir uma variável que usaremos para armazenar uma instância da cena do projétil,ou seja, uma cópia dele com a função instance():

O segundo passo é adicionar essa cena dentro de algum node. Normalmente utilizamos a função add_child e guardamos a cena criada dentro do node raiz com get_parent():

O terceiro passo é fazer com que a posição do projétil seja a mesma do nosso “spawnador” que está na ponta do canhão. Podemos utilizar a função global_transform para coletar as informações de posição, rotação e escala do objeto:

Por fim, precisamos fazer com que cada bala instanciada tenha uma direção. Lembra que criamos a váriavel bulletDirection lá dentro do script do projétil? Agora vamos fazer com que ela receba a direção atual com basis identificando o eixo em que o personagem está olhando para frente (Nesse caso o X):

Teste seu código depois disso e perceba que você já consegue atirar. O único problema é que não conseguimos virar para trás. Para isso precisamos rotacionar nosso objeto quando pressionarmos as teclas de direção utilizando a função rotation_degrees e identificando seu eixo de rotação (no caso Y):

Destruíndo projéteis

Algo importante que sempre deve ser feito é destruir os projéteis em cena. Isso pode causar lentidão dentro do jogo devido ao número de objetos presentes. Para fazer isso é bem simples: crie uma parede utilizando o node StaticBody na cena do jogo e insira uma CollisionShape.Depois renomeie seu node para Wall:

Depois dentro do script do projétil, basta criar um signal de colisão com o node Area.O nome dele é OnBodyEntered:

Dentro da função criada, basta criar uma condição que compara se a colisão ocorreu com algum corpo estático, ou seja, com um StaticBody. Se sim apenas destruímos o projétil com queue_free():

Agora qualquer sólido na fase destruirá os projéteis caso entrem em colisão.