Pygame - 运动加速

时间:2018-04-10 11:17:54

标签: python pygame

我想在python / pygame中创建一个脚本,当你按住一个移动按钮时,它会使角色加速(因此,当我按住左键时,角色会加速到特定的速度,然后速度会均匀当我松开钥匙时,它会慢慢减速直到完全停止。)

此刻,我的代码会识别出角色必须加速,但速度的变化只会在每次按下并释放按键时发生(例如:第一次按键的速度为1,第二次按下将在重置之前,一直到第五或第六次按下最大速度。)

我想编写我的代码,这意味着当按键被按下而不需要多次按下时,角色会加速。

这是我的代码到目前为止的移动部分(周围有几个随机位):

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)

两个变量negx和posx分别根据按下的键减小和增加。按下分配给一个变量的键会将另一个键重置为零,因此当按下相反按钮时接下来调用该变量时,它将从零加速。一旦任一变量达到最大速度,它将在按钮释放时重置,这意味着角色可以再次加速。

如果有任何方法可以使这项工作(以及如果你能够完成代码的话),那么我们将非常感谢您对如何使其发挥作用的指导。

4 个答案:

答案 0 :(得分:1)

为加速度定义变量(示例中为accel_x),将其设置为事件循环中的所需值,并将其添加到每帧的x_change以加速。要将x_change限制为最高速度,您必须对其进行标准化并将其乘以max_speed

要减速对象,当没有按下任何键时,可以将x_change乘以低于1的值。

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()

答案 1 :(得分:0)

我发现了加速角色的另一种方法。不用改变距离,而要改变时间。我定义了一个在pygame.time.delay()中的变量,延迟是我改变的。这样做会更好,因为从一个地方移到另一个地方时,角色看起来不会出现毛刺。

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()

您看到提起钥匙后,thita便恢复到其原始值。

答案 2 :(得分:0)

我试图结合srkx的方法进行加速。当我使用右键向右移动时,我会加速到最大速度。当我释放它时,我确实减速停止。但是,当使用向左键向左移动并释放它之后,我继续以固定速度移动,然后过了一会儿突然停止。知道我的代码有什么问题吗?非常感谢你!

原始代码来自http://programarcadegames.com/python_examples/show_file.php?file=platform_jumper.py

import pygame

# Global constants

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)

# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600


class Player(pygame.sprite.Sprite):
    """ This class represents the bar at the bottom that the player
        controls. """

    # -- Methods
    def __init__(self):
        """ Constructor function """

        # Call the parent's constructor
        super().__init__()

        # Create an image of the block, and fill it with a color.
        # This could also be an image loaded from the disk.
        width = 40
        height = 60
        self.image = pygame.Surface([width, height])
        self.image.fill(RED)

        # Set a referance to the image rect.
        self.rect = self.image.get_rect()

        # Set speed vector of player
        self.xVel = 0
        self.yVel = 0

        # List of sprites we can bump against
        self.level = None

    def update(self):
        """ Move the player. """
        # Gravity
        self.calc_grav()

        # Move left/right


        # See if we hit anything
        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            # If we are moving right,
            # set our right side to the left side of the item we hit
            if self.xVel > 0:
                self.rect.right = block.rect.left
            elif self.xVel < 0:
                # Otherwise if we are moving left, do the opposite.
                self.rect.left = block.rect.right

        # Move up/down
        self.rect.y += self.yVel

        # Check and see if we hit anything
        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:

            # Reset our position based on the top/bottom of the object.
            if self.yVel > 0:
                self.rect.bottom = block.rect.top
            elif self.yVel < 0:
                self.rect.top = block.rect.bottom

            # Stop our vertical movement
            self.yVel = 0

    def calc_grav(self):
        """ Calculate effect of gravity. """
        if self.yVel == 0:
            self.yVel = 1
        else:
            self.yVel += .35

        # See if we are on the ground.
        if self.rect.y >= SCREEN_HEIGHT - self.rect.height and self.yVel >= 0:
            self.yVel = 0
            self.rect.y = SCREEN_HEIGHT - self.rect.height

    def jump(self):
        """ Called when user hits 'jump' button. """

        # move down a bit and see if there is a platform below us.
        # Move down 2 pixels because it doesn't work well if we only move down
        # 1 when working with a platform moving down.
        self.rect.y += 2
        platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        self.rect.y -= 2

        # If it is ok to jump, set our speed upwards
        if len(platform_hit_list) > 0 or self.rect.bottom >= SCREEN_HEIGHT:
            self.yVel = -10




