Implementing smooth motion in 2d space in Pygame

让人想犯罪 __ 提交于 2021-02-05 07:26:26

问题


I want to implement smooth motion that accelerates up to max speed and then decelerates slowly if no keys are pressed, similar to the motion of the space ship in asteroid. Here is my current code for the movement:

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
y_change = 0
accel_x = 0
accel_y = 0
max_speed = 6

sign = lambda a: (a > 0) - (a < 0)

crashed = False
while not crashed:
    keys = pygame.key.get_pressed()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True
        if event.type == pygame.KEYDOWN:
            # Set the acceleration value.
            if event.key == pygame.K_LEFT:
                print('left')
                accel_x = -.2
            if event.key == pygame.K_RIGHT:
                print('right')
                accel_x = .2
            if event.key == pygame.K_DOWN:
                print('down')
                accel_y = .2
            if event.key == pygame.K_UP:
                print('up')
                accel_y = -.2
        if event.type == pygame.KEYUP:
            if event.key in (pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN):
                print('key up')
                accel_x = 0
                accel_y = 0

    x_change += accel_x  # Accelerate.
    y_change += accel_y

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

    if abs(y_change) >= max_speed:  # If max_speed is exceeded.
        # Normalize the y_change and multiply it with the max_speed.
        y_change = sign(y_change) * max_speed

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

    if accel_y == 0:
        y_change *= 0.98

    x += x_change  # Move the object.
    y += y_change

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

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

When pressing the arrow keys individually the motion works perfectly, however if pressing 2 keys in rapid succession, the second key is registered but there is no motion from the object. I've tried making a list of keys using pygame.key.get_pressed() and comparing the current motion with the key pressed in the list, however this didn't solve the problem.


回答1:


The major issue in your code is, that when you press and LEFT, then press and hold RIGHT and finally release LEFT, the resulting states of accel_x and accel_y are both 0, because the last event that happend was pygame.KEYUP.

I recommend to evaluate the states of pygame.key.get_pressed() rather than to use the key events:

  • If UP is pressed and DOWN is not pressed, the increment y_change up to its maximum (y_change = max(y_change-0.2, -max_speed)).
  • If UP is not pressed and DOWN is pressed, the decrement y_change down to its minimum (y_change = min(y_change+0.2, max_speed)).
  • If both keys are pressed simultaneously or no one of them is pressed, then decrease the speed (y_change *= 0.98).

Apply the same principle to x_change, when the keys LEFT and/or RIGHT are pressed:

crashed = False
while not crashed:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            crashed = True

    keys = pygame.key.get_pressed()

    # handle left and right movement
    if keys[pygame.K_LEFT] and not keys[pygame.K_RIGHT]:
        x_change = max(x_change-0.2, -max_speed)
    elif keys[pygame.K_RIGHT] and not keys[pygame.K_LEFT]:
        x_change = min(x_change+0.2, max_speed)
    else:
        x_change *= 0.98

    # handle up and down movement
    if keys[pygame.K_UP] and not keys[pygame.K_DOWN]:
        y_change = max(y_change-0.2, -max_speed)
    elif keys[pygame.K_DOWN] and not keys[pygame.K_UP]:
        y_change = min(y_change+0.2, max_speed)
    else:
        y_change *= 0.98

    x += x_change  # Move the object.
    y += y_change

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

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


来源:https://stackoverflow.com/questions/59104823/implementing-smooth-motion-in-2d-space-in-pygame

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!