[XNA] Movimento de uma flecha ao ser disparado em um jogo 2D
Olá pessoal, estamos desenvolvendo um joguinho que se chama Balloons Buster, baseado nos jogos de atirar nos balões com flechas “Balloon Hunter“, neste caso estamos fazendo em XNA. Tirando algumas dúvidas nos livros de física e no fórum da Unidev implementei de maneira simples a trajetória de uma flecha ao ser disparada com um determinado ângulo e força de um ponto inicial. Então hoje vamos aprender como isso funciona para vocês verem que não é difícil.
Mas antes de começarmos precisamos entender corretamente o que precisamos fazer, então vamos analisar o imagem abaixo.
Então é o seguinte, precisamos lançar uma flecha com uma determinada força ou velocidade e ela também deve modificar ao longo da trajetória modificar sua orientação. Temos, o vetor V que representa a direção e velocidade que a flecha é disparada. Como obtemos ela.
Decompondo o vetor V em:
vetor.X = velocidade * Cos(θ);
vetor.Y = velocidade * Sin(θ);
Tendo nosso vetor de direção inicial, precisamos agora somar sempre este vetor a nossa posição inicial, ou seja:
posicao.X = posicao.X + vetor.X;
posicao.Y = posicao.Y + vetor.Y;
Perceba estamos incrementando nossa posição X e Y inicial da flecha, fazendo ela se movimentar. Mas se você analisar você esta somando sempre e a flecha vai seguir o veto como se fosse uma reta. Porém o que queremos é que a flecha perca a velocidade por causa da gravidade do nosso planeta. Se não existisse a gravidade provavelmente se você lançar algo para uma direção, o objeto iria permanecer nesse trajeto até bater em algo. Então precisamos agora diminuir Y.
vetor.Y = vetor.Y – gravidade; (errado para um jogo)
Note que o eixo Y no jogo é inverso ao plano cartesiano que aprendemos na escola, ou seja ao invés de diminuirmos Y, vamos aumentá-lo.
vetor.Y = vetor.Y + gravidade; (correto para o jogo)
Legal, perceba que agora a cada atualização a posição X continua aumentando constantemente e a Y vai diminuindo aos poucos pela ação da gravidade. Mas se pararmos para pensar, nossa flecha esta subindo em direção ao nosso vetor, e aos poucos o Y vai diminuindo fazendo nossa flecha descer, mas nossa flecha continua com a mesma orientação que ela saiu pois não estamos mudando esta orientação. E como vamos fazer isso ?
Utilizando a tangente podemos calcular o ângulo com base em dois pontos num plano cartesiano, ou seja se temos a posição inicial da flecha e temos a próxima posição, é possível calcular com Atan2 a orientação da flecha.
rotacaoFlecha = Atan2(novaPosicao.Y – posicao.Y, novaPosicao.X – posicao.X);
Agora temos a cada atualização do jogo o calculo da próxima posição da flecha, mais a sua rotação dado a posição passada e a próxima calculada.
Vamos ver como ficaria isso no XNA, então crie um novo programa (LancamentoFlecha), e adicione a imagem abaixo ao seu projeto dentro da pasta Content.

- flecha.png
O Solution do programa é para ficar desta maneira.

Agora vamos definir as variáveis que precisaremos, mas iremos acrescentar também uma resistência no ar contra a flecha para deixar mais real.
O próximo passo é inicializarmos as variáveis que precisamo ser inicializadas, veja com isso deve ficar:
Você deve estar se perguntando o porque de certos valores, não se preocupe, quando você executar o projeto você poderá analisar o que cada valor faz com sua flecha.
Se você colocar um valor alto para a gravidade, sua flecha irá cair muito rápido. Se a velocidade for alta a flecha ira deslocar rapidamente pela tela e você não vai acompanhar o movimento dela. A posição inicial nossa é só para um chute para vermos o movimento. Vale também a pena lembrar que ao usar funções como seno e coseno, os valores usados devem ser sempre em radianos.
O próximo passo é carregar a textura da flecha.
A cada atualização precisamos calcular o próximo ponto, aplicar a gravidade ao vetor Y, verificar a nova orientação da flecha, e aplicar a nova posição a posição dela. Veja como fica:
O valor da resistência do ar neste exemplo é de 0.01f, esse valor deve ser menor que a gravidade, por que se não for, a flecha irá entrar em rotação.
Enfim , só falta desenhar
Vamos entender o porque desse Draw enorme.
SpriteBatch.Draw(Texture2d texture, Vector2 position, Rectangle ? sourceRectangle, Color color, float rotation, Vector2 origin, SpriteEfects effects, float LayerDepth)
Vamos analisar o que fizemo no Draw:
- Colocamos nossa texturaFlecha
- A posição calculada da flecha
- Definimos o tamanho do retângulo da figura, ou seja, definimos que nossa imagem é do tamanho total dela
- Colocamos como sempre a cor branca
- Aqui vem a orientação calculada pelo Atan2(y,x)
- Definimos a partir de qual a figura vai sofre rotação, então colocamos a ponta da flecha
- Valor 1 padrão
- Definimos sem efeito
- Valor 0 para profundidade
Agora é só executar o programa e ver o resultado:
Se você quiser, brinque um pouco com os valores da gravidade, velocidade, ângulo e até mesmo a resistência do ar.
Para fazer download do projeto completo com o código fonte clique aqui.
Agradecimentos especiais a Kamus do Poder e RafaGamer2005 membros da Unidev.
Abraço galera, espero que tenham gostado.








Ae Klebão, tá de parabéns
Obrigado, valeu kakaroto !
Show de bola Kleber… Pelo visto o jogo vai ficar muito bom.
Aguarde meu pac-man revolucionário… rsrsrsrs
Abração!
Eai André, espero que o jogo fique bom sim… mas vamos ver como vai ficar. Quero só ver, pelas imagens seu pacman vai ficar legal mesmo, estou louco para ver ele pronto também.
Abraços t+
Parabéns cara, muito bom o tutorial! Só tenho uma duvida, a posição que você passa (x,y) para o Vector2 é tratada como int ou como float?? Por que no caso (corrija-me se eu estiver errado xD) você manda a coordenada do pixel onde sera iniciado o desenho da sprite, mas se esse valor for um float (ex: 230,35) ele desenharia nessa posição ou arredondaria para 230/231?
Flw, Vlw!
Obrigado amigo. No caso o Vector2 trabalho com float. Ou seja, você pode fazer as divisões sem se preocupar, pois o XNA posiciona em float também.
Abraços, t+
Desculpe, eu segui seu tutorial passo a passo para me ajudar com o problema que estou tendo com o meu projeto, pois estou tendo dificuldade com lançamento obliquo. Mas infelizmente no meu caso, isso não deu certo! Se puder entrar em contato comigo, ficarei grata!
Olá, sem problemas, é só me mandar um email ou me add no msn que te ajudo com seu problema.
Att,
Opa.
Ajudou muito cara.
Apesar de não precisar agora, certamente um dia irei precisar.
Abraços.
Por nada, quando precisar é só lembrar onde você viu o exemplo.
Abraços,
Amo seu site, se eu fosse mulher eu dava pra você huauhauhauhauhauhauha
Não precisa amigo, mesmo se fosse mulher, já encontrei a mulher da minha vida faz 2 anos
Bem basicamente gostaria de saber como eu poderia atirar outra flecha, apertando algum botao.
Olá amigo, é só adicionar cada flecha atirada numa lista de flechas, e mandar sempre atualizar e desenhar a lista toda.
[]s
e aw klebão , parabéns pelo trabalho , mt massa .
me diz uma coisa , se eu quiser fazer esse movimento infinitas vezes eu devo usar o
for( ; ; ) ? se sim , onde ??
valeu , abraçãoo
Obrigado Décio.
Sobre sua pergunta, se você colocar um loop infinito em algum método do seu jogo (por exemplo, Update(GameTime)) você ira travar o método, pois o laço de repetição nunca vai acabar, então seu método nunca será finalizado para que o loop do game possa proseguir.
O que você pode fazer é simples criar uma flag de tempo, dizendo por exemplo, a cada 10 segundos passados você criar uma nova flecha e adiciona em uma lista, ai você fica atualizando e desenhando as informações dessa lista. Porém, você ainda terá um problema, que é quando a lista ficar muito grande como ocupação de memória ou até mesmo lentidão para percorrer a lista, para resolver isto você teria que ficar analisando os limites do seu jogo e remover as flechas inúteis.
Abraços.
Kleber, gostei muito… parabpens.
Por nada amigo, continue estudando.
Abraços.
Parabéns Kleber.
Estou apenas engatinhando em desenvolvimento de games, mas tudo que aprendo eu ensino para meus alunos e agora estou com um mini curso de jogos eletronicos (voluntario), e seu Blog tem me ajudado muito.
Obrigado Lucio, é bom poder sempre ajudar os outros. Eu também, não sei tanto assim, mas sempre que posso ajudar é bom.
Abraços.
Motivado por seu Blog, já estou planejando criar um também, mas voltado para Lógica de programação e quem sabe Allegro. Já adicionei seu blog como referência na apostila e notas de aula do mini curso de jogos.
Abraços
Legal, obrigado pelas referências no curso.
Sobre o blog de lógica e allegro, isso seria bem legal também, quando montar me passe o link que terei o prazer de adicionar nos meu blog.
Não deixe de acessar também o nosso portal de games: http://www.pontov.com.br
Espero esse ano conseguir reformatar meu blog, vamos ver se vai dar certo.
Abraços.