A arena
Obstáculos e terreno
A arena quase nunca é um retângulo vazio. Ela tem blocos de concreto no meio, e eles param o seu robô, engolem os seus tiros e escondem os inimigos. Esta é a página que mais muda o resultado da sua partida.
Quando o robô bate num obstáculo,
o jogo não chama onHitWall. Ele chama um evento diferente, onHitObstacle. Um
robô que só trata parede fica trombando no mesmo bloco, perdendo 1
de vida por vez, até morrer sozinho, sem nenhum adversário ter
atirado nele. O jeito de evitar isso está em
Como tratar a batida no obstáculo.
O que é um obstáculo
É um retângulo cinza fixo dentro da arena. Diferente das paredes da borda, ele fica no meio do caminho. E ele bloqueia três coisas ao mesmo tempo:
Bloqueia o robô
Bater nele custa 1 de vida, empurra o robô para
fora e joga a fila de comandos no lixo. É o mesmo prejuízo de
bater na parede, mas dispara onHitObstacle em vez de
onHitWall.
Bloqueia a bala
O tiro que encosta no bloco é absorvido e some. A energia gasta no
disparo foi perdida, e
onBulletMiss não é chamado: para
quem não trata o evento novo, a bala simplesmente desaparece em
silêncio.
Bloqueia o radar
Se existe um bloco entre você e o adversário, o radar
não enxerga ele, mesmo com o cone apontado bem na
direção certa. O onTargetSpotted nem chega a ser
chamado.
O mapa muda a cada partida
Existem 16 mapas diferentes, e o jogo sorteia um a cada partida. Nas 5 partidas do duelo o sorteio se repete do zero toda vez, então não conte com o mapa da partida anterior.
Não dá para decorar o mapa. Nenhum comando permite
perguntar onde estão os blocos. O seu robô descobre o terreno do
jeito difícil: batendo nele (onHitObstacle) ou vendo o
tiro sumir (onBulletHitObstacle). Escreva um robô que
reage ao que encontra, não um que decora um caminho.
| Mapa | Blocos | Como ele é |
|---|---|---|
open_field |
0 | Campo aberto, sem nenhum bloco. O único assim. |
twin_towers |
2 | Duas torres compridas que criam três corredores |
classic |
3 | Uma barreira central mais dois blocos nas diagonais |
corridors |
3 | Dois paredões verticais e uma cobertura no meio |
zigzag |
3 | Barreiras alternadas que obrigam a mudar de direção |
crossroads |
4 | Quatro portões apontando para o centro |
four_pillars |
4 | Quatro pilares, um em cada quadrante |
fortress |
4 | Uma fortaleza fechada no meio da arena |
split_gate |
4 | Centro aberto, mas as rotas de cima e de baixo divididas |
sniper_lanes |
4 | Faixas compridas alternando entre os dois lados |
open_wings |
4 | Quatro coberturas apontando para uma área central livre |
islands |
5 | Cinco ilhas pequenas com muita linha de visão entre elas |
diamond_cover |
5 | Cinco blocos formando um losango |
spiral |
5 | Uma espiral que leva protegido até o centro |
three_bridges |
5 | Pontes horizontais com vãos e pontos de emboscada |
side_bunkers |
6 | Dois bunkers laterais, o mais cheio de todos |
Como tratar a batida no obstáculo
O evento entrega duas informações: qual bloco você acertou e de que lado dele você está.
def onHitObstacle(self, obstacleId, side):
"""Bati num bloco do meio da arena."""
self.reset() # joga fora o plano que me trouxe ate aqui
self.move(-60) # da re
self.turn(90) # e sai da linha do bloco
O reset() é a parte que importa. Sem ele, o robô volta a
executar exatamente o plano que o levou até o bloco.
O que é o side
É um texto dizendo de que lado do bloco o seu robô está. Repare que ele descreve a sua posição, não a face do bloco que você acertou.
"top" é o robô mais
próximo do topo da tela.
Em situações raras, quando o jogo não consegue decidir o lado, o valor
vem como
"unknown". Trate esse caso junto com os outros e o seu
robô não quebra.
Qual bloco foi
O obstacleId é um nome de texto, diferente para cada
bloco do mapa: "central", "north_gate",
"west_tower", "spiral_core" e assim por
diante. Como os nomes mudam de mapa para mapa, não vale a pena
escrever regras para um nome específico. O uso esperto é outro:
guardar os nomes que você já encontrou para perceber que está batendo
sempre no mesmo bloco.
Quando o radar não enxerga
O jogo traça uma linha reta entre o centro do seu robô e o centro do
adversário. Se essa linha cruza um bloco, o avistamento é cancelado: o
onTargetSpotted não acontece.
Isso significa que silêncio no radar não quer dizer arena vazia. Pode haver alguém a vinte pixels de você, atrás de um bloco. Se o seu robô ficou muito tempo sem avistar ninguém, provavelmente ele precisa mudar de posição, não de direção do radar.
def init(self):
self.silencio = 0
# ... resto da configuracao
def run(self):
self.silencio = self.silencio + 1
if self.silencio > 20:
# Faz tempo que nao vejo ninguem. Talvez tenha um bloco na frente.
self.silencio = 0
self.move(120) # muda de lugar em vez de so girar o radar
self.stop()
def onTargetSpotted(self, botId, botName, botPos):
self.silencio = 0
self.fire(3)
Quando o tiro some
Uma bala que encosta no bloco é destruída na hora. Você já pagou a
energia do disparo e não vai receber nada de volta. E, como o
onBulletMiss não é chamado nesse caso, um robô desatento
continua atirando na mesma direção, alimentando o bloco.
def onBulletHitObstacle(self, bulletId, obstacleId):
"""Meu tiro bateu num bloco. Tem concreto na minha linha de tiro."""
self.rPrint("Tem um bloco na frente: " + str(obstacleId))
self.reset()
self.move(80) # anda de lado antes de tentar de novo
self.turn(30)
O bloco que engole o seu tiro engole o do adversário também. Um robô que percebe isso deixa de ser vítima do terreno e passa a usá-lo: manter concreto entre você e quem está atirando é a defesa mais barata do jogo, porque não custa vida nenhuma.
Um robô que lida com tudo isso
O RoboSombra, no kit, é o exemplo completo: ele guarda onde bateu para não voltar, se desloca quando o tiro é absorvido, e percebe quando o radar ficou tempo demais em silêncio. Copie e ajuste.