Simulando um "tiro" em jogos 2D com Delphi

Veja neste artigo como simular um “tiro” como em um jogo 2D estilo plataforma, utilizando regras matemáticas para traçar o percurso do disparo.

Veja neste artigo como simular um “tiro” como em um jogo 2D estilo plataforma, utilizando regras matemáticas para traçar o percurso do disparo.

Você já deve ter visto, em algum momento, um jogo 2D estilo plataforma, onde personagem disparam uns contra os outros, estando eles em posições horizontal e verticalmente distantes no cenário. Mas como saber movimentar o “tiro” até que ele atinja o oponente? É exatamente isso que abordaremos neste artigo, veremos que a importância da matemática em situações como essa.

De fato, o Delphi não foi pensado para ser uma plataforma de desenvolvimento de jogos, uma boa prova disso é que as posições horizontal e vertical dos controles são dadas por números inteiros, o que nos fará perder um pouco de precisão no disparo, mas nada que atrapalhe tanto. Então, mãos à obra.

Inicialmente, vejamos a parte matemática por trás disso tudo. Observe a imagem abaixo:


Figura 1 - Interpretação geométrica do cenário

Como se trata de um jogo 2D, o cenário é baseado no plano cartesiano, onde a posição de cada elemento é dada por um par ordenado (X, Y), no Delphi, (Left, Top). Na figura, o personagem A encontra-se na posição (Xa, Ya) e o personagem B encontra-se na posição (Xb, Yb). A distância vertical entre eles é dada por Dy = Ya-Yb, e, de forma análoga, a distância horizontal é dada por Dx = Xa-Xb.

Para simular o disparo, é necessário traçar uma reta entre os pontos A e B. Do estudo da geometria, sabemos que toda reta é dada por uma equação do tipo: Y = a.X + b, onde “a” é chamado de coeficiente angular e define a inclinação da reta; “X” é a posição horizontal; e “b” indica o valor de Y para X=0, que deve ser somado para “equilibrar” a posição vertical, caso contrário, estaríamos supondo que a reta passa pela origem (o que nem sempre é verdade).

Para encontrarmos os valores de “a” e “b”, usamos as seguintes expressões:

a = Dy/Dx = (Ya-Yb)/(Xa-Xb)

b = Yb - a.Xb (equivale a resolver a equação Y = a.X+b, para X=Xb e Y=Yb)

Com isso, temos o bastante para definir uma reta que representará o percurso descrito pelo disparo, desde o atirador até o alvo. Porém, antes de codificar isso no Delphi, é necessário entender uma pequena diferença entre o posicionamento de um ponto no plano cartesiano e em um form no Delphi. No plano cartesiano, o eixo Y é crescente no sentido ascendente, já no Delphi, ocorre o inverso, o Top dos componentes cresce “para baixo”. Para adaptarmos as teorias matemáticas vistas aqui ao Delphi, é preciso fazer a seguinte alteração: a posição Y dos controles (personagens e disparo) deverá ser calculada como a diferença entre a altura do form que os contém e da sua posição Top, ou seja Y = form.Height - controle.Top;

Partindo para a prática, crie uma nova aplicação VCL, com um form e, neste form, adicione 3 TShape, 1 TButton e 1 TTimer e configure-os da seguinte forma:

Listagem 1: Definição dos componentes utilizados

TShape Name = ‘Tiro’ Left = 10 Top = 500 Width = 25 Height = 25 Brush.Color = clNavy //ou outra cor, apenas para diferenciar do personagem Shape = stCircle end TShape Name = ‘Atirador’ Left = 10 Top = 500 Width = 60 Height = 60 end TShape Name = ‘Alvo’ Left = 500 Top = 100 Width = 60 Height = 60 TButton Name = ‘btnDisparar’ Caption = 'Disparar' end TTimer Name = ‘Timer1’ Enabled = False Interval = 1 end

Depois, declare as seguintes variáveis na seção private do form:

Listagem 2: Definição das variáveis utilizadas

x0, y0, x1, y1, a, b:Real; direcao:Integer;

A variável direção será usada para indicar se o alvo está na frente(da esquerda para a direita) ou atrás do atirador. Se estiver na frente, seu valor será 1, caso contrário, receberá -1.

No evento onClick do botão, escreva o seguinte trecho de código:

Listagem 3: Definindo o percurso do disparo

x0 := Atirador.Left; y0 := Self.Height - Atirador.Top; x1 := Alvo.Left; y1 := Self.Height - Alvo.Top; a := ((y1-y0)/(x1-x0)); b := y1 - a*x1; if (Alvo.Left > Alvo.Left) then direcao := 1 else direcao := -1; Timer1.Enabled := True;

Por fim, no evento onTimer do Timer1, codifique da seguinte maneira:

Listagem 4: Movimentando o tiro até o alvo

Tiro.Left := Tiro.Left + direcao; Tiro.Top := Round(Self.Height - (a*Tiro.Left + b)); if ((direcao = 1) and (Shape3.Left >= Shape2.Left)) or ((direcao = -1) and (Shape3.Left <= Shape2.Left))then begin Timer1.Enabled := False; Tiro.Left := Shape1.Left; Tiro.Top := Shape1.Top; end;

O if da listagem 4 é usado para reposicionar o tiro quando ele atingir o alvo ou passar deste.

Usamos ainda a função Round para arredondar o valor de Y para o tiro, pois, como foi dito, o Delphi trabalha com números inteiros para as propriedades Top e Left.

Bem, esse foi um exemplo bem simples de como simular um disparo em jogos 2D. Caso fique alguma dúvida sobre o conteúdo exposto, ponho-me à disposição para esclarecimentos, através dos comentários ou por email (de preferência pelos comentários, para que outros possam ver).

Por hoje é só, pessoal. Espero que tenham gostado. Até a próxima!

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados