import pygame
import random
import math

pygame.init()

WIDTH, HEIGHT = 800, 400
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("跑酷游戏 - 摆动横条障碍+下蹲+二段跳+道具")
clock = pygame.time.Clock()
FPS = 60

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 50, 50)
PURPLE = (160, 60, 220)
BLUE = (50, 150, 255)
GOLD = (255, 215, 0)
GREEN = (50, 200, 50)
GRAY = (100, 100, 100)

ground_y = HEIGHT - 40

# 玩家
player_w = 40
player_h = 60
player_crouch_h = 30
player_x = 80
player_y = ground_y - player_h
player_vel_y = 0
player_speed_x = 5
gravity = 0.8
jump_force = -16
jump_count = 0
max_jump = 2
is_crouch = False

# 障碍物：
# type0地面红障碍；type1紫色摆动横条
# 格式 [x, base_y, w, h, type, swing_time, swing_range]
obs_list = []
obs_speed = 6
obs_spawn_timer = 0
obs_min_gap = 120

# 道具
powerup_list = []
powerup_spawn_timer = 0
powerup_min_gap = 300
powerup_size = 30

# 状态
score = 0
high_score = 0
game_over = False

invincible = False
double_score = False
effect_timer = 0
effect_duration = 360

font = pygame.font.SysFont(None, 40)


def reset_game():
    global player_x, player_y, player_vel_y, jump_count, is_crouch
    global obs_list, obs_speed, obs_spawn_timer
    global powerup_list, powerup_spawn_timer
    global score, game_over
    global invincible, double_score, effect_timer

    player_x = 80
    player_y = ground_y - player_h
    player_vel_y = 0
    jump_count = 0
    is_crouch = False

    obs_list = []
    obs_speed = 6
    obs_spawn_timer = 0

    powerup_list = []
    powerup_spawn_timer = 0

    score = 0
    game_over = False

    invincible = False
    double_score = False
    effect_timer = 0


def spawn_obstacle():
    obs_type = random.choice([0, 1])
    if obs_type == 0:
        # 地面固定障碍
        obs_w = random.randint(30, 50)
        obs_h = random.randint(40, 70)
        obs_y = ground_y - obs_h
        # 地面障碍不需要摆动参数
        obs_list.append([WIDTH, obs_y, obs_w, obs_h, obs_type, 0, 0])
    else:
        # 紫色摆动横条
        obs_w = random.randint(60, 90)
        obs_h = 25
        base_y = ground_y - 95
        swing_range = 25  # 上下摆动幅度
        swing_time = random.random() * math.pi * 2  # 初始相位，错开摆动
        obs_list.append([WIDTH, base_y, obs_w, obs_h, obs_type, swing_time, swing_range])


def spawn_powerup():
    powerup_y = ground_y - random.randint(80, 180)
    powerup_list.append([WIDTH, powerup_y, powerup_size, powerup_size])


running = True
while running:
    clock.tick(FPS)
    keys = pygame.key.get_pressed()

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        if event.type == pygame.KEYDOWN:
            if game_over:
                if event.key == pygame.K_SPACE:
                    reset_game()
            else:
                if event.key == pygame.K_SPACE and jump_count < max_jump:
                    player_vel_y = jump_force
                    jump_count += 1

    if not game_over:
        is_crouch = keys[pygame.K_s] or keys[pygame.K_DOWN]

        # 左右移动
        if keys[pygame.K_a] or keys[pygame.K_LEFT]:
            player_x -= player_speed_x
        if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
            player_x += player_speed_x

        # 边界
        if player_x < 0:
            player_x = 0
        if player_x + player_w > WIDTH:
            player_x = WIDTH - player_w

        # 重力跳跃
        player_vel_y += gravity
        player_y += player_vel_y

        if player_y >= ground_y - player_h:
            player_y = ground_y - player_h
            player_vel_y = 0
            jump_count = 0

        # 生成障碍
        obs_spawn_timer += 1
        if obs_spawn_timer > obs_min_gap:
            spawn_obstacle()
            obs_spawn_timer = 0
            obs_min_gap = random.randint(90, 150)

        # 生成道具
        powerup_spawn_timer += 1
        if powerup_spawn_timer > powerup_min_gap:
            spawn_powerup()
            powerup_spawn_timer = 0
            powerup_min_gap = random.randint(240, 420)

        # 更新障碍位置 + 摆动计时
        for obs in obs_list:
            obs[0] -= obs_speed
            if obs[4] == 1:
                obs[5] += 0.04  # 摆动速度，越大晃得越快

        # 移动道具
        for powerup in powerup_list:
            powerup[0] -= obs_speed

        # 清理障碍、计分
        new_obs = []
        for o in obs_list:
            if o[0] + o[2] > 0:
                new_obs.append(o)
            else:
                score += 2 if double_score else 1
        obs_list = new_obs

        # 清理道具
        new_powerups = []
        for p in powerup_list:
            if p[0] + p[2] > 0:
                new_powerups.append(p)
        powerup_list = new_powerups

        # 玩家碰撞盒
        current_ph = player_crouch_h if is_crouch else player_h
        player_rect = pygame.Rect(player_x, player_y + (player_h - current_ph), player_w, current_ph)

        # 碰撞检测
        for o in obs_list:
            if o[4] == 1:
                # 计算摆动后的y
                swing_y = o[1] + math.sin(o[5]) * o[6]
                obs_rect = pygame.Rect(o[0], swing_y, o[2], o[3])
            else:
                obs_rect = pygame.Rect(o[0], o[1], o[2], o[3])

            if player_rect.colliderect(obs_rect):
                if invincible:
                    obs_list.remove(o)
                    score += 5
                else:
                    game_over = True
                    if score > high_score:
                        high_score = score

        # 拾取道具
        for p in powerup_list:
            powerup_rect = pygame.Rect(p[0], p[1], p[2], p[3])
            if player_rect.colliderect(powerup_rect):
                powerup_list.remove(p)
                invincible = True
                double_score = True
                effect_timer = effect_duration
                score += 10

        # 道具倒计时
        if effect_timer > 0:
            effect_timer -= 1
            if effect_timer == 0:
                invincible = False
                double_score = False

        # 难度提速
        obs_speed = 6 + score // 15

    # 绘制
    screen.fill(WHITE)
    pygame.draw.rect(screen, GRAY, (0, ground_y, WIDTH, 40))

    # 道具
    for p in powerup_list:
        pygame.draw.circle(screen, GOLD, (p[0] + p[2] // 2, p[1] + p[3] // 2), p[2] // 2)
        pygame.draw.circle(screen, BLACK, (p[0] + p[2] // 2, p[1] + p[3] // 2), p[2] // 2, 2)

    # 障碍物
    for o in obs_list:
        if o[4] == 0:
            pygame.draw.rect(screen, RED, (o[0], o[1], o[2], o[3]))
        else:
            swing_y = o[1] + math.sin(o[5]) * o[6]
            pygame.draw.rect(screen, PURPLE, (o[0], swing_y, o[2], o[3]))

    # 玩家
    current_ph = player_crouch_h if is_crouch else player_h
    draw_py = player_y + (player_h - current_ph)
    if invincible:
        pygame.draw.rect(screen, GREEN, (player_x, draw_py, player_w, current_ph))
    else:
        pygame.draw.rect(screen, BLUE, (player_x, draw_py, player_w, current_ph))

    score_text = font.render(f"分数：{score}", True, BLACK)
    high_text = font.render(f"最高：{high_score}", True, BLACK)
    jump_text = font.render(f"跳跃：{jump_count}/{max_jump}", True, BLACK)
    screen.blit(score_text, (10, 10))
    screen.blit(high_text, (10, 50))
    screen.blit(jump_text, (10, 90))

    if invincible and double_score:
        effect_text = font.render("无敌 + 双倍分数!", True, GREEN)
        screen.blit(effect_text, (WIDTH // 2 - 140, 10))

    if game_over:
        over_text = font.render("游戏结束！按空格重新开始", True, RED)
        screen.blit(over_text, (WIDTH // 2 - 220, HEIGHT // 2))

    pygame.display.flip()

pygame.quit()
