Não esqueça de preparar seu ambiente de desenvolvimento
Se você não acompanhou o último artigo e não tiver a última versão do projeto que está sendo desenvolvido, poderá fazer o download dele acessando o endereço: http://sdrv.ms/ZJ6bFv.Lembrando que, para desenvolver o que é proposto na coluna, é necessário ter instalado em sua máquina o Microsoft Visual C# 2010 Express e o XNA Game Studio, ambos gratuitos.
Se você está utilizando o Windows 8, então talvez tenha algum problema ao instalar o XNA Game Studio. Esse erro ocorre porque o Game Studio instala consigo uma versão do Games for Windows – LIVE nos bastidores. O problema é que há incompatibilidade entre o Games for Windows – LIVE que o XNA está tentando instalar e o Windows 8, mas isso pode ser corrigido baixando e instalando manualmente a versão mais recente no seguinte link: http://bit.ly/W96StP.
Ao finalizar a atualização, basta tentar instalar o XNA Game Studio novamente e deverá funcionar.
Entendendo os conceitos de colisões
Fazer com que o sprite tenha sua movimentação limitada às bordas do jogo não deixa de ser uma forma de detecção de colisão, bem simples, é verdade. Porém, em jogos 2D, geralmente se deseja realizar detecção de colisão entre dois ou mais sprites.
Existem várias formas de trabalhar com detecção de colisões em qualquer jogo que se queira fazer – basta dar uma procurada no oráculo para constatar essa afirmação. Porém, o objetivo aqui é apresentar um exemplo simples para que os que acompanham a coluna possam entender o conceito.
Quando se trabalha com detecção de colisões, não é sensato pensar em testar pixel por pixel em cada um dos sprites do jogo. Já imaginou o quão trabalhoso isso seria? E o quanto a performance comprometeria o desempenho do jogo?
Desse modo, os algoritmos de detecção de colisão trabalham com representações aproximadas das formas dos sprites, o que já facilita bastante a elaboração da sua fórmula. Os algoritmos de detecção de colisão mais comuns utilizam o conceito de bounding boxes, que aproxima a forma do objeto com um ou mais retângulos, ou caixas (daí a palavra boxes). A figura abaixo nos mostra um sprite cuja forma está contida dentro de uma caixa que define seus limites para colisão.
Implementando o bounding box
Uma maneira simples de desenvolver e testar o bounding box é simplesmente verificar se as posições das coordenadas X e Y da primeira caixa (que envolve o sprite que você deseja testar) estão dentro da segunda caixa (que envolve o segundo objeto a ser testado).
Em outras palavras, você deve verificar se os valores de X e Y da caixa que quer testar são menores ou iguais aos valores de X e Y da outra caixa, mais a largura da outra caixa.
Sendo assim, mãos à obra. No arquivo classSprite.cs, adicione o seguinte método (nomeado de detectaColisao) que receberá um sprite como parâmetro e o testará com o sprite atual. Se houver uma colisão, o método retornará verdadeiro.
Para entender a lógica desse código, analise-o observando a figura abaixo e prossiga somente se tiver certeza do que está acontecendo aqui.
Analisando o exemplo do código, as duas caixas só irão se sobrepor se ambas as coordenadas X e Y do retângulo 2 estiverem no intervalo (X para X + largura, Y para Y + altura) do retângulo 1. Observando a figura acima, veja que a coordenada Y do retângulo 2 não é maior que a coordenada Y mais a altura do retângulo 1. Isso significa que suas caixas podem estar colidindo. Porém, quando verificamos a coordenada X do retângulo 2, você verá que é maior que a coordenada X mais a largura do retângulo 1, o que significa que as caixas não estão colidindo.
A figura abaixo ilustra uma situação em que você tem uma colisão. Nesse caso, perceba que ambas as posições, X e Y, do retângulo 2 estão contidas no intervalo do retângulo 1. No exemplo de código, você também faz o teste oposto, verificando se as coordenadas X e Y do retângulo 1 estão contidas no intervalo do retângulo 2. Dessa forma, estamos nos prevenindo de, por exemplo, o canto superior esquerdo do retângulo 2 estar fora do retângulo 1, mas o topo deste estar dentro do retângulo 2.
Para testar o método na prática, você criará um segundo sprite no meio da tela do jogo. Para fazer isso, basta replicar o sprite que você criou no encontro anterior e incluir o código para testar colisões no método Update na classe Game1.
Primeiramente, declare uma nova variável de sprite no início da classe Game1, junto com as outras definições:
Agora, no método LoadContent, inclua o código para a criação e inicialização do sprite:
E não se esqueça de adicionar o código para descarregar o sprite no UnloadContent:
No método Update, inclua o código para movimentar o sprite na tela:
E, finalmente, no método Draw, inclua o código para desenhar o novo sprite na tela:
Nesse momento, se você executar o jogo, perceberá que os dois sprites estão se movimentado, mas ainda não estão colidindo. Resolveremos isso adicionando uma chamada ao método detectaColisao no método Update e alterando a velocidade entre os sprites, conforme segue abaixo:
Agora sim, se você executar o seu jogo, irá perceber que os sprites estão colidindo um com o outro, além de colidirem com as bordas da janela. Bacana, não?

Quando quiser testar colisões entre esferas, verifique se a distância entre os centros delas são menores que a soma dos seus raios. Em caso positivo, então uma colisão ocorreu. Essa é a forma mais eficiente de detectar colisões entre duas esferas.
Para dar suporte a esse sistema, na classe classSprite vamos criar duas novas propriedades, uma chamada centro e outra raio, que serão calculadas de acordo com outra propriedade do sprite.
Em seguida, crie um novo método para testar esse tipo específico de colisão:
Finalmente, atualize o método Update na classe Game1 para chamar o método detectaColisaoCirculo ao invés do detectaColisao. Agora sim, você perceberá que os círculos só irão colidir quando eles de fato colidirem ;)
No encontro de hoje você trabalhou a ideia básica de um sistema de detecção de colisões entre dois sprites em um jogo 2D. Aos poucos você está avançando nos conceitos de programação de jogos e no próximo artigo aprenderá a capturar a entrada de dados do jogador via teclado e a utilizará para controlar um dos sprites. Fique ligado e até lá!
O projeto atualizado com o código desse encontro pode ser baixado no endereço: http://sdrv.ms/103ONfV
Revisão: Bruno Nominato
Comentários