Polybrow
Polybrow

Reputation: 55

Pygame - Movement Acceleration

I want to make a script in python/pygame that will make a character speed up as you hold a movement button (so, when I hold the left key, the character will accelerate to a specific speed and then the speed will even out, when I release the key it will slowly decrease in speed until stopping fully.)

at the moment, my code will recognize that the character must speed up, however the changes in speed only occur every time I press down and release the key (e.g: first key press will have the speed at 1, second press will be two, all the way up to the fifth or sixth press where it's at max speed, before resetting.)

I want to write my code so it means the character will accelerate whilst the key is being held down and not require multiple presses.

here is the movement section (with a few more random bits that were around it) of my code so far:

x = (display_width * 0.45)
y = display_height * 0.8
x_change = 0
negx = 0
posx = 0
bun_speed = 0

while not crashed:
        for event in pygame.event.get():
                if event.type == pygame.QUIT:
                        crashed = True
            if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_LEFT:
                        posx = 0
                        if negx != -5:
                            negx = negx - 1
                            x_change = negx
                        elif negx == -5:
                            negx = 0
                            x_change = -5
                    elif event.key == pygame.K_RIGHT:
                        negx = 0
                        if posx != 5:
                            posx = posx + 1
                            x_change = posx
                        elif posx == 5:
                            posx = 0
                            x_change = 5
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT:
                        x_change = 0
                elif event.key == pygame.K_RIGHT:
                        x_change = 0
    x += x_change

    display.fill(white)
    bunny(x,y)

    pygame.display.update()
    clock.tick(60)

the two variables negx and posx decrease and increase respectively depending on the key pressed. pressing the key assigned to one variable resets the other to zero, so when that variable is next called when the opposite button is pressed it will accelerate from zero. Once either variable reaches the max speed, it resets for when the button is released meaning the character can accelerate once more.

If there's any way to make this work (as well as neaten up the code, if you're able to) then guidance as to how to get it to function would be much appreciated.

Upvotes: 1

Views: 7135

Answers (3)

Luke Ingles
Luke Ingles

Reputation: 1

Kevin, what you have mentioned is a key point, but it is a very easy fix, you just need to replace decelerating code with something that checks whether the x_change is positive or negative and then adding or subtracting once you have figured it out.

For example his code is:

if accel_x == 0:
    x_change *= 0.92

replace this with something along the lines of:

if accel_x == 0:
    if x_change > 0:
        x_change -= 0.2
        if x_change < 0.2:
            x_change = 0
    elif x_change < 0:
        x_change += 0.2
        if x_change > -0.2:
            x_change = 0

Upvotes: 0

sudchau
sudchau

Reputation: 13

I found another way of accelerating the character. Instead of changing distance, change time. I defined a variable which goes inside pygame.time.delay() and the delay is something I change. This is better because the character does not look like glitching when moving from one place to another.

import pygame
pygame.init()

win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("ACCELERATE")

def main():

    k = True

    thita = 40
    x = 250
    y = 400

    while k:

        keys = pygame.key.get_pressed()

        for event in pygame.event.get():
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT:
                    thita = 40
                if event.key == pygame.K_RIGHT:
                    thita = 40
            if event.type == pygame.QUIT:
                k = False

        if keys[pygame.K_LEFT]:
            x -= 4
            pygame.time.delay(thita)
            if thita > 12:
                thita -= 1
        if keys[pygame.K_RIGHT]:
            x += 4
            pygame.time.delay(thita)
            if thita > 11:
                thita -= 1

        pygame.draw.rect(win, (255, 0, 0), (x, y, 10, 10))
        pygame.display.update()
        win.fill((0, 0, 0))

main()

You see the thita goes back to its original value as soon as we lift the key.

Upvotes: 0

skrx
skrx

Reputation: 20438

Define a variable for the acceleration (accel_x in the example), set it to the desired value in the event loop and add it to the x_change every frame to accelerate. To limit the x_change to the maximum speed, you have to normalize it and multiply it by the max_speed.

To decelerate the object, you can multiply x_change with a value below 1 when no key is pressed.

import pygame


pygame.init()
display = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
GRAY = pygame.Color('gray12')
display_width, display_height = display.get_size()
x = display_width * 0.45
y = display_height * 0.8
x_change = 0
accel_x = 0
max_speed = 6

crashed = False
while not crashed:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
                crashed = True
        elif event.type == pygame.KEYDOWN:
            # Set the acceleration value.
            if event.key == pygame.K_LEFT:
                accel_x = -.2
            elif event.key == pygame.K_RIGHT:
                accel_x = .2
        elif event.type == pygame.KEYUP:
            if event.key in (pygame.K_LEFT, pygame.K_RIGHT):
                accel_x = 0

    x_change += accel_x  # Accelerate.
    if abs(x_change) >= max_speed:  # If max_speed is exceeded.
        # Normalize the x_change and multiply it with the max_speed.
        x_change = x_change/abs(x_change) * max_speed

    # Decelerate if no key is pressed.
    if accel_x == 0:
        x_change *= 0.92

    x += x_change  # Move the object.

    display.fill(GRAY)
    pygame.draw.rect(display, (0, 120, 250), (x, y, 20, 40))

    pygame.display.update()
    clock.tick(60)

pygame.quit()

Upvotes: 3

Related Questions