import pygame
import math
import random

# --- 配置部分 ---
WIDTH, HEIGHT = 800, 600
MAP_SIZE = 16
TILE_SIZE = 64
FOV = math.pi / 3
HALF_FOV = FOV / 2
NUM_RAYS = WIDTH // 2  # 降低分辨率以提高贴图性能和复古感
MAX_DEPTH = MAP_SIZE   # 基础最大视距
SCALE = WIDTH // NUM_RAYS

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
DARK_RED = (50, 0, 0)

# --- 初始化 ---
pygame.init()
pygame.mixer.init() # 初始化音效系统

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("恐怖迷宫: 逃离实体")
clock = pygame.time.Clock()
font_hud = pygame.font.SysFont('Arial', 24, bold=True)
font_end = pygame.font.SysFont('Arial', 64, bold=True)

# --- 资源加载 (贴图与音效) ---

# 1. 墙壁贴图系统
try:
    # 尝试加载名为 wall.jpg 的图片
    wall_texture = pygame.image.load('wall.jpg').convert()
    wall_texture = pygame.transform.scale(wall_texture, (TILE_SIZE, TILE_SIZE))
except:
    # 如果没图，程序自动生成一个“恐怖噪点”纹理
    print("未找到 wall.jpg，使用程序生成的噪点纹理。")
    wall_texture = pygame.Surface((TILE_SIZE, TILE_SIZE))
    for x in range(TILE_SIZE):
        for y in range(TILE_SIZE):
            # 生成灰暗、脏兮兮的噪点
            noise = random.randint(30, 100)
            # 偶尔有一些血迹般的红点
            if random.random() < 0.05:
                wall_texture.set_at((x, y), (noise + 50, 0, 0))
            else:
                wall_texture.set_at((x, y), (noise, noise, noise))

# 2. 音效加载 (示例代码，需要你有对应的wav/mp3文件)
# 为了防止报错，这里使用了 try-except，如果你有文件请取消注释并确保文件名正确
try:
    # 背景环境音 (电流声、风声)
    # bg_music = pygame.mixer.Sound('ambience.wav')
    # bg_music.play(-1) # -1 表示无限循环
    
    # 心跳声
    # heartbeat_sfx = pygame.mixer.Sound('heartbeat.wav')
    pass
except:
    print("未找到音频文件，静音模式运行。")

# --- 游戏状态变量 ---
player_x, player_y = 1.5, 1.5
player_angle = 0
enemy_x, enemy_y = MAP_SIZE - 2.5, MAP_SIZE - 2.5 # 敌人初始位置
enemy_speed = 0.02 # 敌人移动速度 (比玩家慢，但穿墙)

# 地图生成 (1是墙，0是路)
world_map = [[1] * MAP_SIZE for _ in range(MAP_SIZE)]
for x in range(1, MAP_SIZE - 1):
    for y in range(1, MAP_SIZE - 1):
        world_map[x][y] = 0

# 随机生成障碍物
for _ in range(int(MAP_SIZE * MAP_SIZE * 0.2)):
    rx, ry = random.randint(1, MAP_SIZE-2), random.randint(1, MAP_SIZE-2)
    world_map[rx][ry] = 1

# 确保关键位置畅通
world_map[1][1] = 0
world_map[MAP_SIZE-2][MAP_SIZE-2] = 0

# 出口位置
exit_pos = (MAP_SIZE - 1.5, MAP_SIZE - 1.5)

# --- 核心函数 ---

