如何为Python Pygame乒乓球游戏合理拆分函数优化代码?
Pygame乒乓球游戏代码结构优化方案
你的思路是对的——用函数拆分代码确实能提升可读性和可维护性。原有的绘制函数方向没问题,但可以优化参数传递方式,同时把主循环里的逻辑模块也拆分成独立函数,避免主函数过于臃肿。
优化点说明
- 打包相关变量:把 paddle、ball 这类属性相关的变量打包成元组/字典,减少函数参数数量,让函数更简洁。
- 拆分逻辑模块:将输入处理、AI移动、碰撞检测、球重置等逻辑从主循环中剥离,每个函数只负责单一职责。
- 减少冗余封装:像原代码中
update_display这类无额外逻辑的封装可以直接替换为原调用,避免不必要的函数层级。
优化后的完整代码
import pygame import random # ---------------------- 绘制类函数(优化参数) ---------------------- def draw_paddles(window, color, player_paddle, opponent_paddle): # player_paddle格式:(x, y, width, height) pygame.draw.rect(window, color, player_paddle) pygame.draw.rect(window, color, opponent_paddle) def draw_ball(window, color, ball_pos, radius): # ball_pos格式:(x, y) pygame.draw.circle(window, color, ball_pos, radius) def draw_scores(window, window_width, colors, font, scores): player_score_text = font.render(f"Score: {scores['player']}", True, colors['blue']) opponent_score_text = font.render(f"Opponent: {scores['opponent']}", True, colors['red']) window.blit(player_score_text, (10, 10)) window.blit(opponent_score_text, (window_width - opponent_score_text.get_width() - 10, 10)) def draw_countdown(window, window_size, colors, countdown_font, text, counter): window_width, window_height = window_size countdown_text = countdown_font.render(text, True, colors['white'] if counter > 0 else colors['green']) countdown_position = ( (window_width - countdown_text.get_width()) // 2, (window_height - countdown_text.get_height()) // 2 - 40 ) window.blit(countdown_text, countdown_position) # ---------------------- 游戏逻辑类函数 ---------------------- def handle_player_input(player_paddle, window_height, speed=5): keys = pygame.key.get_pressed() paddle_y = player_paddle[1] paddle_height = player_paddle[3] if keys[pygame.K_UP] and paddle_y > 0: return (player_paddle[0], paddle_y - speed, player_paddle[2], player_paddle[3]) if keys[pygame.K_DOWN] and paddle_y < window_height - paddle_height: return (player_paddle[0], paddle_y + speed, player_paddle[2], player_paddle[3]) return player_paddle def move_opponent_paddle(opponent_paddle, ball_pos, window_height, speed=1.5): paddle_y = opponent_paddle[1] paddle_height = opponent_paddle[3] ball_y = ball_pos[1] # 追踪球的y坐标,简单AI逻辑 if ball_y < paddle_y + paddle_height / 2: new_y = paddle_y - speed else: new_y = paddle_y + speed # 限制 paddle 不超出窗口 new_y = max(0, min(new_y, window_height - paddle_height)) return (opponent_paddle[0], new_y, opponent_paddle[2], opponent_paddle[3]) def update_ball(ball_pos, ball_dir, ball_radius, window_size, player_paddle, opponent_paddle, ball_speed): ball_x, ball_y = ball_pos dx, dy = ball_dir window_width, window_height = window_size # 移动球 new_x = ball_x + dx new_y = ball_y + dy # 上下边界碰撞 if new_y - ball_radius <= 0 or new_y + ball_radius >= window_height: dy = -dy # 玩家 paddle 碰撞 if (new_x <= player_paddle[0] + player_paddle[2] and player_paddle[1] <= new_y <= player_paddle[1] + player_paddle[3]): dx = abs(ball_speed) new_x = player_paddle[0] + player_paddle[2] + ball_radius + 1 # 修正位置避免重复碰撞 # 对手 paddle 碰撞 if (new_x >= opponent_paddle[0] - ball_radius and opponent_paddle[1] <= new_y <= opponent_paddle[1] + opponent_paddle[3]): dx = -abs(ball_speed) new_x = opponent_paddle[0] - ball_radius - 1 # 修正位置避免重复碰撞 return (new_x, new_y), (dx, dy) def check_score(ball_pos, ball_radius, window_width, scores): ball_x = ball_pos[0] new_scores = scores.copy() # 球出左边界,对手得分 if ball_x - ball_radius <= 0: new_scores['opponent'] += 1 return new_scores, True # 球出右边界,玩家得分 elif ball_x + ball_radius >= window_width: new_scores['player'] += 1 return new_scores, True return new_scores, False def reset_ball(window_size): window_width, window_height = window_size return (window_width // 2, window_height // 2) # ---------------------- 主函数 ---------------------- def main(): pygame.init() # 窗口设置 window_size = (600, 400) window_width, window_height = window_size window = pygame.display.set_mode(window_size) pygame.display.set_caption("Cosmic Collision") # 颜色定义 colors = { 'black': (0, 0, 0), 'white': (255, 255, 255), 'red': (255, 64, 64), 'blue': (126, 192, 238), 'gray': (217, 217, 217), 'green': (189, 252, 201), 'dark_red': (238, 64, 0) } # 游戏对象初始化 ball_radius = 10 ball_speed = 3 ball_pos = reset_ball(window_size) ball_dir = (ball_speed, ball_speed) # (dx, dy) paddle_width = 10 paddle_height = 60 player_paddle = (0, (window_height - paddle_height) // 2, paddle_width, paddle_height) opponent_paddle = (window_width - paddle_width, (window_height - paddle_height) // 2, paddle_width, paddle_height) opponent_speed = 1.5 scores = {'player': 0, 'opponent': 0} # 字体 font = pygame.font.SysFont(None, 40) countdown_font = pygame.font.SysFont('Consolas', 60) clock = pygame.time.Clock() game_over = False # 倒计时设置 counter, text = 3, '3' pygame.time.set_timer(pygame.USEREVENT, 1000) countdown_active = True while not game_over: # 事件处理 for event in pygame.event.get(): if event.type == pygame.QUIT: game_over = True if event.type == pygame.USEREVENT and countdown_active: counter -= 1 if counter > 0: text = str(counter) elif counter == 0: text = 'Go!' else: countdown_active = False if not countdown_active: # 更新玩家 paddle 位置 player_paddle = handle_player_input(player_paddle, window_height) # 更新对手 paddle 位置 opponent_paddle = move_opponent_paddle(opponent_paddle, ball_pos, window_height, opponent_speed) # 更新球的位置和方向 ball_pos, ball_dir = update_ball(ball_pos, ball_dir, ball_radius, window_size, player_paddle, opponent_paddle, ball_speed) # 检查得分并重置球 scores, scored = check_score(ball_pos, ball_radius, window_width, scores) if scored: ball_pos = reset_ball(window_size) ball_dir = (ball_speed, ball_speed) # 绘制流程 window.fill(colors['black']) draw_paddles(window, colors['white'], player_paddle, opponent_paddle) draw_ball(window, colors['gray'], ball_pos, ball_radius) draw_scores(window, window_width, colors, font, scores) if countdown_active: draw_countdown(window, window_size, colors, countdown_font, text, counter) pygame.display.update() clock.tick(60) pygame.quit() if __name__ == "__main__": main()
拆分逻辑说明
- 绘制函数优化:用元组/字典打包相关参数,比如
player_paddle包含x,y,width,height,避免函数参数列表过长,同时让函数职责更清晰。 - 输入处理函数:单独处理玩家的上下键输入,返回新的paddle位置,主循环只需要接收结果即可。
- AI移动函数:把对手的追踪逻辑封装起来,方便后续调整AI难度(比如修改speed参数)。
- 球更新函数:整合球的移动、边界碰撞、paddle碰撞逻辑,返回更新后的位置和方向,避免主循环里的嵌套判断。
- 得分检测与重置:单独处理得分逻辑,判断球是否出界,返回新分数和是否需要重置球的标记,主循环根据标记重置球。
这样拆分后,主循环的逻辑变得非常清晰,每个函数只负责一件事,后续修改或扩展功能(比如添加音效、修改AI逻辑)时,只需要对应修改单个函数即可,不会影响其他模块。
内容的提问来源于stack exchange,提问作者Bee
相关产品推荐
相关产品推荐

