# GESP等级：二级 | GESP Python 二级考点
"""
game.py - Game类 + Brick类
弹球大作战游戏主逻辑
OOP设计：封装游戏循环、物理引擎、渲染、层次功能
"""

import sys
import os
import json
import random
import math
from pathlib import Path

import pygame

from ball import Ball


# ============================================================
# Brick类 — 砖块对象
# ============================================================
class Brick:
    """
    砖块类

    属性:
        rect: pygame.Rect 位置和尺寸
        color: RGB元组
        hp: 生命值（普通=1，坚硬=2，不可摧毁=-1）
        points: 击碎得分
        hit_animation: 被击中后的闪烁计数器
    """

    # 不同行的颜色方案
    ROW_COLORS = [
        (255, 50, 50),    # 红 (第1行)
        (255, 165, 50),   # 橙 (第2行)
        (255, 255, 50),   # 黄 (第3行)
        (50, 200, 50),    # 绿 (第4行)
        (50, 150, 255),   # 蓝 (第5行)
        (200, 50, 255),   # 紫 (第6行)
    ]

    # 不同行的分值
    ROW_POINTS = [60, 50, 40, 30, 20, 10]

    def __init__(self, x, y, width, height, row, brick_type="normal"):
        """
        初始化砖块

        参数:
            x, y: 左上角坐标
            width, height: 砖块尺寸
            row: 行号（决定颜色和分值）
            brick_type: "normal" / "hard" / "unbreakable"
        """
        self.rect = pygame.Rect(x, y, width, height)

        if brick_type == "unbreakable":
            self.hp = -1          # 不可摧毁
            self.color = (100, 100, 100)
            self.points = 0
            self.type = "unbreakable"
        elif brick_type == "hard":
            self.hp = 2           # 需要2次击中
            self.color = (200, 200, 200)
            self.points = 100
            self.type = "hard"
        else:
            self.hp = 1           # 普通砖
            self.color = self.ROW_COLORS[row % len(self.ROW_COLORS)]
            self.points = self.ROW_POINTS[row % len(self.ROW_POINTS)]
            self.type = "normal"

        self.initial_color = self.color
        self.row = row
        self.hit_animation = 0   # 击中闪烁计数器
        self.destroyed = False

    def hit(self):
        """被球击中，返回是否被摧毁"""
        if self.hp == -1:
            # 不可摧毁砖，只闪烁
            self.hit_animation = 8
            return False

        self.hp -= 1
        self.hit_animation = 6

        if self.hp <= 0:
            self.destroyed = True
            return True
        else:
            # hard砖变色提示
            alpha = self.hp / 2.0
            self.color = tuple(
                int(200 + (c - 200) * alpha) if c > 100 else c
                for c in self.initial_color
            )
            return False

    def update(self):
        """更新动画状态"""
        if self.hit_animation > 0:
            self.hit_animation -= 1

    def draw(self, screen):
        """绘制砖块"""
        if self.destroyed:
            return

        # 闪烁效果
        if self.hit_animation > 0 and self.hit_animation % 4 < 2:
            draw_color = (255, 255, 255)
        else:
            draw_color = self.color

        # 砖块主体
        pygame.draw.rect(screen, draw_color, self.rect)
        pygame.draw.rect(screen, (60, 60, 60), self.rect, 1)  # 边框

        # 类型标记
        if self.type == "hard":
            # 坚硬砖显示标记
            mid_x = self.rect.centerx
            mid_y = self.rect.centery
            pygame.draw.line(screen, (100, 100, 100),
                             (mid_x - 6, mid_y), (mid_x + 6, mid_y), 2)
        elif self.type == "unbreakable":
            # 不可摧毁砖显示 X 标记
            mid_x = self.rect.centerx
            mid_y = self.rect.centery
            pygame.draw.line(screen, (80, 80, 80),
                             (mid_x - 5, mid_y - 5), (mid_x + 5, mid_y + 5), 2)
            pygame.draw.line(screen, (80, 80, 80),
                             (mid_x + 5, mid_y - 5), (mid_x - 5, mid_y + 5), 2)

        # 高光效果
        highlight = pygame.Surface((self.rect.width, self.rect.height // 3), pygame.SRCALPHA)
        highlight.fill((255, 255, 255, 30))
        screen.blit(highlight, (self.rect.x, self.rect.y))


# ============================================================
# Particle类 — 粒子特效（三级功能）
# ============================================================
class Particle:
    """简单的粒子特效"""
    def __init__(self, x, y, color, speed=3):
        self.x = x
        self.y = y
        self.vx = random.uniform(-speed, speed)
        self.vy = random.uniform(-speed, speed)
        self.color = color
        self.life = random.randint(15, 30)
        self.max_life = self.life
        self.size = random.randint(2, 5)

    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.vy += 0.1  # 重力
        self.life -= 1
        return self.life > 0

    def draw(self, screen):
        alpha = int(255 * self.life / self.max_life)
        size = max(1, int(self.size * self.life / self.max_life))
        try:
            color = (*self.color[:3], alpha)
        except TypeError:
            color = self.color
        pygame.draw.circle(screen, self.color,
                          (int(self.x), int(self.y)), size)


# ============================================================
# PowerUp类 — 道具（三级功能）
# ============================================================
class PowerUp:
    """
    道具类

    类型:
        wide:  挡板变宽
        multi: 分身球
        slow:  减速
        life:  加命
    """
    TYPES = ["wide", "multi", "slow", "life"]
    COLORS = {
        "wide": (0, 200, 255),
        "multi": (255, 100, 255),
        "slow": (0, 255, 100),
        "life": (255, 50, 50),
    }
    SYMBOLS = {
        "wide": "W",
        "multi": "M",
        "slow": "S",
        "life": "+1",
    }

    def __init__(self, x, y, pu_type):
        self.rect = pygame.Rect(x - 15, y - 10, 30, 20)
        self.type = pu_type
        self.color = self.COLORS[pu_type]
        self.symbol = self.SYMBOLS[pu_type]
        self.speed = 2
        self.active = True

    def update(self):
        self.rect.y += self.speed
        if self.rect.y > 700:
            self.active = False

    def draw(self, screen):
        pygame.draw.rect(screen, self.color, self.rect, border_radius=4)
        pygame.draw.rect(screen, (255, 255, 255), self.rect, 1, border_radius=4)
        font = pygame.font.Font(None, 22)
        text = font.render(self.symbol, True, (255, 255, 255))
        text_rect = text.get_rect(center=self.rect.center)
        screen.blit(text, text_rect)

    def apply(self, game):
        """应用道具效果"""
        if self.type == "wide":
            game.paddle_width = min(200, game.paddle_width + 40)
            game.paddle_rect.width = game.paddle_width
            game.effect_timer = 600  # 10秒 (60fps)
        elif self.type == "multi":
            # 创建两个分身球
            for _ in range(2):
                if len(game.balls) < 5:
                    new_ball = game.balls[0].clone(
                        game.balls[0].x + random.randint(-30, 30),
                        game.balls[0].y
                    )
                    game.balls.append(new_ball)
            game.particle_effect(game.balls[0].x, game.balls[0].y,
                                (255, 100, 255), 15)
        elif self.type == "slow":
            for b in game.balls:
                b.set_speed(max(2, b.base_speed * 0.6))
            game.effect_timer = 480  # 8秒
        elif self.type == "life":
            game.lives = min(9, game.lives + 1)
            game.particle_effect(game.balls[0].x, game.balls[0].y,
                                (255, 50, 50), 20)


# ============================================================
# Game类 — 游戏主控制器
# ============================================================
class Game:
    """
    弹球大作战 Game 主类

    层次功能:
        ⭐   - 基础游戏: 完整可玩的打砖块游戏
        ⭐⭐ - 自定义: 颜色/速度/挡板尺寸/背景色
        ⭐⭐⭐ - 扩展: 道具/特殊砖/粒子特效/最高分

    使用方法:
        game = Game(tier=1)
        game.run()
    """

    # 窗口常量
    SCREEN_WIDTH = 800
    SCREEN_HEIGHT = 620
    FPS = 60
    GAME_AREA_BOTTOM = 580  # 底部信息区域起始

    # 挡板常量
    PADDLE_WIDTH = 100
    PADDLE_HEIGHT = 14
    PADDLE_Y = 555

    # 砖块常量
    BRICK_WIDTH = 78
    BRICK_HEIGHT = 22
    BRICK_PADDING = 4
    BRICK_OFFSET_TOP = 50
    BRICK_OFFSET_LEFT = 15
    BRICK_COLS = 10
    BRICK_ROWS = 5

    # 难度预设
    DIFFICULTY = {
        "easy": {"ball_speed": 4, "paddle_width": 120, "brick_rows": 4},
        "normal": {"ball_speed": 5, "paddle_width": 100, "brick_rows": 5},
        "hard": {"ball_speed": 7, "paddle_width": 80, "brick_rows": 6},
    }

    def __init__(self, tier=1, difficulty="normal"):
        """
        初始化游戏

        参数:
            tier: 1=⭐基础, 2=⭐⭐自定义, 3=⭐⭐⭐扩展
            difficulty: "easy" / "normal" / "hard"
        """
        self.tier = tier
        self.difficulty = difficulty

        # --- 基础属性 ---
        self.score = 0
        self.high_score = self._load_high_score()
        self.lives = 3
        self.level = 1
        self.running = False
        self.paused = False
        self.game_over = False
        self.level_complete = False
        self.started = False  # 是否已发射球

        # --- 挡板 ---
        self.paddle_width = self.PADDLE_WIDTH
        self.paddle_height = self.PADDLE_HEIGHT
        self.paddle_y = self.PADDLE_Y
        self.paddle_rect = pygame.Rect(
            (self.SCREEN_WIDTH - self.paddle_width) // 2,
            self.paddle_y,
            self.paddle_width,
            self.paddle_height,
        )
        self.paddle_color = (200, 200, 255)
        self.paddle_speed = 8
        self.effect_timer = 0  # 道具效果计时

        # --- 球 ---
        self.ball_speed = self.DIFFICULTY[difficulty]["ball_speed"]
        self.ball_start_pos = (
            self.paddle_rect.centerx,
            self.paddle_rect.top - 10,
        )
        self.balls = []
        self._init_ball()

        # --- 砖块 ---
        self.bricks = []
        self._create_bricks()

        # --- 道具和粒子 ---
        self.powerups = []
        self.particles = []
        self.powerup_drop_chance = 0.15  # 15%概率掉落道具

        # --- 二级功能自定义 ---
        self.bg_color = (10, 10, 30)
        self.show_hud = True
        self.ball_color_index = Ball.COLOR_NAMES.index(
            self.balls[0].color_name
        )

        # --- 三级功能 ---
        self.combo_count = 0
        self.combo_timer = 0
        self.max_combo = 0

        # --- 按键状态（二级功能菜单）---
        self.show_settings = False

    # ---------- 初始化辅助 ----------

    def _init_ball(self):
        """创建初始球"""
        ball = Ball(
            self.ball_start_pos[0],
            self.ball_start_pos[1],
            radius=10,
            color_name="white",
            speed=self.ball_speed,
        )
        self.balls = [ball]

    def _create_bricks(self):
        """创建砖块网格"""
        self.bricks.clear()
        rows = self.DIFFICULTY[self.difficulty]["brick_rows"]
        cols = self.BRICK_COLS

        for row in range(rows):
            for col in range(cols):
                x = self.BRICK_OFFSET_LEFT + col * (self.BRICK_WIDTH + self.BRICK_PADDING)
                y = self.BRICK_OFFSET_TOP + row * (self.BRICK_HEIGHT + self.BRICK_PADDING)

                if self.tier >= 3:
                    # 三级功能：混合砖块类型
                    if row == rows - 1 and col in (2, 5, 7):
                        brick_type = "unbreakable"
                    elif row == 0 and col in (1, 4, 6, 8):
                        brick_type = "hard"
                    else:
                        brick_type = "normal"
                else:
                    brick_type = "normal"

                brick = Brick(x, y, self.BRICK_WIDTH, self.BRICK_HEIGHT, row, brick_type)
                self.bricks.append(brick)

    # ---------- 最高分持久化 ----------

    def _load_high_score(self):
        """从文件加载最高分"""
        path = Path(__file__).parent / "highscore.json"
        try:
            if path.exists():
                with open(path, "r", encoding="utf-8") as f:
                    data = json.load(f)
                    return data.get("high_score", 0)
        except (json.JSONDecodeError, IOError):
            pass
        return 0

    def _save_high_score(self):
        """保存最高分到文件"""
        if self.score > self.high_score:
            self.high_score = self.score
            path = Path(__file__).parent / "highscore.json"
            try:
                with open(path, "w", encoding="utf-8") as f:
                    json.dump({"high_score": self.high_score}, f)
            except IOError:
                pass

    # ---------- 粒子特效（三级功能） ----------

    def particle_effect(self, x, y, color, count=10):
        """生成粒子效果"""
        if self.tier >= 3:
            for _ in range(count):
                self.particles.append(Particle(x, y, color))

    # ---------- 游戏循环 ----------

    def run(self):
        """主游戏循环入口"""
        pygame.init()

        # 音频初始化（三级功能）
        self.sound_enabled = False
        if self.tier >= 3:
            try:
                pygame.mixer.init()
                self.sound_enabled = True
                self._init_sounds()
            except Exception:
                self.sound_enabled = False

        self.screen = pygame.display.set_mode(
            (self.SCREEN_WIDTH, self.SCREEN_HEIGHT)
        )
        pygame.display.set_caption(f"弹球大作战 | 第{self.tier}级{'⭐' * self.tier}")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.Font(None, 30)
        self.font_small = pygame.font.Font(None, 22)
        self.font_large = pygame.font.Font(None, 48)

        self.running = True

        while self.running:
            self._handle_events()
            if not self.paused and not self.game_over and not self.level_complete:
                self._update()
            self._draw()
            self.clock.tick(self.FPS)

        pygame.quit()
        sys.exit()

    def _init_sounds(self):
        """初始化音效（三级功能 - 用pygame生成简单音效）"""
        try:
            # 简单碰撞音效 - 使用 Square wave 合成
            self.sound_hit = self._generate_sound(440, 0.08)
            self.sound_brick = self._generate_sound(660, 0.1)
            self.sound_wall = self._generate_sound(330, 0.05)
            self.sound_lose = self._generate_sound(220, 0.3)
            self.sound_win = self._generate_sound(880, 0.15)
            self.sound_powerup = self._generate_sound(550, 0.2)
        except Exception:
            self.sound_enabled = False

    def _generate_sound(self, freq, duration):
        """生成简单正弦波音效"""
        sample_rate = 22050
        n_samples = int(sample_rate * duration)
        buf = pygame.sndarray.make_sound(
            (255 * (n_samples * [0])).reshape((n_samples, 1))
        )
        # 简化：直接用pygame.mixer.Sound
        # 由于生成wave较复杂，使用现有Sound buffer
        # 这里用简单的beep替代
        return None

    def _play_sound(self, sound_type):
        """播放音效"""
        if not self.sound_enabled:
            return
        try:
            # 使用winsound进行简单的beep
            import winsound
            freqs = {
                "hit": 440,
                "brick": 660,
                "wall": 330,
                "lose": 220,
                "win": 880,
                "powerup": 550,
            }
            dur = 80 if sound_type != "lose" else 200
            winsound.Beep(freqs.get(sound_type, 440), dur)
        except Exception:
            pass

    # ---------- 事件处理 ----------

    def _handle_events(self):
        """处理用户输入事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.running = False

            elif event.type == pygame.KEYDOWN:
                self._handle_keydown(event)

        # 持续按键
        keys = pygame.key.get_pressed()
        self._handle_continuous_keys(keys)

        # 鼠标控制挡板（可选）
        if pygame.mouse.get_focused():
            mouse_x, _ = pygame.mouse.get_pos()
            self.paddle_rect.centerx = max(
                self.paddle_rect.width // 2,
                min(self.SCREEN_WIDTH - self.paddle_rect.width // 2, mouse_x)
            )

    def _handle_keydown(self, event):
        """处理按键按下事件"""
        # --- 通用控制 ---
        if event.key == pygame.K_ESCAPE:
            if self.game_over or self.level_complete:
                self.running = False
            else:
                self.paused = not self.paused

        elif event.key == pygame.K_r and self.game_over:
            self._reset_game()
            return

        elif event.key == pygame.K_SPACE:
            if self.game_over or self.level_complete:
                self._reset_game()
                return
            if not self.balls[0].active:
                self.balls[0].launch()
                self.started = True
                if self.tier >= 3:
                    self._play_sound("hit")

        # --- 暂停时或游戏中均可的设置 ---
        if event.key == pygame.K_F1:
            self.show_settings = not self.show_settings

        if not self.paused and not self.game_over:
            # --- 二级功能：实时调整 ---
            if self.tier >= 2:
                if event.key == pygame.K_c:
                    # 切换球颜色
                    for b in self.balls:
                        name = b.cycle_color(1)
                    self.ball_color_index = Ball.COLOR_NAMES.index(name)

                elif event.key == pygame.K_v:
                    # 切换背景色
                    self._cycle_bg_color()

                elif event.key == pygame.K_EQUALS or event.key == pygame.K_PLUS:
                    # 加速
                    new_speed = min(12, self.ball_speed + 1)
                    self.ball_speed = new_speed
                    for b in self.balls:
                        b.set_speed(new_speed)

                elif event.key == pygame.K_MINUS:
                    # 减速
                    new_speed = max(2, self.ball_speed - 1)
                    self.ball_speed = new_speed
                    for b in self.balls:
                        b.set_speed(new_speed)

                elif event.key == pygame.K_LEFTBRACKET:
                    # 缩小挡板
                    self.paddle_width = max(50, self.paddle_width - 10)
                    old_center = self.paddle_rect.centerx
                    self.paddle_rect.width = self.paddle_width
                    self.paddle_rect.centerx = old_center

                elif event.key == pygame.K_RIGHTBRACKET:
                    # 放大挡板
                    self.paddle_width = min(250, self.paddle_width + 10)
                    old_center = self.paddle_rect.centerx
                    self.paddle_rect.width = self.paddle_width
                    self.paddle_rect.centerx = old_center

            # --- 三级功能 ---
            if self.tier >= 3:
                if event.key == pygame.K_t:
                    # 切换轨迹
                    for b in self.balls:
                        b.trail_enabled = not b.trail_enabled

                elif event.key == pygame.K_g:
                    # 切换发光
                    for b in self.balls:
                        b.glow_enabled = not b.glow_enabled

        # 调试：按 F2 直接过关（调试用）
        if event.key == pygame.K_F2 and not self.game_over:
            self._clear_all_bricks()

    def _handle_continuous_keys(self, keys):
        """处理持续按键"""
        if self.paused or self.game_over:
            return

        # 仅当ball未激活时用键盘控制挡板
        # 鼠标控制持续有效（已在事件循环中）
        if not pygame.mouse.get_focused() or not any(pygame.mouse.get_pressed()):
            if keys[pygame.K_LEFT] or keys[pygame.K_a]:
                self.paddle_rect.x -= self.paddle_speed
            if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
                self.paddle_rect.x += self.paddle_speed

        # 边界限制
        self.paddle_rect.x = max(
            0,
            min(self.SCREEN_WIDTH - self.paddle_rect.width, self.paddle_rect.x)
        )

        # 球未发射时跟随挡板
        if not self.started or not self.balls[0].active:
            self.balls[0].x = self.paddle_rect.centerx
            self.balls[0].y = self.paddle_rect.top - self.balls[0].radius

    def _cycle_bg_color(self):
        """循环切换背景色（二级功能）"""
        bg_colors = [
            (10, 10, 30),    # 深蓝
            (30, 10, 10),    # 深红
            (10, 30, 10),    # 深绿
            (30, 30, 10),    # 深黄
            (10, 10, 10),    # 纯黑
            (30, 10, 30),    # 深紫
        ]
        try:
            idx = bg_colors.index(self.bg_color)
        except ValueError:
            idx = 0
        self.bg_color = bg_colors[(idx + 1) % len(bg_colors)]

    # ---------- 更新逻辑 ----------

    def _update(self):
        """更新游戏状态"""
        # 更新球
        for ball in self.balls[:]:
            ball.move()
            ball.bounce_wall(self.SCREEN_WIDTH, self.SCREEN_HEIGHT - 40)

            # 挡板碰撞
            if ball.bounce_paddle(self.paddle_rect):
                if self.tier >= 3:
                    self._play_sound("hit")
                self.started = True

            # 砖块碰撞
            for brick in self.bricks:
                if brick.destroyed:
                    continue
                result = ball.bounce_brick(brick.rect)
                if result:
                    if brick.hit():
                        # 砖块被摧毁
                        self._on_brick_destroyed(brick, ball)
                    else:
                        # 坚硬砖击中但未碎
                        if self.tier >= 3:
                            self._play_sound("hit")
                        self.particle_effect(
                            ball.x, ball.y, (255, 255, 255), 3
                        )
                    break  # 每帧只处理一个砖块碰撞

            # 检查球是否出界
            if ball.is_off_screen(self.SCREEN_HEIGHT):
                if ball.is_clone and self.tier >= 3:
                    # 分身球消失
                    self.balls.remove(ball)
                else:
                    self._on_ball_lost()
                    return

        # 更新道具
        for pu in self.powerups[:]:
            pu.update()
            if not pu.active:
                self.powerups.remove(pu)
                continue
            if pu.rect.colliderect(self.paddle_rect):
                pu.apply(self)
                self.powerups.remove(pu)
                if self.tier >= 3:
                    self._play_sound("powerup")
                self.particle_effect(pu.rect.centerx, pu.rect.centery,
                                    pu.color, 15)

        # 更新粒子
        self.particles = [p for p in self.particles if p.update()]

        # 更新砖块动画
        for brick in self.bricks:
            brick.update()

        # 道具效果计时
        if self.effect_timer > 0:
            self.effect_timer -= 1
            if self.effect_timer == 0:
                self._reset_effects()

        # 连击计时
        if self.combo_timer > 0:
            self.combo_timer -= 1
            if self.combo_timer == 0:
                self.combo_count = 0

        # 检查过关
        if all(b.destroyed or b.type == "unbreakable" for b in self.bricks):
            self.level_complete = True
            if self.tier >= 3:
                self._play_sound("win")
            self._save_high_score()

        # 防呆：如果球全灭但没有game_over（分身球全消失）
        if all(b.is_off_screen(self.SCREEN_HEIGHT) for b in self.balls):
            if not self.game_over:
                self._on_ball_lost()

    def _on_brick_destroyed(self, brick, ball):
        """砖块被摧毁时的处理"""
        if self.tier >= 3:
            self._play_sound("brick")

        # 连击
        self.combo_count += 1
        self.combo_timer = 60  # 1秒内连续击碎算连击
        combo_bonus = self.combo_count if self.combo_count > 1 else 1
        if self.combo_count > self.max_combo:
            self.max_combo = self.combo_count

        # 计分
        points = brick.points * combo_bonus
        self.score += points

        # 粒子特效（三级功能）
        if self.tier >= 3:
            self.particle_effect(
                brick.rect.centerx,
                brick.rect.centery,
                brick.initial_color,
                12
            )

        # 道具掉落（三级功能）
        if self.tier >= 3:
            if random.random() < self.powerup_drop_chance:
                pu_type = random.choice(PowerUp.TYPES)
                pu = PowerUp(brick.rect.centerx, brick.rect.centery, pu_type)
                self.powerups.append(pu)

    def _on_ball_lost(self):
        """球掉落时的处理"""
        self.lives -= 1

        if self.tier >= 3:
            self._play_sound("lose")

        if self.lives <= 0:
            self.game_over = True
            self._save_high_score()
            return

        # 重置球
        if self.balls:
            main_ball = self.balls[0]
            main_ball.reset(
                self.paddle_rect.centerx,
                self.paddle_rect.top - main_ball.radius
            )
            # 清除分身球
            self.balls = [main_ball]
            self.balls[0].is_clone = False

        self.started = False

    def _reset_effects(self):
        """重置道具效果"""
        # 恢复挡板宽度
        self.paddle_width = self.DIFFICULTY[self.difficulty]["paddle_width"]
        self.paddle_rect.width = self.paddle_width
        # 恢复球速
        for b in self.balls:
            b.set_speed(self.ball_speed)

    def _clear_all_bricks(self):
        """清空所有砖块（调试/过关）"""
        for brick in self.bricks:
            if not brick.destroyed and brick.type != "unbreakable":
                brick.destroyed = True
                self.score += brick.points
                self.particle_effect(
                    brick.rect.centerx, brick.rect.centery,
                    brick.initial_color, 8
                )

    def _reset_game(self):
        """重置整个游戏"""
        self.score = 0
        self.lives = 3
        self.level = 1
        self.game_over = False
        self.level_complete = False
        self.started = False
        self.combo_count = 0
        self.combo_timer = 0
        self.max_combo = 0
        self.powerups.clear()
        self.particles.clear()
        self._reset_effects()

        # 重置挡板
        self.paddle_rect.centerx = self.SCREEN_WIDTH // 2
        self.paddle_rect.y = self.PADDLE_Y

        # 重置球
        self._init_ball()
        self.balls[0].x = self.paddle_rect.centerx
        self.balls[0].y = self.paddle_rect.top - self.balls[0].radius

        # 重建砖块
        self._create_bricks()

    # ---------- 渲染 ----------

    def _draw(self):
        """绘制所有内容"""
        self.screen.fill(self.bg_color)

        # 绘制砖块
        for brick in self.bricks:
            brick.draw(self.screen)

        # 绘制道具
        for pu in self.powerups:
            pu.draw(self.screen)

        # 绘制粒子
        for p in self.particles:
            p.draw(self.screen)

        # 绘制球
        for ball in self.balls:
            ball.draw(self.screen)

        # 绘制挡板
        if self.effect_timer > 0:
            # 有道具效果时挡板闪烁
            glow = (255, 255, 255) if self.effect_timer // 30 % 2 == 0 else self.paddle_color
            pygame.draw.rect(self.screen, glow, self.paddle_rect, border_radius=5)
        else:
            pygame.draw.rect(self.screen, self.paddle_color, self.paddle_rect, border_radius=5)

        # 挡板高光
        highlight_rect = pygame.Rect(
            self.paddle_rect.x + 4,
            self.paddle_rect.y + 2,
            self.paddle_rect.width - 8,
            self.paddle_rect.height // 2,
        )
        pygame.draw.rect(
            self.screen, (255, 255, 255, 40), highlight_rect, border_radius=3
        )

        # 绘制底部信息区域分割线
        pygame.draw.line(
            self.screen, (100, 100, 100),
            (0, self.GAME_AREA_BOTTOM),
            (self.SCREEN_WIDTH, self.GAME_AREA_BOTTOM),
            2,
        )

        # 绘制 HUD
        self._draw_hud()

        # 覆盖层
        if self.paused:
            self._draw_overlay("暂停", "按 ESC 继续", (255, 255, 255))
        if self.game_over:
            self._draw_overlay("游戏结束", f"得分: {self.score}  |  按 R 重新开始  |  ESC 退出", (255, 100, 100))
        if self.level_complete:
            self._draw_overlay("过关!", f"得分: {self.score}  |  按 SPACE 下一关  |  ESC 退出", (100, 255, 100))

        # 设置面板
        if self.show_settings:
            self._draw_settings_panel()

        pygame.display.flip()

    def _draw_hud(self):
        """绘制游戏信息"""
        y = self.GAME_AREA_BOTTOM + 8

        # 分数
        score_text = self.font.render(f"分数: {self.score}", True, (255, 255, 255))
        self.screen.blit(score_text, (15, y))

        # 最高分（三级功能）
        if self.tier >= 3:
            hs_text = self.font_small.render(
                f"最高分: {self.high_score}", True, (200, 200, 100)
            )
            self.screen.blit(hs_text, (15, y + 28))

        # 等级
        lv_text = self.font.render(f"关卡: {self.level}", True, (255, 255, 255))
        self.screen.blit(lv_text, (250, y))

        # 生命
        life_text = self.font.render(f"生命: {'♥' * self.lives}{'♡' * (9 - self.lives)}", True, (255, 100, 100))
        self.screen.blit(life_text, (400, y))

        # 速度（二级功能）
        if self.tier >= 2:
            speed_text = self.font_small.render(
                f"速度: {self.ball_speed}", True, (150, 200, 255)
            )
            self.screen.blit(speed_text, (660, y))

        # 连击（三级功能）
        if self.tier >= 3 and self.combo_count > 1:
            combo_text = self.font_small.render(
                f"连击 x{self.combo_count}", True, (255, 255, 0)
            )
            self.screen.blit(combo_text, (660, y + 24))

        # 操作提示
        hint = "[F1] 设置" if self.tier >= 2 else "[ESC] 暂停"
        hint_text = self.font_small.render(hint, True, (100, 100, 100))
        self.screen.blit(hint_text, (self.SCREEN_WIDTH - 120, y))

    def _draw_overlay(self, title, subtitle, title_color):
        """绘制居中覆盖层"""
        s = pygame.Surface((self.SCREEN_WIDTH, self.SCREEN_HEIGHT), pygame.SRCALPHA)
        s.fill((0, 0, 0, 180))
        self.screen.blit(s, (0, 0))

        title_surf = self.font_large.render(title, True, title_color)
        title_rect = title_surf.get_rect(center=(self.SCREEN_WIDTH // 2, 240))
        self.screen.blit(title_surf, title_rect)

        sub_surf = self.font.render(subtitle, True, (200, 200, 200))
        sub_rect = sub_surf.get_rect(center=(self.SCREEN_WIDTH // 2, 290))
        self.screen.blit(sub_surf, sub_rect)

    def _draw_settings_panel(self):
        """绘制设置面板（二级/三级功能说明）"""
        # 半透明背景
        s = pygame.Surface((self.SCREEN_WIDTH, self.SCREEN_HEIGHT), pygame.SRCALPHA)
        s.fill((0, 0, 0, 200))
        self.screen.blit(s, (0, 0))

        lines = [
            "=== 设置面板 ===",
            "",
            "[ESC]  暂停/继续",
            "[R]    重新开始（游戏结束时）",
            "[F1]   开关本面板",
            "[SPACE] 发射球",
            "",
            "--- 二级功能 ⭐⭐ ---",
            "[C]    切换球颜色",
            "[V]    切换背景色",
            "[+/-]  加速/减速 (2-12)",
            "[[/]]  缩小/放大挡板",
        ]

        if self.tier >= 3:
            lines += [
                "",
                "--- 三级功能 ⭐⭐⭐ ---",
                "[T]    开关轨迹特效",
                "[G]    开关发光特效",
            ]

        lines += [
            "",
            f"当前球色: {self.balls[0].color_name}",
            f"当前速度: {self.ball_speed}",
            f"挡板宽度: {self.paddle_width}",
        ]

        if self.tier >= 3:
            lines += [
                f"轨迹: {'开' if self.balls[0].trail_enabled else '关'}",
                f"发光: {'开' if self.balls[0].glow_enabled else '关'}",
                f"最高分: {self.high_score}",
            ]

        for i, line in enumerate(lines):
            color = (255, 255, 100) if line.startswith("==") else \
                    (200, 200, 100) if line.startswith("---") else \
                    (150, 200, 255) if "当前" in line else \
                    (200, 200, 200)
            text = self.font_small.render(line, True, color)
            self.screen.blit(text, (200, 80 + i * 22))


# ============================================================
# 模块自测
# ============================================================
if __name__ == "__main__":
    print("Game module loaded. Usage:")
    print("  from game import Game")
    print("  game = Game(tier=3)")
    print("  game.run()")