def cast_rays():
    """射线投射与3D渲染"""
    # --- 呼吸光影效果 ---
    # 使用正弦波模拟手电筒电压不稳或紧张的视觉收缩
    time_now = pygame.time.get_ticks()
    # 周期约3秒，幅度为2.5个单位距离
    breath_offset = math.sin(time_now * 0.002) * 2.5 
    # 基础视距 + 呼吸波动
    current_max_depth = MAX_DEPTH + breath_offset 

    start_angle = player_angle - HALF_FOV
    
    for ray in range(NUM_RAYS):
        angle = start_angle + ray * (FOV / NUM_RAYS)
        sin_a = math.sin(angle)
        cos_a = math.cos(angle)
        
        # 射线投射
        for depth in range(1, int(current_max_depth * 100)): # 精度100
            depth /= 100
            target_x = player_x + cos_a * depth
            target_y = player_y + sin_a * depth
            
            # 撞墙检测
            if world_map[int(target_x)][int(target_y)] == 1:
                # 修正鱼眼效应
                depth *= math.cos(player_angle - angle)
                
                # 计算墙高
                proj_height = min(int(TILE_SIZE * 4 / (depth + 0.0001)), HEIGHT * 2)
                
                # --- 贴图映射 (Texture Mapping) ---
                hit_x = target_x - int(target_x)
                hit_y = target_y - int(target_y)
                
                # 确定纹理的X坐标
                if abs(hit_x - 0.5) > abs(hit_y - 0.5):
                    tex_x = int(hit_y * TILE_SIZE)
                else:
                    tex_x = int(hit_x * TILE_SIZE)
                
                # 截取纹理并缩放
                wall_column = wall_texture.subsurface((tex_x, 0, 1, TILE_SIZE))
                wall_column = pygame.transform.scale(wall_column, (SCALE, int(proj_height)))
                
                # 绘制墙壁
                wall_y = (HEIGHT - proj_height) // 2
                screen.blit(wall_column, (ray * SCALE, wall_y))
                
                # --- 距离阴影 (Fog/Shading) ---
                # 距离越远越黑，模拟黑暗环境
                shade_intensity = int(depth * 255 / (current_max_depth * 0.8))
                if shade_intensity > 255: shade_intensity = 255
                if shade_intensity < 0: shade_intensity = 0
                
                # 绘制黑色遮罩
                shade_surface = pygame.Surface((SCALE, int(proj_height)))
                shade_surface.set_alpha(shade_intensity)
                shade_surface.fill(BLACK)
                screen.blit(shade_surface, (ray * SCALE, wall_y))
                
                break # 这条射线结束

def update_enemy():
    """简单的幽灵AI：穿墙直线追踪"""
    global enemy_x, enemy_y
    dx = player_x - enemy_x
    dy = player_y - enemy_y
    dist = math.sqrt(dx*dx + dy*dy)
    
    if dist > 0.5:
        enemy_x += (dx / dist) * enemy_speed
        enemy_y += (dy / dist) * enemy_speed
    return dist

