Python Asteroids on GitHub

A toot from Jani led me to see the defect allowing ships to shoot themselves down. The question is what to do about it.

Jani Poikela has sent me a few toots about the ability of the ship to overrun its own missiles at high speed. I think that if you actually accelerate into them, too bad for you. But it turns out that if you are near light speed and fire, you’ll unconditionally hit your own missile. That’s not good. What “should” happen is that you’d stay right behind it.

In thinking about Jani’s notes, I realized this: The ship moves after firing, because the ship `update` is this:

``````    def update(self, delta_time, fleets):
self.control_motion(delta_time, fleets)
self._location.move(delta_time)
``````

Since the missile is rezzed just a bit outside our radius (11 points, to be exact), if our velocity exceeds 11 points per tick, we’ll move on top of our own missile. This is not good.

What we should do, presumably, is move and then fire. I think that reversing the order of those two should eliminate the problem. I’ll try it. Some in-game testing tells me that it does eliminate the problem. The “cost” is just that the controls on the ship take effect one tick later than they used to. I don’t think anyone will notice.

Commit: ship moves before applying controls. Eliminates shooting self down at high speed.

I think that fix is righteous enough. Perhaps the ideal would be do controls, move, then fire if possible, but this will do.

No. Let’s do it right. Right is always better. Extract from this:

``````class Ship(Flyer):
def control_motion(self, delta_time, fleets):
if not pygame.get_init():
return
keys = pygame.key.get_pressed()
if keys[pygame.K_f]:
self.turn_left(delta_time)
if keys[pygame.K_d]:
self.turn_right(delta_time)
if keys[pygame.K_j]:
self.power_on(delta_time)
else:
self.power_off()
if keys[pygame.K_k]:
self.fire_if_possible(fleets)
else:
self._can_fire = True
if keys[pygame.K_SPACE]:
self._hyperspace_generator.press_button(self._asteroid_tally, fleets)
else:
self._hyperspace_generator.lift_button()
``````
``````    def control_motion(self, delta_time, fleets):
if not pygame.get_init():
return
keys = pygame.key.get_pressed()
if keys[pygame.K_f]:
self.turn_left(delta_time)
if keys[pygame.K_d]:
self.turn_right(delta_time)
if keys[pygame.K_j]:
self.power_on(delta_time)
else:
self.power_off()
self.control_firing(fleets)
if keys[pygame.K_SPACE]:
self._hyperspace_generator.press_button(self._asteroid_tally, fleets)
else:
self._hyperspace_generator.lift_button()

def control_firing(self, fleets):
if not pygame.get_init():
return
if pygame.key.get_pressed()[pygame.K_k]:
self.fire_if_possible(fleets)
else:
self._can_fire = True
``````

The noise here is terrible, they are replacing all the plywood on the roof.

Now we extract the call from `control_motion` and put it into. `update`, putting calls in the right order. That works a treat. I also managed to shoot myself down by moving rapidly, turning around, then firing while decelerating, allowing the missile to catch up with me.