class Platform(pygame.sprite.Sprite):
    """ Platform the user can jump on """

    def __init__(self, width, height):
        """ Platform constructor. Assumes constructed with user passing in
            an array of 5 numbers like what's defined at the top of this
            code. """
        super().__init__()

        self.image = pygame.Surface([width, height])
        self.image.fill(GREEN)

        self.rect = self.image.get_rect()


class Level(object):
    """ This is a generic super-class used to define a level.
        Create a child class for each level with level-specific
        info. """

    def __init__(self, player):
        """ Constructor. Pass in a handle to player. Needed for when moving platforms
            collide with the player. """
        self.platform_list = pygame.sprite.Group()
        self.enemy_list = pygame.sprite.Group()
        self.player = player

        # Background image
        self.background = None

    # Update everythign on this level
    def update(self):
        """ Update everything in this level."""
        self.platform_list.update()
        self.enemy_list.update()

    def draw(self, screen):
        """ Draw everything on this level. """

        # Draw the background
        screen.fill(BLUE)

        # Draw all the sprite lists that we have
        self.platform_list.draw(screen)
        self.enemy_list.draw(screen)


# Create platforms for the level
class Level_01(Level):
    """ Definition for level 1. """

    def __init__(self, player):
        """ Create level 1. """

        # Call the parent constructor
        Level.__init__(self, player)

        # Array with width, height, x, and y of platform
        level = [[210, 70, 500, 500],
                 [210, 70, 200, 400],
                 [210, 70, 600, 300],
                 ]

        # Go through the array above and add platforms
        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)


def main():
    """ Main Program """
    pygame.init()

    # Set the height and width of the screen
    size = [SCREEN_WIDTH, SCREEN_HEIGHT]
    screen = pygame.display.set_mode(size)

    pygame.display.set_caption("Platformer Jumper")

    # Create the player
    player = Player()

    # Create all the levels
    level_list = []
    level_list.append(Level_01(player))

    # Set the current level
    current_level_no = 0
    current_level = level_list[current_level_no]

    active_sprite_list = pygame.sprite.Group()
    player.level = current_level

    player.rect.x = 340
    player.rect.y = SCREEN_HEIGHT - player.rect.height
    active_sprite_list.add(player)

    accel_x = 0
    max_speed = 6
    # Loop until the user clicks the close button.
    done = False

    # Used to manage how fast the screen updates
    clock = pygame.time.Clock()

    # -------- Main Program Loop -----------
    while not done:
        player_running = False
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True

            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    accel_x = -0.5
                if event.key == pygame.K_RIGHT:
                    accel_x = 0.5
                if event.key == pygame.K_SPACE:
                    player.jump()
            elif event.type == pygame.KEYUP:
                if event.key in (pygame.K_LEFT, pygame.K_RIGHT):
                    accel_x = 0

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

        # Decelerate if no key is pressed.
        if accel_x == 0:
            player.xVel *= 0.5

        player.rect.x += player.xVel




        # Update the player.
        active_sprite_list.update()

        # Update items in the level
        current_level.update()

        # If the player gets near the right side, shift the world left (-x)
        if player.rect.right > SCREEN_WIDTH:
            player.rect.right = SCREEN_WIDTH

        # If the player gets near the left side, shift the world right (+x)
        if player.rect.left < 0:
            player.rect.left = 0

        # ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
        current_level.draw(screen)
        active_sprite_list.draw(screen)

        # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT

        # Limit to 60 frames per second
        clock.tick(60)

        # Go ahead and update the screen with what we've drawn.
        pygame.display.flip()

    # Be IDLE friendly. If you forget this line, the program will 'hang'
    # on exit.
    pygame.quit()


if __name__ == "__main__":
    main()

答案 3 :(得分:0)

Kevin,您提到的是关键点,但这是一个非常简单的解决方法,您只需要用一些减速的代码替换检查x_change是正数还是负数的东西,然后在确定了x_change后加减即可。

例如,他的代码是:

if accel_x == 0:
    x_change *= 0.92

用以下内容代替:

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