str s sõs tr s
ss
r r rts
r r rts
str ór
tsrtsrts rts
s s tás
srtsrt
srtsrt
ã rs trr r ts s rtâs
r ss
Esta parte é muito importante, pois definimos uma nova interface que os
sprites deverão seguir para poderem participar do colisor. Essa interface é formada por dois métodos:
retangulosColisao: deve devolver um array com os dados de cada
retângulo;
colidiuCom(sprite): recebe a notificação de que o sprite colidiu
com outro (recebido como parâmetro)
Nós abstraímos mais um pouco, deixando para o final a função que veri-
fica se dois retângulos colidem. Considero uma excelente prática ir isolando as partes difíceis ou que não têm muito a ver com o algoritmo sendo criado: 94
Casa do Código
Capítulo 5. Detecção de colisões
rts trt rt
ór trsçã rtâs
rtr rt rtrr rt
rt rt rtrr
rt rttr rt
rt rt rttr
5.4
Criando um sprite colidível
Agora que temos nosso Colisor, vamos criar uma nova versão da classe
Bola seguindo a interface exigida por este, além da interface de animação já vista anteriormente:
t tt
tstt tt
ts
ts
ts
ts
tsr
tsr
rtt
tr çã
tr t
sr t
tr sã
rtss t
tsrt
95
5.4. Criando um sprite colidível
Casa do Código
Os métodos atualizar e
desenhar não mudaram em nada. O
método atualizar muda a posição da bola de acordo com suas veloci-
dades horizontal e vertical e inverte as velocidades quando ela está quicando no Canvas. O método desenhar usa a API do contexto 2d para desenhar a bola em sua posição, com a cor e o raio definidos. Em caso de dúvida, consulte a seção 2.4:
tr t
r t tstt
ts tsr ts
tst tsr
ts
ts tsr ts
tst tsr
ts
ts ts
ts ts
sr t
r t tstt
ts
tt tsr
tPt
trts ts tsr tP s
t
trstr
Para a bola, o método retangulosColisao, criará um único retân-
gulo que, mesmo assim, deve estar contido em um array. Só para lembrar,
em JavaScript, os colchetes delimitam arrays e as chaves delimitam objetos.
Temos, portanto, um objeto dentro de um array:
rtss t
rtr
96
Casa do Código
Capítulo 5. Detecção de colisões
ts tsr ts é tr
ts tsr ts
rr tsr
tr tsr
Como a posição (x,y) da bola define seu centro, descontamos o raio
para achar a posição do seu retângulo circundante, que na realidade é um
quadrado. O lado desse quadrado é igual ao dobro do raio da bola:
Figura 5.6: Retângulo circundante da bola
Falta agora o método colidiuCom. Por enquanto, vamos mostrar uma
mensagem de alerta:
tsrt
rtP
Faça o teste e veja se a mensagem aparece:
97
5.5. Melhorando o código
Casa do Código
Figura 5.7: Colisão detectada
No entanto, a mensagem aparece muitas vezes pelos seguintes motivos:
Estamos detectando colisões repetidas. Testamos A e vimos que colidiu
com B. Ao testar B, não precisamos colidi-lo com A novamente!
São duas bolinhas dando a mesma resposta à colisão, então tudo isso
ocorre em dobro!
Resultado: quatro PÁ! por colisão.
Fora o fato de as bolinhas continuarem seu trajeto normalmente,
fazendo com que passem uma dentro da outra e provoquem novas
colisões.
5.5
Melhorando o código
Resolvendo a detecção repetida
Do jeito que estamos programando, cada colisão é detectada duas vezes. Fizemos a seguinte sequência de ações:
Pegamos o primeiro sprite (vamos chamá-lo de A);
98
Casa do Código
Capítulo 5. Detecção de colisões
Fazemos um loop em todos os outros e testamos contra A;
Detectamos uma colisão com outro sprite (que chamaremos de B);
Enviamos uma mensagem para A e para B.
Mas o processo não para aí, chegou a vez de testar B!
Testamos B contra os outros;
Detectamos sua colisão com A (que já foi detectada anteriormente);
Enviamos as mensagens novamente para A e para B.
Para resolver o primeiro problema, vamos manter um registro de colisões
já testadas. Isto pode ser feito de diversas formas, mas queimando neurônios eu achei mais fácil usar um objeto associativo contendo arrays, onde eu asso-cio um sprite aos outros com quem ele já colidiu. Veja:
tór
r t
r sts t
ss srt rr trs
st q á tr t
r sts tr t
Infelizmente, os elementos de jaTestados não podem ser outros ob-
jetos. Nesse código, nave deve ser uma string, pois as propriedades de um objeto podem ser expressas por strings usando a sintaxe de [colchetes] (veja a seção 1.4).
Preste bastante atenção ao exemplo teórico a seguir. Se gerarmos uma
string única para cada sprite, podemos associar cada uma a um array den-
tro desse objeto associativo. Tendo as strings devidamente armazenadas no objeto, podemos verificar se a colisão já foi testada:
99
5.5. Melhorando o código
Casa do Código
tór
sts tst srts
rr s tçõs
r strsrt
r strsrt
rr s rrs s ã str
sts sts
sts sts
str sã s á ã tst
tstrt
str tst r tr rtçã
stss
stss
Para verificar se o teste atual não é repetido, podemos usar o método
indexOf dos arrays. Por exemplo, jaTestados[id1].indexOf(id2)
devolve a posição da string id2 dentro do array associado à id1 no objeto, ou o valor -1 caso ainda não exista:
tór rt
rr s á tst
sts
sts
q tsts sã
Vamos, finalmente, para a parte prática.
Primeiro, crie o método