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.

Leia isto antes de qualquer outra coisa

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.

A consequência para o seu código

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á.

o mínimo que resolve
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.

bloco "left" "right" "top" "bottom"
O valor descreve onde você está. Lembre que na arena o eixo vertical cresce para baixo, então "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.

percebendo o silêncio
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.

parando de atirar no concreto
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 outro lado da moeda

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.