You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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()

拆分逻辑说明

  1. 绘制函数优化:用元组/字典打包相关参数,比如player_paddle包含x,y,width,height,避免函数参数列表过长,同时让函数职责更清晰。
  2. 输入处理函数:单独处理玩家的上下键输入,返回新的paddle位置,主循环只需要接收结果即可。
  3. AI移动函数:把对手的追踪逻辑封装起来,方便后续调整AI难度(比如修改speed参数)。
  4. 球更新函数:整合球的移动、边界碰撞、paddle碰撞逻辑,返回更新后的位置和方向,避免主循环里的嵌套判断。
  5. 得分检测与重置:单独处理得分逻辑,判断球是否出界,返回新分数和是否需要重置球的标记,主循环根据标记重置球。

这样拆分后,主循环的逻辑变得非常清晰,每个函数只负责一件事,后续修改或扩展功能(比如添加音效、修改AI逻辑)时,只需要对应修改单个函数即可,不会影响其他模块。

内容的提问来源于stack exchange,提问作者Bee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 11:34:55