Continuous movement of a box in pygame

2019-02-27 10:28发布

问题:

I have written the following code that creates a simple game where when you click an arrow on the keyboard a box moves a unit over in the game.

I am trying to make it so that if i push any of the arrow buttons the box will continue to move in that direction until another arrow is pushed. So if i push the right arrow once instead of scooting +50 pixels it will move continuously across the screen untill a different arrow is clicked and then it will go that way

import pygame #importing the pygame library

# some initializations
pygame.init()  # this line initializes pygame
window = pygame.display.set_mode( (800,600) ) # Create a window with   width=800 and height=600
pygame.display.set_caption( 'Rectangle move' ) # Change the window's name we create to "Rectangle move"
clock = pygame.time.Clock() # Clocks are used to track and control the frame-rate of a game (how fast and how slow the pace of the game)
                        # This line creates and initializes a clock.

# color definitions, using RBG color model.
black = (0,0,0)
white = (255,255,255)

# initial center position for the square (bob)
x,y = 0,0
lastKey=0
game_loop=True
while game_loop:
    for event in pygame.event.get():   # loop through all events
        if event.type == pygame.QUIT:
            game_loop = False # change the game_loop boolean to False to quit.
        if event.type == pygame.KEYDOWN: 
            lastKey = event.key
    #check last entered key
    #lastKey equals "LEFT", "RIGHT", "UP", "DOWN" --> do the required stuff!
    #set x coordinate minus 50 if left was pressed
    if lastKey == pygame.K_LEFT:
         x -= 50
    if lastKey == pygame.K_RIGHT:
         x += 50
    if lastKey == pygame.K_UP:
         y += 50
    if lastKey == pygame.K_DOWN:
         y -= 50
    if event.key == pygame.K_LEFT:
          x -= 50
    if event.key == pygame.K_RIGHT:
          x += 50
    if event.key == pygame.K_UP:
          y += 50
    if event.key == pygame.K_DOWN:
          y -= 50
 # draw and update screen
 window.fill( black ) # fill the screen with black overwriting even bob.
 pygame.draw.rect( window, white, (x, y, 50, 50) ) # draw bob on the screen with new coordinates after its movement.
                                                      # the parameters are as follows: window: is the window object you want to draw on. white: the object color used to fill the rectangle
                                                      # (x,y,50,50) x is the x position of the left side of the rectangle. y is the y position of the upper side of the rectangle. 
                                                      # In other words (x,y) is the coordinate of the top left point of the rectangle.
                                                      # 50 is the width, and 50 is the height
 pygame.display.update() #updates the screen with the new drawing of the rectangle.

#fps stuff:
 clock.tick(10) # this controls the speed of the game. low values makes the game slower, and large values makes the game faster.

 pygame.quit()

any help would be much appreciated.

回答1:

You want to change the state of your application when you press a key. So you need a variable to keep track of that state (the state is: What direction should the box move?).

Here's a complete, minimal example that does what you're looking for. Note the comments.

import pygame, sys

pygame.init()
screen = pygame.display.set_mode((640, 480))
screen_r = screen.get_rect()
clock = pygame.time.Clock()
rect = pygame.rect.Rect(0, 0, 50, 50)

# let's start at the center of the screen
rect.center = screen_r.center

# a dict to map keys to a direction
movement = {pygame.K_UP:    ( 0, -1),
            pygame.K_DOWN:  ( 0,  1),
            pygame.K_LEFT:  (-1,  0), 
            pygame.K_RIGHT: ( 1,  0)}

move = (0, 0)

# a simple helper function to apply some "speed" to your movement
def mul10(x):
    return x * 10

while True:
    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            sys.exit()
        # try getting a direction from our dict
        # if the key is not found, we don't change 'move'
        if e.type == pygame.KEYDOWN:
            move = movement.get(e.key, move)

    # move the rect by using the 'move_ip' function
    # but first, we multiply each value in 'move' with 10
    rect.move_ip(map(mul10, move))

    # ensure that 'rect' is always inside the screen
    rect.clamp_ip(screen_r)
    screen.fill(pygame.color.Color('Black'))
    pygame.draw.rect(screen, pygame.color.Color('White'), rect)
    pygame.display.update()
    clock.tick(60)

I use a Rect instead of keeping track of two coordinates x and y, since that allows to make use of the move_ip and clamp_ip functions to easily move the rect inside the screen.



回答2:

Try to save the entered key into a variable and check it after your Event-Loop. Like this:

#...
lastKey = None
while game_loop:
    for event in pygame.event.get():   # loop through all events
        if event.type == pygame.QUIT:
            game_loop = False # change the game_loop boolean to False to quit.
        if event.type == pygame.KEYDOWN: 
            lastKey = event.key
    #check last entered key
    #lastKey equals "LEFT", "RIGHT", "UP", "DOWN" --> do the required stuff!
    #set x coordinate minus 50 if left was pressed
    if lastKey == pygame.K_LEFT
         x -= 50
    #<add the other statements here>
    #(...)

I would recommend to not use that many if-statements. It could get a bit confusing after some time. Check the following question out to keep your code brief:

Replacements for switch statement in Python?



回答3:

Here are two versions, the first demonstrates how to utilize an event loop to get continuous movement (similar to Sloth's solution, but a bit simpler for beginners who don't know dictionaries yet), the second one shows how to achieve this with pygame.key.get_pressed().

Solution 1: Check which key was pressed in the event loop and change the x and y velocities to the desired values. Then add the velocities to the rect.x and rect.y positions in the while loop.

I'd actually recommend using vectors instead of the velocity_x and velocity_y variables and another one for the actual position of your sprite. pygame.Rects can't have floats as their coordinates and so a vector or separate variables for the position would be more accurate.

import pygame as pg


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    rect = pg.Rect(100, 200, 40, 60)
    velocity_x = 0
    velocity_y = 0
    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_d:
                    velocity_x = 4
                elif event.key == pg.K_a:
                    velocity_x = -4
            elif event.type == pg.KEYUP:
                if event.key == pg.K_d and velocity_x > 0:
                    velocity_x = 0
                elif event.key == pg.K_a and velocity_x < 0:
                    velocity_x = 0

        rect.x += velocity_x
        rect.y += velocity_y

        screen.fill((40, 40, 40))
        pg.draw.rect(screen, (150, 200, 20), rect)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()

Solution 2: Call pygame.key.get_pressed to check which key is currently being held down. Check if the left, right, up or down keys are held and then adjust the position of the sprite each frame.

pygame.key.get_pressed has the disadvantage that you can't know the order of the key presses, but the code looks a bit simpler.

import pygame as pg


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    rect = pg.Rect(100, 200, 40, 60)
    velocity = (0, 0)
    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True

        keys = pg.key.get_pressed()
        if keys[pg.K_d]:
            rect.x += 4
        if keys[pg.K_a]:
            rect.x -= 4

        screen.fill((40, 40, 40))
        pg.draw.rect(screen, (150, 200, 20), rect)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()


标签: python pygame