Staying alive
A battle is won by the vehicle left standing, or the healthier one when time runs out. Shooting well is half of it. This tutorial is the other half: the shield, dodging, and not getting stuck.
The shield, and what it costs
A shield generator absorbs part of every hit while it's up. shield.set_level(level) sets it from 0 (off) to 1 (full), and it stays where you set it. But it draws energy all the time it's up, and energy doesn't come back by itself: only a charging point gives it back. A shield left at full drains the tank, and a vehicle with an empty tank loses power altogether.
So raise it when it's needed, and only when there's energy to spare:
shield.set_level(0)
if contact and contact.range < 200 and state.energy > 30:
shield.set_level(0.5)Setting it to 0 first, then up when needed, means the last call wins: the shield is down unless something in this update raised it.
Seeing missiles coming
A missile warning sensor gives warning.threat(): the opponent's missile that will reach you soonest, if one is coming your way. Its heading is the way the missile is flying, and eta how many seconds until it arrives. See the threat record.
Two good answers to a missile:
- Get across its path. A missile flies in a straight line. Moving at right angles to its heading gets you out of the way; moving away along it doesn't.
- Take it on the shield. Just before it lands, raise the shield all the way.
threat = warning.threat()
if threat and threat.eta < 1 and state.energy > 30:
shield.set_level(1)
if threat and threat.eta > 0.2:
course = threat.heading + 90
# Whichever side is the smaller turn.
if abs(angle_diff(course, state.heading)) > 90:
course = threat.heading - 90With less than a fifth of a second to go there's no time to get clear, so it doesn't try: it braces instead.
Walls and obstacles
A vehicle against a wall can't dodge. Turn back towards the middle before you get there; state.arena_width and state.arena_height say how big the arena is. When something stops you, state.blocked is True: turn away until you're clear.
margin = 40
near_x = state.x < margin or state.x > state.arena_width - margin
near_y = state.y < margin or state.y > state.arena_height - margin
if near_x or near_y:
course = bearing_to(state.x, state.y, state.arena_width / 2, state.arena_height / 2)
if state.blocked:
course = state.heading + 90The whole program
The order matters: each part may change course, and the last one that does wins. So the most urgent (walls, then being stuck) come last.
from vehicle import drive, radar, missiles, shield, warning
def update(state, memory):
if memory.sweep == None:
memory.sweep = 0
course = state.heading
throttle = 0.5
shield.set_level(0)
contact = radar.contact()
if contact and state.time - contact.seen_at <= 0.2:
radar.scan(contact.bearing)
missiles.aim(contact.bearing)
course = contact.bearing + 35
throttle = 1
if contact.range < 200 and state.energy > 30:
shield.set_level(0.5)
on_target = abs(angle_diff(contact.bearing, missiles.turret())) <= 3
if on_target and contact.range < 170 and missiles.ready():
missiles.fire()
else:
memory.sweep = wrap(memory.sweep + 15)
radar.scan(memory.sweep)
# A missile coming: brace if it's about to land, else get across its path.
threat = warning.threat()
if threat and threat.eta < 1 and state.energy > 30:
shield.set_level(1)
if threat and threat.eta > 0.2:
course = threat.heading + 90
if abs(angle_diff(course, state.heading)) > 90:
course = threat.heading - 90
throttle = 1
# Off the walls, and out of anything that has stopped us.
margin = 40
near_x = state.x < margin or state.x > state.arena_width - margin
near_y = state.y < margin or state.y > state.arena_height - margin
if near_x or near_y:
course = bearing_to(state.x, state.y, state.arena_width / 2, state.arena_height / 2)
if state.blocked:
course = state.heading + 90
turn = clamp(angle_diff(course, state.heading) / 45, -1, 1)
drive.set(throttle=throttle, turn=turn)Going further
- Obstacles stop missiles as well as vehicles. Keeping one between you and the opponent is cover: the Taking cover example shows how to find an obstacle with the radar and get behind it.
- Heat matters too: firing and shielding warm the vehicle, and an overheated one locks out until it cools.
state.heatandstate.overheatedsay where it stands. - This program will still run out of energy in a long battle. The next tutorial fixes that.