【问题标题】:Pygame logic issuePygame逻辑问题
【发布时间】:2016-11-29 19:44:49
【问题描述】:

我正在尝试使用 pygame 开发一个 Brick Breaker/Breakout 游戏,但是当我用箭头移动时,我遇到了一个恼人的问题,它会弄脏桨(玩家)上的“球”,我要离开代码给你看看。

import pygame

pygame.init()

isRunning = True

WIDTH = 800
HEIGHT = 600

FPS = 60

clock = pygame.time.Clock()

window = pygame.display.set_mode((WIDTH, HEIGHT))

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.Surface((60, 30))
        self.image.fill((200, 255, 200))
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT - 30

    def update(self):
        self.speedx = 0

        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_a]:
            self.speedx = -5

        if keystate[pygame.K_d]:
            self.speedx = 5

        self.rect.x += self.speedx

        if self.rect.right + self.speedx > WIDTH:
            self.rect.right = WIDTH

        if self.rect.left + self.speedx < 0:
            self.rect.left = 0

        ball = Ball(self.rect.centerx, self.rect.top)
        for i in all_sprites:
            print(i)
        all_sprites.add(ball)

    def shoot(self):
        ball = Ball(self.rect.centerx, self.rect.top)
        all_sprites.add(ball)
        balls.add(ball)

class Ball(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10, 10))
        self.image.fill((100, 150, 200))
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.speedy = -3

    def update(self):
        pass
        #self.rect.y += self.speedy

all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)

while isRunning:

    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            isRunning = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                player.shoot()

    window.fill((0, 0, 30))

    all_sprites.update()

    all_sprites.draw(window)

    pygame.display.flip()

pygame.quit()
quit()

