método caso a colisão seja detectada, porém como diversas colisões podem ser de-
tectas, como nave com tiro ou tiro com meteoro, isso será decidido em tempo de
execução. É exatamente por isso que precisamos, por último, de um parâmetro a
mais, que recebe o nome do método a ser executado caso a colisão aconteça.
O que teremos então é uma verificação de cada elemento do primeiro array, com
cada elemento do segundo array. Caso a detecção aconteça, faremos um log por
enquanto, e mostraremos quais elementos tiveram a colisão.
Na GameScene.m teremos o código a seguir.
- (BOOL)checkRadiusHitsOfArray:(NSArray *)array1
againstArray:(NSArray *)array2
withSender:(id)sender
andCallbackMethod:(SEL)callbackMethod
{
BOOL result = NO;
for (int i = 0; i < [array1 count]; i++) {
// Pega objeto do primeiro array
CCSprite *obj1 = [array1 objectAtIndex:i];
CGRect rect1 = obj1.boundingBox;
for (int j = 0; j < [array2 count]; j++) {
// Pega objeto do segundo array
CCSprite *obj2 = [array2 objectAtIndex:j];
113
7.1. Detectando colisões
Casa do Código
CGRect rect2 = obj2.boundingBox;
// Verifica colisão
if (CGRectIntersectsRect(rect1, rect2)) {
NSLog(@"Colisão Detectada: %@",
NSStringFromSelector(callbackMethod));
result = YES;
// Se encontrou uma colisão, sai dos 2 loops
i = [array1 count] + 1;
j = [array2 count] + 1;
}
}
}
return result;
}
Tendo o método que identifica a colisão como fizemos, podemos utilizá-lo para
a verificação de dois arrays quaisquer. Faremos a chamada a ele para detectar coli-sões entre tiros e meteoros e entre meteoros e a nave. Esse método deve ser chamado de tempos em tempos pelo Cocos2D, portanto, utilizaremos mais uma vez o agendamento do framework, passando esse método para o schedule:.
Ainda na GameScene.m faremos essas chamadas.
- (void)checkHits:(float)dt
{
// Checa se houve colisão entre Meteoros e Tiros
[self checkRadiusHitsOfArray:self.meteorsArray
againstArray:self.shootsArray
withSender:self
andCallbackMethod:@selector(meteorHit:withShoot:)];
// Checa se
houve colisão entre Jogador(es) e Meteoros
[self checkRadiusHitsOfArray:self.playersArray
againstArray:self.meteorsArray
withSender:self
andCallbackMethod:@selector(playerHit:withMeteor:)];
}
Como citado anteriormente, agendaremos o método de checagem de colisões.
114
Casa do Código
Capítulo 7. Detectando colisões, pontuando e criando efeitos
Para isso, o método schedule: receberá o método checkHits: como parâmetro.
- (void)startGame
{
// Ao entrar na GameScene, inicia a checagem de colisões
// e inicia as Engines do jogo
[self schedule:@selector(checkHits:)];
[self startEngines];
}
Rode o jogo e repare no console do Xcode. A colisão já está sendo detectada, e
portanto, podemos partir para a atualização do placar e criação dos efeitos necessá-
rios!
7.2
Efeitos
No momento que detectamos que dois objetos do jogo colidiram, algumas coisas
devem ser feitas. Vamos listar para facilitar o fluxo a seguir.
Executar uma animação, como explosão ou similar
Remover os elementos dos arrays
Atualizar o placar ou mostrar tela de game over
Vamos começar pela animação. Existem diversas possibilidades de animação
utilizando o Cocos2D. O framework oferece alguns efeitos tradicionais como fade e scale. A ideia é configurar uma série de ações, que juntas e em um espaço curto de tempo, criam uma animação.
Para o primeiro exemplo, vamos animar o meteoro quando é atingido pelo tiro.
Nesse momento, animaremos o meteoro para que fique pequeno, dando a impressão
que sumiu por ser atingido.
O que faremos abaixo é:
Reduzir a escala de tamanho da imagem
Retirar da tela com um efeito leve, chamado fade out
Rodar ambas em sequência
115
7.2. Efeitos
Casa do Código
Após rodar a sequência de animações, precisamos retirar o meteoro do array
e da memória, pois ele não existe mais. Precisamos também parar o agendamento
desse objeto, que roda de tempos em tempos atualizando sua posição e gerando o
movimento.
Teremos um novo método na Meteor, que será invocado quando houver a co-
lisão. Defina-o na Meteor.h:
- (void)gotShot;
Agora implemente o método na Meteor.m:
- (void)gotShot
{
// Para o agendamento
[self unscheduleUpdate];
// Cria efeitos
float dt = 0.2f;
CCScaleBy *a1 = [CCScaleBy actionWithDuration:dt scale:0.5f];
CCFadeOut *a2 = [CCFadeOut actionWithDuration:dt];
CCSpawn *s1 = [CCSpawn actionWithArray:
[NSArray arrayWithObjects:a1, a2, nil]];
// Método a ser executado após efeito
CCCallFunc *c1 = [CCCallFunc actionWithTarget:self
selector:@selector(removeMe:)];
// Executa efeito
[self runAction:[CCSequence actionWithArray:
[NSArray arrayWithObjects:s1, c1, nil]]];
}
No método acima cancelamos o agendamento da atualização de posição e cria-
mos as ações que juntas farão o efeito de sumir do meteoro.
O Cocos2D possui ainda um método que pode ser invocado para que o objeto
seja liberado da memória. Esse método é o removeFromParentAndCleanup: e
será invocado logo após a animação acabar. Fazemos isso via CCCallFunc, pois