import pygame
import random
import sys

pygame.init()
WIDTH, HEIGHT = 900, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("毕业设计：无限NPC赛车")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 36)

# ================= 常量 =================
GREEN = (34, 139, 34)
GRAY = (40, 40, 40)
LANE_CENTER = WIDTH // 2
LANE_WIDTH = 200

# ================= 载具父类 =================


class Vehicle:
    def __init__(self, x, y, w, h, hp, speed, color):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.hp = hp
        self.speed = speed
        self.color = color

    def update(self):
        pass

    def draw(self):
        pygame.draw.rect(screen, self.color, (self.x, self.y, self.w, self.h))

# ================= 玩家 =================


class Player(Vehicle):
    def __init__(self, vtype):
        if vtype == "truck":
            super().__init__(LANE_CENTER-25, HEIGHT-120, 50, 80, 5, 3, (70, 70, 70))
        else:
            super().__init__(LANE_CENTER-20, HEIGHT-120, 40, 60, 2, 6, (30, 144, 255))

        self.shield = False
        self.boost = 0

    def update(self, keys):
        if keys[pygame.K_LEFT]:
            self.x -= self.speed
        if keys[pygame.K_RIGHT]:
            self.x += self.speed

        # ✅ 边界限制（不能出地图）
        self.x = max(LANE_CENTER-LANE_WIDTH//2,
                     min(self.x, LANE_CENTER+LANE_WIDTH//2-self.w))

        if self.boost > 0:
            self.boost -= 1

# ================= NPC（无限生成） =================


class NPC(Vehicle):
    def __init__(self):
        super().__init__(
            LANE_CENTER - 20 + random.choice([-60, 0, 60]),
            random.randint(-300, -60),
            40, 60, 1, random.uniform(3, 6), (220, 20, 60)
        )

    def update(self):
        self.y += self.speed
        if self.y > HEIGHT:
            self.y = random.randint(-300, -60)
            self.x = LANE_CENTER - 20 + random.choice([-60, 0, 60])

# ================= 道具（带模型） =================


class Item:
    def __init__(self):
        self.x = LANE_CENTER + random.choice([-60, 0, 60])
        self.y = -60
        self.type = random.choice(["boost", "shield", "attack"])

    def update(self):
        self.y += 4

    def draw(self):
        if self.type == "boost":
            pygame.draw.polygon(screen, (255, 215, 0),
                                [(self.x+15, self.y), (self.x, self.y+30), (self.x+30, self.y+30)])
        elif self.type == "shield":
            pygame.draw.circle(screen, (138, 43, 226),
                               (self.x+15, self.y+15), 14, 3)
        elif self.type == "attack":
            pygame.draw.line(screen, (255, 140, 0),
                             (self.x+15, self.y), (self.x+15, self.y+30), 5)

# ================= 载具选择 =================


def select_vehicle():
    sel = 0
    while True:
        screen.fill((20, 20, 30))
        screen.blit(font.render("选择载具", True, (255, 255, 255)),
                    (WIDTH//2-80, 120))

        screen.blit(font.render("小汽车（高速）", True,
                                (255, 255, 0) if sel == 0 else (255, 255, 255)), (WIDTH//2-100, 260))
        screen.blit(font.render("卡车（高生命）", True,
                                (255, 255, 0) if sel == 1 else (255, 255, 255)), (WIDTH//2-100, 340))

        pygame.display.flip()

        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if e.type == pygame.KEYDOWN:
                if e.key == pygame.K_UP:
                    sel = (sel-1) % 2
                if e.key == pygame.K_DOWN:
                    sel = (sel+1) % 2
                if e.key == pygame.K_RETURN:
                    return "truck" if sel == 1 else "car"

# ================= 主程序 =================


def main(vtype):
    player = Player(vtype)
    npcs = [NPC() for _ in range(5)]
    items = []
    score = 0
    game_over = False

    while True:
        clock.tick(60)
        screen.fill(GREEN)
        pygame.draw.rect(screen, GRAY, (LANE_CENTER -
                         LANE_WIDTH//2, 0, LANE_WIDTH, HEIGHT))

        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if e.type == pygame.KEYDOWN:
                if game_over and e.key == pygame.K_r:
                    player = Player(vtype)
                    npcs = [NPC() for _ in range(5)]
                    items = []
                    score = 0
                    game_over = False

        if not game_over:
            keys = pygame.key.get_pressed()
            player.update(keys)

            # ✅ 无限 NPC
            for n in npcs:
                n.update()
                n.draw()
                if abs(player.x-n.x) < 35 and abs(player.y-n.y) < 55:
                    if player.shield:
                        player.shield = False
                    else:
                        player.hp -= 1
                    if player.hp <= 0:
                        game_over = True

            # ✅ 无限道具
            if random.random() < 0.01:
                items.append(Item())

            for it in items[:]:
                it.update()
                it.draw()
                if abs(player.x-it.x) < 35 and abs(player.y-it.y) < 55:
                    if it.type == "boost":
                        player.boost = 180
                    elif it.type == "shield":
                        player.shield = True
                    elif it.type == "attack":
                        for n in npcs:
                            if n.y < player.y:
                                n.y = -60
                                score += 1
                    items.remove(it)

            player.draw()
            screen.blit(font.render(
                f"HP:{player.hp}", True, (255, 215, 0)), (20, 20))
            screen.blit(font.render(
                f"Score:{score}", True, (255, 255, 255)), (20, 60))
        else:
            screen.blit(font.render("游戏结束 按 R 重开", True, (255, 255, 255)),
                        (WIDTH//2-180, HEIGHT//2))

        pygame.display.flip()


# ================= 入口 =================
if __name__ == "__main__":
    vtype = select_vehicle()
    main(vtype)