【问题讨论】:

    标签: python pygame


    【解决方案1】:

    我不确定我是否理解您的问题,但代码的问题在于您每次更新播放器时都会创建一个球。只需删除 player update 方法中的最后四行并取消注释 ball 的 update 方法中的行,一切正常。

    其他提示

    当球离开屏幕时删除它们。这将防止游戏运行缓慢或崩溃。可以通过在球更新方法中添加if self.rect.bottom &lt; 0: self.kill()来实现。

    在适当的时候使用elif

    在播放器更新方法中,您定义了一个属性self.speedx,该属性仅在该方法内部使用,因此最好只使用局部变量。此外,不鼓励在 __init__ 方法之外定义属性。

    您的代码稍作修改。

    import pygame
    pygame.init()
    
    is_running = True  # Use lowercase_and_underscore for variable names.
    
    WIDTH = 800
    HEIGHT = 600
    FPS = 60
    
    clock = pygame.time.Clock()
    window = pygame.display.set_mode((WIDTH, HEIGHT))
    
    
    class Player(pygame.sprite.Sprite):
        def __init__(self):
            pygame.sprite.Sprite.__init__(self)
    
            self.image = pygame.Surface((60, 30))
            self.image.fill((200, 255, 200))
            self.rect = self.image.get_rect()
            self.rect.centerx = WIDTH / 2
            self.rect.bottom = HEIGHT - 30
    
        def update(self):
            speedx = 0  # Don't define attributes outside __init__. Local variable works in this case instead.
    
            keystate = pygame.key.get_pressed()
            if keystate[pygame.K_a]:
                speedx = -5
            elif keystate[pygame.K_d]:  # Use elif so it doesn't need to check this condition if the above is true.
                speedx = 5
    
            self.rect.x += speedx
    
            if self.rect.right + speedx > WIDTH:
                self.rect.right = WIDTH
            elif self.rect.left + speedx < 0:  # Use elif so it doesn't need to check this condition if the above is true.
                self.rect.left = 0
    
        def shoot(self):
            ball = Ball(self.rect.centerx, self.rect.top)
            all_sprites.add(ball)
            balls.add(ball)
    
    
    class Ball(pygame.sprite.Sprite):
        def __init__(self, x, y):
            pygame.sprite.Sprite.__init__(self)
            self.image = pygame.Surface((10, 10))
            self.image.fill((100, 150, 200))
            self.rect = self.image.get_rect()
            self.rect.bottom = y
            self.rect.centerx = x
            self.speedy = -3
    
        def update(self):
            if self.rect.bottom < 0:  # Chack if the ball has exit above the screen.
                self.kill()  # If it has it should delete itself.
            self.rect.y += self.speedy
    
    all_sprites = pygame.sprite.Group()
    balls = pygame.sprite.Group()
    player = Player()
    all_sprites.add(player)
    
    while is_running:
    
        clock.tick(FPS)
        print(all_sprites)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    player.shoot()
    
        window.fill((0, 0, 30))
        all_sprites.update()
        all_sprites.draw(window)
        pygame.display.flip()
    
    pygame.quit()
    quit()
    

    编辑:将球保持在桨上并利用空间发射

    首先,您可以在 Player 类中创建一个属性 self.current_ball,它将引用球拍上的球。然后在 Player 类的 update 方法中更新球相对于球拍的位置。

    要让球保持在桨上,你必须将球的self.speedy 更改为从 0 开始,否则它会在创建后直接移动。当您调用 player.shoot() 方法时,您将设置 self.speedy = -3 将开始球移动。

    启动后,您只需在桨上创建一个新球并重复相同的过程。

    import pygame
    pygame.init()
    
    is_running = True  # Use lowercase_and_underscore for variable names.
    
    WIDTH = 800
    HEIGHT = 600
    FPS = 60
    
    clock = pygame.time.Clock()
    window = pygame.display.set_mode((WIDTH, HEIGHT))
    
    
    class Player(pygame.sprite.Sprite):
        def __init__(self):
            pygame.sprite.Sprite.__init__(self)
    
            self.image = pygame.Surface((60, 30))
            self.image.fill((200, 255, 200))
            self.rect = self.image.get_rect()
            self.rect.centerx = WIDTH / 2
            self.rect.bottom = HEIGHT - 30
            self.current_ball = Ball(self.rect.centerx, self.rect.top)
            all_sprites.add(self.current_ball)
            balls.add(self.current_ball)
    
        def update(self):
            speedx = 0  # Don't define attributes outside __init__. Local variable works in this case instead.
    
            keystate = pygame.key.get_pressed()
            if keystate[pygame.K_a]:
                speedx = -5
            elif keystate[pygame.K_d]:  # Use elif so it doesn't need to check this condition if the above is true.
                speedx = 5
    
            self.rect.x += speedx
    
            if self.rect.right + speedx > WIDTH:
                self.rect.right = WIDTH
            elif self.rect.left + speedx < 0:  # Use elif so it doesn't need to check this condition if the above is true.
                self.rect.left = 0
    
            self.current_ball.rect.midbottom = self.rect.midtop  # Set the ball position relative to paddle position.
    
        def shoot(self):
            self.current_ball.speedy = -3  # The ball should start moving.
            self.current_ball = Ball(self.rect.centerx, self.rect.top)  # Create a new ball on the paddle.
            all_sprites.add(self.current_ball)
            balls.add(self.current_ball)
    
    
    class Ball(pygame.sprite.Sprite):
        def __init__(self, x, y):
            pygame.sprite.Sprite.__init__(self)
            self.image = pygame.Surface((10, 10))
            self.image.fill((100, 150, 200))
            self.rect = self.image.get_rect()
            self.rect.bottom = y
            self.rect.centerx = x
            self.speedy = 0  # The ball don't move from the beginning.
    
        def update(self):
            if self.rect.bottom < 0:  # Chack if the ball has exit above the screen.
                self.kill()  # If it has it should delete itself.
            self.rect.y += self.speedy
    
    all_sprites = pygame.sprite.Group()
    balls = pygame.sprite.Group()
    player = Player()
    all_sprites.add(player)
    
    while is_running:
    
        clock.tick(FPS)
        print(all_sprites)
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                is_running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    player.shoot()
    
        window.fill((0, 0, 30))
        all_sprites.update()
        all_sprites.draw(window)
        pygame.display.flip()
    
    pygame.quit()
    quit()
    

    【讨论】:

    • 这并不是我真正想要实现的,我已经在另一个游戏中用你使用过的相同逻辑完成了它。我的问题是我想让球在矩形上方不断移动,而当我按下空格时它必须移动。那么,你能帮我解决这个问题吗?
    • 编辑:我看到你处理过类似问题的帖子,那个人没有更新窗口表面,只是没有显示矩形。在我看来,这就是为什么它不只绘制一次而不是涂抹屏幕的原因。 stackoverflow.com/questions/39970906/…
    • 我添加了一个您正在寻找的实现示例。您的代码弄脏屏幕的原因不是因为我在您链接的问题中回答的原因。您的问题是每次更新玩家时都会创建一个新球,每秒更新 60 次。因此,在 1 秒后,您在不同位置创建了 60 个球。您应该只创建一个球并移动那个球。
    • 好吧,我终于明白了,我把 pygame.draw.rect(bla, bla, bla) 与创建实例列表然后每次都添加混淆了。无论如何,感谢您的回答和帮助(很多)。并且有这么多的耐心:S
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 2015-07-19
    相关资源
    最近更新 更多