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.

Commit: Ship now reads controls, moves, then reads firing controls.

OK, now I feel all righteous. And the noise, it’s terrible. Air guns hammering right over my head. I’d go out on the deck but then they might drop things on me.

This is all I can stands, and I can’t stands no more.

Instant Summary

I found a quick fix, change the offset. A better fix, move then update. An even better one, update controls, move, then check for firing. Satisfactory.

See you next time with a new roof!