2016-11-27 261 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個球。您只應創建一個球並移動該球。 –