2016-11-27 94 views
1

我想用pygame开发一个Brick Breaker/Breakout游戏,但是我正面临着一个恼人的问题,那就是当我用箭头移动时,会在桨(玩家)上弄脏“球”给你看看代码。Pygame逻辑问题

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

回答

2

我不确定我是否理解您的问题,但代码的问题在于您每次更新播放器时都会创建一个球。只需删除播放器更新方法中的最后四行,并取消注释球的更新方法中的一行,并且所有内容都按照原样运行。

其他提示

删除球,当他们退出屏幕。这将防止游戏运行缓慢或崩溃。可以通过在球更新方法中添加if self.rect.bottom < 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类的更新方法中,更新球相对于桨的位置。

要将球保持在桨状态,必须将球的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() 
+0

这实际上并不是我想要实现的,我已经在另一个游戏中使用了相同的逻辑来完成它。 我的问题是,我想把球不断移动与矩形,在它之上,当我按空间它必须移动。 那么,你能帮我解决这个问题吗? –

+0

编辑:我看到一个帖子,你已经处理了类似的问题,这家伙没有更新窗口表面,只是没有显示rects。在我看来,这就是为什么它不是画一次而是画一个画面。 http://stackoverflow.com/questions/39970906/pygame-move-a-square-on-the-screen-but-can-not-erase-the-previous-movements/39970939#39970939 –

+0

我已添加一个你正在寻找的实现的例子。你的代码为什么会弄脏屏幕的原因不是因为我在你关联的问题中回答的原因。你的问题在于你每次更新玩家时都会创造一个新球,每秒玩60次。所以在1秒后你在不同的位置创造了60个球。您只应创建一个球并移动该球。 –