
Uma das coisas mais importantes em um jogo é a colisão. Isso não significa que deva haver uma explosão ao colidir sprites, mas simplesmente fazer com que o Super Mario possa caminhar sobre o chão sem atravessá-lo.
Existem muitas implementações para colisão. Desde implementações simples até das mais complexas. Por exemplo, a colisão usada nos jogos do Mario para coletar as moedas só precisa informar se Mario tocou a moeda. Mas para testar a colisão em um koopa, é necessário verificar se Mario está acima ou no lado ao tocar o inimigo. Caso esteja em cima, Mario sai ileso e elimina o inimigo. Caso esteja no lado, Mario perde uma vida.
Para testar uma colisão dessas, é bem mais complicado. Principalmente se os sprites se movem com mais velocidade.
O que vou mostrar agora é a colisão simples (aquela da moeda). Até porque a minha colisão que detecta a direção do toque não é 100% confiável em altas velocidades (parece até coisa de mecânica quântica). Eu digo "minha" colisão porque fiz questão de tentar criar uma solução por conta própria, sem pesquisar nada na internet. É claro que futuramente terei que ir atrás disso, pois não sou um bom programador de jogos e nem um bom matemático.
Para detectar uma colisão simples, o ideal é usar cálculos e algoritmos que usem poucos ciclos de CPU. É bem difÃcil saber o quanto um cálculo usa de CPU. Mas podemos deduzir a complexidade dele pela quantidade de linhas de códigos e quantidade de loops usados.
Uma das minhas idéias iniciais para detectar colisão deixou o jogo com uns 5 quadros de animação por segundo. Enquanto as outras duas mantinham a velocidade de 50. Aà podemos ver que não daria certo usá-la
Mas porque ficou tão pesado? Porque o que eu fazia era comparar pixel por pixel a área utilizada por cada um dos sprites que eu estava testando a colisão. Quando eu vi a degradação da performance, logo busquei outra alternativa, bem mais leve.
Vamos a elas:
Mas para fins didáticos, vou mostrar minha idéia dos 5 FPS:
Comparando colisão entre sprite1 com sprite2:
1 - gerar lista com todos os pixels do sprite1
2 - gerar lista com todos os pixels do sprite2
3 - comparar cada pixel com sprite1 com cada pixel do sprite2
Este método é bastante lento, mas 100% confiável. O problema é que se um sprite com 50x50 pixels for comparado com outro sprite 50x50, estaremos comparando 2500 pixels contra outros 2500. Isso tudo 50 vezes por segundo.
O método mais simples e igualmente preciso que eu usei no jogo foi este:
1 - Verificação Horizontal (Eixo X):
1.1 - Subtrair a distância (sempre em pixels) da extremidade da direita do sprite mais à direita com a extremidade esquerda do sprite mais à esquerda;
1.2 - Somar a largura do sprite1 com a largura do sprite2;
1.3 - se a distância for menor ou igual à soma das larguras, realizar a verificação Vertical.
2 - Verificação Vertical (Eixo Y):
2.1 - Subtrair a distância (sempre em pixels) do topo do sprite mais acima com o fundo do sprite mais abaixo;
2.2 - Somar a altura do sprite1 com a altura do sprite2;
2.3 - se a distância for menor ou igual à soma das alturas, a colisão foi confirmada.
No passo 1.3, vejam que há condição para continuar. Se uma colisão em uma das dimensões não tiver sido detectada, não há necessidade de testar na outra dimensão.
Colidir em uma dimensão parece coisa de doido, mas o que quero dizer é o seguinte:
Na figura acima, houve uma colisão no eixo Y, mas não no eixo X. Portanto, para um jogo 2D, não houve colisão. Veja que os dois quadrados ocupam as mesmas posições referentes a altura.
Já nesta figura acima, houve uma colisão no eixo X, mas não no eixo Y.
E aqui, finalmente ocorreu uma colisão nos dois eixos.
Segue o código abaixo.
Vocês devem ter visto que existe uma classe chamada Sprite. Esta classe é uma implementação minha para facilitar as coisas. Uma das facilidades é poder retornar o X/Y de cada um dos vértices do pictureBox, obtido através do Location e do Size. A implementação da classe Sprite segue abaixo:
Tags: C#, Colisão, Desenvolvimento, Jogos, Windows Forms, WinForms Lander
Categorias: Desenvolvimento | No Comments »