Anatomia
Como um robô é montado
Um robô é um arquivo de texto com algumas instruções. Esta página explica cada pedaço desse arquivo, sem pressupor que você já saiba Python.
As duas linhas que todo robô tem
from robot import Robot
class MeuRobo(Robot):
...
A primeira linha diz: "pegue o robô básico que já vem pronto no jogo". Esse robô básico já sabe andar, girar, atirar e enxergar, então você não precisa ensinar nada disso.
A segunda linha diz: "o meu robô é uma versão personalizada daquele robô básico".
Aquele (Robot) entre parênteses é o que dá ao seu robô todos os comandos do
jogo. Sem ele, o seu arquivo é só um texto qualquer.
MeuRobo é o nome que vai aparecer em cima do tanque na arena. Troque pelo
nome do seu time.
Em Python, os espaços no começo da linha têm significado. Tudo que
pertence ao seu robô fica deslocado quatro espaços para a direita, e tudo que pertence
a um comando específico fica deslocado mais quatro. O PyCharm faz isso sozinho quando
você aperta Enter depois de uma linha terminada em dois-pontos. Se aparecer o erro
IndentationError, é sinal de que uma linha ficou fora do lugar.
O ciclo de vida: quem chama o quê
Você nunca "roda" o seu robô diretamente. Quem manda é o jogo: ele chama certos comandos do seu robô em certos momentos. Seu trabalho é preencher esses comandos.
O detalhe que mais confunde
Comandos como move(100) não acontecem na hora: eles entram numa
fila. O jogo executa essa fila devagar, um pedacinho por quadro. Só
quando a fila termina é que o run() é chamado de novo, do começo.
Consequência prática: nunca coloque um while True: dentro do
run(). O run() já é o laço do robô: quem repete é
o jogo. Um laço infinito ali dentro congela a partida.
O stop(): fazendo uma coisa depois da outra
Os comandos que você enfileira acontecem ao mesmo tempo, a não ser que
você separe. O stop() é o separador.
Sem stop() no meio
self.move(100)
self.turn(90)
self.stop()
Anda e gira simultaneamente: o robô faz uma curva.
Com stop() no meio
self.move(100)
self.stop()
self.turn(90)
self.stop()
Anda em linha reta, para, e só então gira no lugar.
Isso vale para qualquer combinação: andar enquanto gira o radar, virar o corpo enquanto a arma aponta para outro lado, e assim por diante.
Os 11 comandos obrigatórios
O jogo espera encontrar estes onze comandos no seu robô. Eles podem estar vazios, mas precisam existir.
| Comando | Quando o jogo chama |
|---|---|
init(self) | Uma vez, quando o robô entra na arena. É onde se definem cores e ajustes iniciais. |
run(self) | Toda vez que a fila de comandos esvazia. É o cérebro do robô. |
sensors(self) | A cada quadro. Serve para observar a arena. |
onHitWall(self) | Quando o robô bate numa parede. |
onRobotHit(self, ...) | Quando o seu robô trombou em outro. |
onHitByRobot(self, ...) | Quando outro robô trombou no seu. |
onHitByBullet(self, ...) | Quando o robô leva um tiro. |
onBulletHit(self, ...) | Quando um tiro seu acerta alguém. |
onBulletMiss(self, ...) | Quando um tiro seu sai da arena sem acertar. |
onTargetSpotted(self, ...) | Quando o radar enxerga um inimigo. |
onRobotDeath(self) | Quando a vida do robô chega a zero. |
A página de eventos explica cada um em detalhe, com as informações que o jogo entrega junto.
Quando o jogo precisa avisar o seu robô de alguma coisa e o comando correspondente não existe (ou existe mas dá erro), o programa inteiro é encerrado no meio da partida, para todo mundo. Por isso todo robô deste site começa com os onze comandos escritos, mesmo os vazios.
Como deixar um comando vazio
Em Python não existe comando vazio de verdade: é preciso escrever pass, que
significa "não faça nada aqui".
def onBulletMiss(self, bulletId):
pass
O self que aparece em todo comando é o jeito do robô se referir a si mesmo.
É por isso que os comandos são sempre escritos como self.move(100): leia
como "eu, ande 100".
O robô mínimo, completo
Este é o menor robô válido do jogo. Ele não faz nada além de escolher as cores, mas entra na arena sem quebrar nada e é o ponto de partida certo.
from robot import Robot
class RoboMinimo(Robot):
def init(self):
"""Roda uma unica vez, quando o robo entra na arena."""
# Cores em RGB: (vermelho, verde, azul), de 0 a 255
self.setColor(66, 185, 193) # o corpo do tanque
self.setGunColor(255, 255, 255) # o cano da arma
self.setRadarColor(255, 204, 77) # o radar
self.setBulletsColor(66, 185, 193) # os tiros
# Deixa o campo de visao do radar visivel. Otimo para entender
# o que o robo enxerga enquanto voce testa.
self.radarVisible(True)
def run(self):
"""O cerebro do robo. Escreva aqui o que ele deve fazer."""
pass
def sensors(self):
"""Roda a cada quadro. Use para observar a arena."""
pass
def onHitWall(self):
"""Bati numa parede."""
pass
def onRobotHit(self, robotId, robotName):
"""EU bati em outro robo."""
pass
def onHitByRobot(self, robotId, robotName):
"""OUTRO robo bateu em mim."""
pass
def onHitByBullet(self, bulletBotId, bulletBotName, bulletPower):
"""Levei um tiro."""
pass
def onBulletHit(self, botId, bulletId):
"""Meu tiro acertou alguem."""
pass
def onBulletMiss(self, bulletId):
"""Meu tiro saiu da arena sem acertar ninguem."""
pass
def onTargetSpotted(self, botId, botName, botPos):
"""Meu radar viu um inimigo."""
pass
def onRobotDeath(self):
"""Minha vida chegou a zero."""
pass
As frases entre """ são comentários de documentação: o jogo ignora,
servem só para você lembrar do que se trata. As linhas que começam com #
também são ignoradas.
O próximo passo
Com o esqueleto no lugar, comece a preencher. A ordem que costuma funcionar melhor é:
- Fazer ele andar. Coloque um
self.move(80)norun()e veja o que acontece. - Fazer ele não bater na parede. Preencha o
onHitWall(). - Fazer ele enxergar. Gire o radar no
run(). - Fazer ele atirar. Coloque um
self.fire(3)noonTargetSpotted(). - Fazer ele mirar direito. Aí sim entram as contas, e o RoboCacador mostra como.