本节没有添加新的功能,而是将前面的功能使用精灵类(pygame.sprite.Sprite
) 重构。
顺便我们使用图片美化了一下程序。
看到之前的代码,你会发现代码有点混乱,很多地方使用了全局变量(global
)。
本节我们将使用类进行重构。
Block(Sprite)
:基类,用于创建一个带图像的长方形。Player(Block)
:玩家。Ball(Block)
:球。Opponent(Block)
: 对手。GameManager
: 绘制/更新元素。我们将游戏的主要逻辑移到了这个类中。
键盘的输入还是在主循环中处理,这样搞还是有些混乱。
在主程序中,需要创建pygame.sprite.Group()
,并将精灵加入其中。
import sys
import random
import pygameclass Block(pygame.sprite.Sprite):def __init__(self,path,x_pos,y_pos):super().__init__()self.image = pygame.image.load(path)self.rect = self.image.get_rect(center = (x_pos,y_pos))class Player(Block):def __init__(self,path,x_pos,y_pos,speed):super().__init__(path,x_pos,y_pos)self.speed = speedself.movement = 0def screen_constrain(self):if self.rect.top <= 0:self.rect.top = 0if self.rect.bottom >= screen_height:self.rect.bottom = screen_heightdef update(self,ball_group):self.rect.y += self.movementself.screen_constrain()class Ball(Block):def __init__(self,path,x_pos,y_pos,speed_x,speed_y,paddles):super().__init__(path,x_pos,y_pos)self.speed_x = speed_x * random.choice((1,-1))self.speed_y = speed_y * random.choice((1,-1))self.paddles = paddlesself.active = Falseself.score_time = 0def update(self):if self.active:self.rect.x += self.speed_xself.rect.y += self.speed_yself.collisions()else:self.restart_counter()def collisions(self):if self.rect.top <= 0 or self.rect.bottom >= screen_height:pygame.mixer.Sound.play(pong_sound)self.speed_y *= -1if pygame.sprite.spritecollide(self,self.paddles,False):pygame.mixer.Sound.play(pong_sound)collision_paddle = pygame.sprite.spritecollide(self,self.paddles,False)[0].rectif abs(self.rect.right - collision_paddle.left) < 10 and self.speed_x > 0:self.speed_x *= -1if abs(self.rect.left - collision_paddle.right) < 10 and self.speed_x < 0:self.speed_x *= -1if abs(self.rect.top - collision_paddle.bottom) < 10 and self.speed_y < 0:self.speed_y *= -1if abs(self.rect.bottom - collision_paddle.top) < 10 and self.speed_y > 0:self.speed_y *= -1def reset_ball(self):self.active = Falseself.speed_x *= random.choice((1,-1))self.speed_y *= random.choice((1,-1))self.score_time = pygame.time.get_ticks()self.rect.center = (screen_width/2,screen_height/2)pygame.mixer.Sound.play(score_sound)def restart_counter(self):current_time = pygame.time.get_ticks()countdown_number = 3if current_time - self.score_time <= 700:countdown_number = 3if 700 < current_time - self.score_time <= 1400:countdown_number = 2if 1400 < current_time - self.score_time <= 2100:countdown_number = 1if current_time - self.score_time >= 2100:self.active = Truetime_counter = basic_font.render(str(countdown_number),True,accent_color)time_counter_rect = time_counter.get_rect(center = (screen_width/2,screen_height/2 + 50))pygame.draw.rect(screen,bg_color,time_counter_rect)screen.blit(time_counter,time_counter_rect)class Opponent(Block):def __init__(self,path,x_pos,y_pos,speed):super().__init__(path,x_pos,y_pos)self.speed = speeddef update(self,ball_group):if self.rect.top < ball.rect.y:self.rect.y += self.speedif self.rect.bottom > ball.rect.y:self.rect.y -= self.speedself.constrain()def constrain(self):if self.rect.top <= 0: self.rect.top = 0if self.rect.bottom >= screen_height: self.rect.bottom = screen_heightclass GameManager:def __init__(self,ball_group,paddle_group):self.player_score = 0self.opponent_score = 0self.ball_group = ball_groupself.paddle_group = paddle_groupdef run_game(self):self.paddle_group.draw(screen)self.ball_group.draw(screen)self.paddle_group.update(self.ball_group)self.ball_group.update()self.reset_ball()self.draw_score()def reset_ball(self):if self.ball_group.sprite.rect.right >= screen_width:self.opponent_score += 1self.ball_group.sprite.reset_ball()if self.ball_group.sprite.rect.left <= 0:self.player_score += 1self.ball_group.sprite.reset_ball()def draw_score(self):player_score = basic_font.render(str(self.player_score),True,accent_color)opponent_score = basic_font.render(str(self.opponent_score),True,accent_color)player_score_rect = player_score.get_rect(midleft = (screen_width / 2 + 40,screen_height/2))opponent_score_rect = opponent_score.get_rect(midright = (screen_width / 2 - 40,screen_height/2))screen.blit(player_score,player_score_rect)screen.blit(opponent_score,opponent_score_rect)# General setup
pygame.mixer.pre_init(44100, -16, 2, 512)
pygame.init()
clock = pygame.time.Clock()# Main Window
screen_width = 980
screen_height = 720
screen = pygame.display.set_mode((screen_width,screen_height))
pygame.display.set_caption('Pong')# Global Variables
bg_color = pygame.Color('#2F373F')
accent_color = (27,35,43)
basic_font = pygame.font.Font('freesansbold.ttf', 32)
pong_sound = pygame.mixer.Sound("pong.ogg")
score_sound = pygame.mixer.Sound("score.ogg")
middle_strip = pygame.Rect(screen_width/2 - 2,0,4,screen_height)# Game Objects
player = Player('Paddle.png',screen_width - 20,screen_height/2,5)
opponent = Opponent('Paddle.png',20,screen_width/2,5)
paddle_group = pygame.sprite.Group()
paddle_group.add(player)
paddle_group.add(opponent)ball = Ball('Ball.png',screen_width/2,screen_height/2,4,4,paddle_group)
ball_sprite = pygame.sprite.GroupSingle()
ball_sprite.add(ball)game_manager = GameManager(ball_sprite,paddle_group)# Game Loop
while True:for event in pygame.event.get():if event.type == pygame.QUIT:pygame.quit()sys.exit()if event.type == pygame.KEYDOWN:if event.key == pygame.K_DOWN:player.movement += player.speedif event.key == pygame.K_UP:player.movement -= player.speedif event.type == pygame.KEYUP:if event.key == pygame.K_DOWN:player.movement -= player.speedif event.key == pygame.K_UP:player.movement += player.speed# Background Stuffscreen.fill(bg_color)pygame.draw.rect(screen,accent_color,middle_strip)# Run Gamegame_manager.run_game()# Renderingpygame.display.flip()clock.tick(120)