def draw_heartbeat_overlay(dist):
    """心跳红屏与距离提示"""
    # 危险距离阈值：10米内开始有反应
    if dist < 10.0:
        # 计算基础红色强度 (距离越近越红)
        base_alpha = int((1 - dist / 10.0) * 100)
        
        # 心跳搏动效果
        # 距离越近，心跳越快 (频率增加)
        pulse_speed = 0.005 + (10.0 - dist) * 0.002 
        pulse = (math.sin(pygame.time.get_ticks() * pulse_speed) + 1) / 2 # 0到1之间
        
        # 最终透明度
        final_alpha = base_alpha + int(pulse * 60)
        final_alpha = min(200, max(0, final_alpha))
        
        # 绘制全屏红色遮罩
        overlay = pygame.Surface((WIDTH, HEIGHT))
        overlay.fill(RED)
        overlay.set_alpha(final_alpha)
        screen.blit(overlay, (0, 0))
        
        # 屏幕下方的距离提示文字
        # 只有很近的时候才显示文字，增加恐慌感
        if dist < 8.0:
            color_val = 255 if pulse > 0.5 else 150 # 文字也会闪烁
            text = font_hud.render(f"ENTITY DISTANCE: {dist:.2f}m", True, (color_val, 0, 0))
            text_rect = text.get_rect(center=(WIDTH//2, HEIGHT - 50))
            screen.blit(text, text_rect)

def draw_minimap():
    """左上角小地图"""
    size = WIDTH // 5
    scale = size / MAP_SIZE
    
    # 半透明背景
    s = pygame.Surface((size, size))
    s.set_alpha(100)
    s.fill(BLACK)
    screen.blit(s, (0,0))
    
    # 墙壁
    for x in range(MAP_SIZE):
        for y in range(MAP_SIZE):
            if world_map[x][y] == 1:
                pygame.draw.rect(screen, (100, 100, 100), (x * scale, y * scale, scale, scale))
    
    # 玩家
    pygame.draw.circle(screen, BLUE, (int(player_x * scale), int(player_y * scale)), 3)
    
    # 出口 (绿色方块)
    ex, ey = exit_pos
    pygame.draw.rect(screen, GREEN, ((ex-0.5)*scale, (ey-0.5)*scale, scale, scale))
    
    # 敌人 (仅在小地图显示红点，增加压迫感)
    pygame.draw.circle(screen, RED, (int(enemy_x * scale), int(enemy_y * scale)), 3)

# --- 主循环 ---
running = True
game_state = "PLAYING" # PLAYING, WIN, LOSE

while running:
    clock.tick(60)
    
    # 绘制背景 (天花板和地板)
    # 天花板：深红黑色
    pygame.draw.rect(screen, (20, 5, 5), (0, 0, WIDTH, HEIGHT//2))
    # 地板：深灰色，带渐变模拟
    pygame.draw.rect(screen, (15, 15, 15), (0, HEIGHT//2, WIDTH, HEIGHT//2))

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        # 按空格键重置游戏
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE and game_state != "PLAYING":
                # 重置逻辑
                player_x, player_y = 1.5, 1.5
                enemy_x, enemy_y = MAP_SIZE - 2.5, MAP_SIZE - 2.5
                game_state = "PLAYING"

    if game_state == "PLAYING":
        # 1. 玩家移动
        keys = pygame.key.get_pressed()
        if keys[pygame.K_a]: player_angle -= 0.05
        if keys[pygame.K_d]: player_angle += 0.05
        
        move_speed = 0.05
        # 简单的碰撞检测
        if keys[pygame.K_w]:
            new_x = player_x + math.cos(player_angle) * move_speed
            new_y = player_y + math.sin(player_angle) * move_speed
            if world_map[int(new_x)][int(player_y)] == 0: player_x = new_x
            if world_map[int(player_x)][int(new_y)] == 0: player_y = new_y
        if keys[pygame.K_s]:
            new_x = player_x - math.cos(player_angle) * move_speed
            new_y = player_y - math.sin(player_angle) * move_speed
            if world_map[int(new_x)][int(player_y)] == 0: player_x = new_x
            if world_map[int(player_x)][int(new_y)] == 0: player_y = new_y

        # 2. 敌人AI更新
        dist_to_enemy = update_enemy()
        
        # 3. 渲染3D场景
        cast_rays()
        
        # 4. 恐怖UI反馈 (心跳红屏)
        draw_heartbeat_overlay(dist_to_enemy)
        
        # 5. 小地图
        draw_minimap()

        # 6. 判定逻辑
        # 失败判定：被抓到
        if dist_to_enemy < 0.5:
            game_state = "LOSE"
        
        # 胜利判定：到达撤离点 (范围已扩大到 1.5)
        ex, ey = exit_pos
        dist_to_exit = math.sqrt((player_x - ex)**2 + (player_y - ey)**2)
        if dist_to_exit < 1.5:
            game_state = "WIN"

    elif game_state == "WIN":
        screen.fill(BLACK)
        text = font_end.render("ESCAPED!", True, GREEN)
        sub = font_hud.render("Press SPACE to play again", True, WHITE)
        screen.blit(text, (WIDTH//2 - text.get_width()//2, HEIGHT//2 - 50))
        screen.blit(sub, (WIDTH//2 - sub.get_width()//2, HEIGHT//2 + 20))
        
    elif game_state == "LOSE":
        # 死亡画面
        overlay = pygame.Surface((WIDTH, HEIGHT))
        overlay.fill(DARK_RED)
        overlay.set_alpha(200)
        screen.blit(overlay, (0,0))
        
        text = font_end.render("YOU DIED", True, BLACK)
        sub = font_hud.render("The entity caught you. Press SPACE.", True, WHITE)
        screen.blit(text, (WIDTH//2 - text.get_width()//2, HEIGHT//2 - 50))
        screen.blit(sub, (WIDTH//2 - sub.get_width()//2, HEIGHT//2 + 20))

    pygame.display.flip()

pygame.quit()