Search code examples
pythonpygamegame-physics

How to stop player accelerating when it shouldn't be


In the main game loop, a movement key press changes the player state:

for event in pygame.event.get():
    elif event.type == KEYDOWN:
        if event.key == K_w:
            player.state = "moving_up"
    elif event.type == KEYUP:
        if event.key == K_w:
            player.state = "stopping_up"

When the player update method is called, it moves according to the state:

def update(self):
    if self.state == "idle":
        self.displacement = self.displacement
    else:            
        if self.state == "moving_up":
            self.displacement[1] = self.displacement[1] - self.speed
        if self.state == "stopping_up":
            s = self.rect.top % 32
            self.displacement[1] = self.displacement[1] - s
            self.state = "idle"
        new_position = self.rect.move(self.displacement)
        self.rect = new_position

When I move the player, the speed seems to be accelerating after each consequent press of the key. e.g. the first time i move the speed is fine, but the next time it is even faster than before and it just snowballs...

Here is a print out of the (speed), (displacement) when moving right:

idle
0.02 [0.7200000000000003, 0]
0.02 [0.7400000000000003, 0]
0.02 [0.7600000000000003, 0]

...

0.02 [1.2400000000000007, 0]
0.02 [1.2600000000000007, 0]
0.02 [19.26, 0]
idle

You can see that on the last movement the displacement increases greatly.

Any idea why this is happening?


update, here is another print out with s:

0.02 [1.1600000000000006, 0]
0.02 [1.1800000000000006, 0]
0.02 [1.2000000000000006, 0]
0.02 [1.2200000000000006, 0]
0.02 [1.2400000000000007, 0]
0.02 [1.2600000000000007, 0]
s: remainder to next tile 18
0.02 [19.2600000000000007, 0]

It looks like s is causing the jump in displacement.

This was intentional as it was supposed to find the distance to the next tile and make the player move there. (tiles are 32x32) and s was the remainder until the next one.

Seems like I need to revise the movement code as it's not resulting in what I expected.


Solution

  • The obvious thing here is that the final value is using s rather than self.speed.

    As a side note:
    In general, in doing physical simulations, it's best to use physical units. By this I mean, think of time in seconds, not loop passes, etc, and work from this. If you want to increment a distance using a speed, do this as dist += dt*speed, not dist += speed. Usually this involves and extra multiplication, but it's well worth it. Otherwise, you're effectively using time units so that dt=1., which is possible, but trickier than it seems at first.

    Here, for example, you're adding self.displacement[1] - self.speed, and in the next line you do self.displacement[1] = self.displacement[1] - s, where s seems to be a distance. Although in numbers these two things look similar, physically they are very different. It's not surprising there was a bug here because the whole thing is hard to understand.