找回密码
 立即注册
搜索
热搜: 活动 交友
查看: 25|回复: 0

AI + 人工调试 一年半的完整程序

[复制链接]

2

主题

0

回帖

79

积分

初级程序员

积分
79
发表于 昨天 22:26 | 显示全部楼层 |阅读模式
上个帖子答应了要发这个迭代许久的starship游戏
需注意:
1. 感想成长会在下一个帖子发布,看过的记得在评论区里面踢一下我,这样我不会忘记
2. 该程序没有完全迭代成功。还有portal功能没有完善。本来想做成phira的,现在发现即使是有AI也还早着呢
3. 参与该项目的AI:我,deepseek v3,chatGPT v5,claudecode的一个版本我已经忘了是哪个版本了。
4. 创始时间:我上初级班之前大约半年,所以好像还不止一年半但我懒得数了 :P

以下为1776行的完整代码
前提条件:
1. pygame下载
2. 刘老师以前那个sound的文件夹中的一下文件:
├── biu.wav├── boom2.wav├── mariocoin.wav├── mariodie.wav├── plantzombie.mp3├── missionimpossible.mp3├── music.mp3 【蔡徐坤音乐dddd】【很可惜论坛好不能append .wav和.py然后我截屏这个代码又太累了】
需要把这几个和你的这个py以及生成的俩.json文件放在同一个文件夹中。
如果你们需要的静音版(让你们写作业的时候偷偷玩)或者以前的超级石山代码或是我纯人工的版本的话,可以在评论区叫我。我会尽量塞到下一个帖子里面。

希望你们喜欢!也可以把你们的想法扔到评论区里面!

import pygame
import random
import sys
import json
import os
import math
from pygame import mixer
from pathlib import Path

# Initialize pygame
pygame.init()
mixer.init()

# Screen dimensions
WIDTH, HEIGHT = 1400, 830
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Galactic Space Explorer")

# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)
PURPLE = (128, 0, 128)
ORANGE = (255, 165, 0)
GOLD = (255, 215, 0)
CYAN = (0, 255, 255)
MAGENTA = (255, 0, 255)
DARK_PURPLE = (75, 0, 130)
SPIKE_GOLD = (255, 215, 0)
BLOOD_RED = (139, 0, 0)
HEAL_GREEN = (50, 255, 50)
IRON_RED = (255, 50, 50)
BRIGHT_RED = (255, 0, 0)
DARK_GREEN = (0, 100, 40)
STEEL_BLUE = (70, 130, 180)
ROSE_GOLD = (183, 110, 121)
NEBULA_PURPLE = (102, 51, 153)
PHANTOM_GRAY = (80, 80, 100)
PORTAL_BLUE = (50, 100, 200)
PORTAL_PURPLE = (150, 50, 200)

# Fonts
font_large = pygame.font.SysFont('freesansbold', 70, bold=True)
font_medium = pygame.font.SysFont('freesansbold', 45, bold=False)
font_small = pygame.font.SysFont('freesansbold', 28, bold=False)
font_tiny = pygame.font.SysFont('freesansbold', 22, bold=False)

# Load sounds
laser_sound = mixer.Sound('biu.wav')
laser_sound.set_volume(0.15)
explosion_sound = mixer.Sound('boom2.wav')
explosion_sound.set_volume(0.2)
powerup_sound = mixer.Sound('mariocoin.wav')
death_sound = mixer.Sound('mariodie.wav')
death_sound.set_volume(0.5)

# ---- Storage files ----
BASE_DIR = Path(__file__).parent
SETTINGS_FILE = BASE_DIR / "starship_settings.json"
HIGHSCORE_FILE = BASE_DIR / "starship_highscore.json"

# ---- Skins for starship ----
SKINS = [
    {"name": "Classic Blue", "unlock": 0, "color": BLUE, "accent": WHITE, "laser_color": (0, 100, 255), "booster_color": (0, 150, 255)},
    {"name": "Red Phoenix", "unlock": 5, "color": RED, "accent": YELLOW, "laser_color": (255, 50, 50), "booster_color": (255, 80, 0)},
    {"name": "Golden Eagle", "unlock": 10, "color": (255, 215, 0), "accent": (255, 100, 0), "laser_color": (255, 200, 0), "booster_color": (255, 150, 0)},
    {"name": "Purple Nebula", "unlock": 15, "color": PURPLE, "accent": (200, 100, 255), "laser_color": (160, 50, 255), "booster_color": (180, 0, 255)},
    {"name": "Cyan Storm", "unlock": 20, "color": (0, 255, 255), "accent": WHITE, "laser_color": (0, 200, 200), "booster_color": (0, 100, 200)},
    {"name": "Lava Core", "unlock": 30, "color": (255, 60, 0), "accent": (255, 200, 0), "laser_color": (255, 80, 0), "booster_color": (255, 30, 0)},
    {"name": "Emerald", "unlock": 40, "color": DARK_GREEN, "accent": (0, 255, 100), "laser_color": (0, 200, 80), "booster_color": (0, 150, 50)},
    {"name": "Arctic Ice", "unlock": 50, "color": (200, 230, 255), "accent": WHITE, "laser_color": (150, 200, 255), "booster_color": (100, 150, 200)},
    {"name": "Dark Matter", "unlock": 60, "color": (50, 50, 80), "accent": (150, 150, 200), "laser_color": (100, 100, 150), "booster_color": (200, 50, 200)},
    {"name": "Solar Flare", "unlock": 75, "color": (255, 140, 0), "accent": (255, 255, 100), "laser_color": (255, 120, 0), "booster_color": (255, 200, 0)},
    {"name": "Cosmic Pink", "unlock": 90, "color": (255, 100, 200), "accent": (255, 200, 255), "laser_color": (255, 80, 180), "booster_color": (255, 50, 150)},
    {"name": "Platinum", "unlock": 110, "color": (192, 192, 192), "accent": WHITE, "laser_color": (180, 180, 180), "booster_color": (100, 100, 100)},
    {"name": "Steel Phantom", "unlock": 125, "color": STEEL_BLUE, "accent": (150, 150, 150), "laser_color": (100, 150, 200), "booster_color": (50, 100, 150)},
    {"name": "Rose Gold", "unlock": 140, "color": ROSE_GOLD, "accent": GOLD, "laser_color": (200, 100, 120), "booster_color": (150, 80, 90)},
    {"name": "Nebula Core", "unlock": 160, "color": NEBULA_PURPLE, "accent": MAGENTA, "laser_color": (150, 50, 200), "booster_color": (200, 50, 150)},
    {"name": "Phantom", "unlock": 180, "color": PHANTOM_GRAY, "accent": CYAN, "laser_color": (100, 150, 200), "booster_color": (60, 80, 100)},
    {"name": "Midnight Sun", "unlock": 200, "color": (30, 30, 40), "accent": ORANGE, "laser_color": (255, 100, 0), "booster_color": (200, 80, 0)},
]

# ---- High score functions ----
def load_highscore():
    if HIGHSCORE_FILE.exists():
        data = json.loads(HIGHSCORE_FILE.read_text(encoding="utf-8"))
        return data.get("highscore", 0)
    return 0

def save_highscore(score):
    current_high = load_highscore()
    if score > current_high:
        HIGHSCORE_FILE.write_text(json.dumps({"highscore": score}, indent=2), encoding="utf-8")
        return True
    return False

# ---- Default settings ----
DEFAULT_SETTINGS = {"skin": "Classic Blue"}

def load_settings():
    if SETTINGS_FILE.exists():
        return json.loads(SETTINGS_FILE.read_text(encoding="utf-8"))
    return DEFAULT_SETTINGS.copy()

def save_settings(settings):
    SETTINGS_FILE.write_text(json.dumps(settings, indent=2), encoding="utf-8")

# Load saved skin and high score
settings = load_settings()
saved_skin_name = settings.get("skin", "Classic Blue")
high_score = load_highscore()

# Find the saved skin or default to first
selected_skin = next((s for s in SKINS if s["name"] == saved_skin_name), SKINS[0])
current_skin_index = SKINS.index(selected_skin)

# ========== MUSIC MANAGEMENT ==========
def play_menu_music():
    mixer.music.stop()
    mixer.music.load('plantzombie.mp3')
    mixer.music.set_volume(0.5)
    mixer.music.play(-1)

def play_game_music():
    mixer.music.stop()
    mixer.music.load('missionimpossible.mp3')
    mixer.music.set_volume(0.5)
    mixer.music.play(-1)

def play_godmode_music():
    mixer.music.stop()
    mixer.music.load('music.mp3')
    mixer.music.set_volume(0.7)
    mixer.music.play(-1)

def stop_music():
    mixer.music.stop()

# Start with menu music
play_menu_music()

# ========== HELPER FUNCTIONS ==========
def draw_text(text, font, color, x, y, center=True):
    text_surface = font.render(text, True, color)
    if center:
        screen.blit(text_surface, (x - text_surface.get_width()//2, y - text_surface.get_height()//2))
    else:
        screen.blit(text_surface, (x, y))

def draw_button(text, x, y, width, height, inactive_color, active_color, action=None):
    mouse = pygame.mouse.get_pos()
    click = pygame.mouse.get_pressed()

    button_rect = pygame.Rect(x - width//2, y - height//2, width, height)
    is_hover = button_rect.collidepoint(mouse)

    if is_hover:
        pygame.draw.rect(screen, active_color, button_rect, border_radius=10)
        pygame.draw.rect(screen, WHITE, button_rect, 3, border_radius=10)
        draw_text(text, font_medium, BLACK, x, y)
        if click[0] == 1:
            return action
    else:
        pygame.draw.rect(screen, inactive_color, button_rect, border_radius=10)
        pygame.draw.rect(screen, WHITE, button_rect, 3, border_radius=10)
        draw_text(text, font_medium, BLACK, x, y)

    return None

def draw_starfield():
    for _ in range(12):
        pygame.draw.circle(screen, WHITE,
                         (random.randint(0, WIDTH), random.randint(0, HEIGHT)),
                         random.randint(1, 2))

def get_rainbow_color(frame):
    colors = [
        (255, 0, 0), (255, 165, 0), (255, 255, 0), (0, 255, 0),
        (0, 255, 255), (0, 0, 255), (128, 0, 255), (255, 0, 255)
    ]
    return colors[frame % len(colors)]

def draw_high_tech_border():
    """Thicker HUD-style border with HALO feel"""
    for i in range(1, 6):
        alpha = max(0, 60 - i * 10)
        glow_rect = pygame.Rect(i-1, i-1, WIDTH - (i-1)*2, HEIGHT - (i-1)*2)
        pygame.draw.rect(screen, (0, 150, 255, alpha), glow_rect, 2)

    pygame.draw.rect(screen, CYAN, (3, 3, WIDTH - 6, HEIGHT - 6), 4)
    pygame.draw.rect(screen, (100, 200, 255, 100), (8, 8, WIDTH - 16, HEIGHT - 16), 2)

    corner_size = 25
    bracket_thick = 4
    corners = [(4, 4), (WIDTH - 4, 4), (4, HEIGHT - 4), (WIDTH - 4, HEIGHT - 4)]
    for x, y in corners:
        if x == 4:
            pygame.draw.line(screen, CYAN, (x, y), (x + corner_size, y), bracket_thick)
            pygame.draw.line(screen, CYAN, (x, y), (x, y + corner_size), bracket_thick)
            pygame.draw.line(screen, (0, 200, 255), (x + 3, y + 3), (x + corner_size - 3, y + 3), 2)
            pygame.draw.line(screen, (0, 200, 255), (x + 3, y + 3), (x + 3, y + corner_size - 3), 2)
        else:
            pygame.draw.line(screen, CYAN, (x - corner_size, y), (x, y), bracket_thick)
            pygame.draw.line(screen, CYAN, (x, y), (x, y + corner_size), bracket_thick)
            pygame.draw.line(screen, (0, 200, 255), (x - corner_size + 3, y + 3), (x - 3, y + 3), 2)
            pygame.draw.line(screen, (0, 200, 255), (x - 3, y + 3), (x - 3, y + corner_size - 3), 2)

# ========== PHIGROS PORTAL CLASS ==========
class PhigrosPortal:
    def __init__(self, x, y):
        self.rect = pygame.Rect(x - 50, y - 50, 100, 100)
        self.x = x
        self.y = y
        self.angle = 0
        self.active = True
        self.pulse = 0
        self.pulse_direction = 1
        self.spawn_time = pygame.time.get_ticks()
        self.lifetime = 15000

    def update(self):
        self.angle += 8
        self.pulse += self.pulse_direction * 3
        if self.pulse > 30:
            self.pulse_direction = -1
        elif self.pulse < 0:
            self.pulse_direction = 1

        if pygame.time.get_ticks() - self.spawn_time > self.lifetime:
            return False
        return self.active

    def draw(self, screen):
        # Outer glow
        for i in range(5):
            radius = 50 + i * 2 + self.pulse // 3
            alpha = max(0, 70 - i * 12)
            pygame.draw.circle(screen, (PORTAL_BLUE[0], PORTAL_BLUE[1], PORTAL_BLUE[2]),
                             (int(self.x), int(self.y)), radius, 3)

        # Main rings
        for ring in range(3):
            radius = 42 - ring * 4
            pygame.draw.circle(screen, PORTAL_BLUE, (int(self.x), int(self.y)), radius, 3)
            pygame.draw.circle(screen, PORTAL_PURPLE, (int(self.x), int(self.y)), radius - 4, 2)

        # Rotating outer orbs
        for i in range(8):
            rad = math.radians(self.angle + i * 45)
            px = self.x + math.cos(rad) * 48
            py = self.y + math.sin(rad) * 48
            pygame.draw.circle(screen, CYAN, (int(px), int(py)), 4)
            pygame.draw.circle(screen, WHITE, (int(px), int(py)), 2)

        # Rotating inner orbs
        for i in range(6):
            rad = math.radians(-self.angle * 1.5 + i * 60)
            px = self.x + math.cos(rad) * 28
            py = self.y + math.sin(rad) * 28
            pygame.draw.circle(screen, MAGENTA, (int(px), int(py)), 3)

        # Bright core
        pygame.draw.circle(screen, WHITE, (int(self.x), int(self.y)), 20)
        pygame.draw.circle(screen, (200, 200, 255), (int(self.x), int(self.y)), 12)
        pygame.draw.circle(screen, PORTAL_BLUE, (int(self.x), int(self.y)), 6)

        # Core pulse
        core_glow = 12 + self.pulse // 3
        pygame.draw.circle(screen, (255, 255, 200), (int(self.x), int(self.y)), core_glow, 2)

        # Text
        draw_text("PORTAL", font_small, GOLD, self.x, self.y - 50)
        draw_text("PRESS SPACE", font_tiny, CYAN, self.x, self.y + 58)

        # Timer bar
        time_left = max(0, (self.lifetime - (pygame.time.get_ticks() - self.spawn_time)) // 1000)
        bar_width = 70
        bar_height = 5
        progress_width = bar_width * (time_left / 15)
        pygame.draw.rect(screen, (50, 50, 80), (self.x - bar_width//2, self.y + 72, bar_width, bar_height))
        pygame.draw.rect(screen, CYAN, (self.x - bar_width//2, self.y + 72, progress_width, bar_height))

    def draw_minimap_indicator(self, screen):
        center_x, center_y = WIDTH // 2, HEIGHT // 2
        dx = self.x - center_x
        dy = self.y - center_y
        distance = math.sqrt(dx*dx + dy*dy)

        if distance > 0:
            dx /= distance
            dy /= distance

        margin = 60
        indicator_x = center_x + dx * (WIDTH//2 - margin)
        indicator_y = center_y + dy * (HEIGHT//2 - margin)

        indicator_x = max(margin, min(WIDTH - margin, indicator_x))
        indicator_y = max(margin, min(HEIGHT - margin, indicator_y))

        arrow_size = 12 + self.pulse // 6
        points = [
            (indicator_x, indicator_y - arrow_size),
            (indicator_x - arrow_size//2, indicator_y + arrow_size//2),
            (indicator_x - arrow_size//4, indicator_y + arrow_size//4),
            (indicator_x - arrow_size//4, indicator_y + arrow_size),
            (indicator_x, indicator_y + arrow_size - 3),
            (indicator_x + arrow_size//4, indicator_y + arrow_size),
            (indicator_x + arrow_size//4, indicator_y + arrow_size//4),
            (indicator_x + arrow_size//2, indicator_y + arrow_size//2),
        ]
        pygame.draw.polygon(screen, MAGENTA, points)
        pygame.draw.polygon(screen, CYAN, points, 2)

class PhigrosNote:
    def __init__(self, x, target_y, lane):
        self.x = x
        self.y = -40
        self.target_y = target_y
        self.speed = 6.5
        self.hit = False
        self.missed = False
        self.lane = lane
        self.size = 14
        self.glow = 0
        self.glow_dir = 1

    def update(self):
        self.y += self.speed
        self.glow += self.glow_dir * 0.5
        if self.glow > 6:
            self.glow_dir = -1
        elif self.glow < 0:
            self.glow_dir = 1
        return self.y > HEIGHT + 60

    def draw(self, screen):
        if not self.hit and not self.missed:
            for i in range(3):
                alpha = 100 - i * 25
                pygame.draw.circle(screen, (255, 200, 0), (int(self.x), int(self.y)), self.size + i*2 + int(self.glow))
            pygame.draw.circle(screen, YELLOW, (int(self.x), int(self.y)), self.size)
            pygame.draw.circle(screen, ORANGE, (int(self.x), int(self.y)), self.size - 3)
            pygame.draw.line(screen, WHITE, (self.x - 6, self.y), (self.x + 6, self.y), 3)
            pygame.draw.line(screen, WHITE, (self.x, self.y - 6), (self.x, self.y + 6), 3)

def phigros_minigame(player, portal):
    clock = pygame.time.Clock()
    notes = []
    score_gain = 0
    health_loss = 0
    beat_interval = 40
    next_beat = beat_interval
    judgement_line_y = HEIGHT // 2 + 100
    note_positions = [WIDTH//4, WIDTH//2, 3*WIDTH//4]
    combo = 0
    max_combo = 0
    perfect_count = 0
    good_count = 0
    miss_count = 0

    original_pos = player.rect.center
    player.rect.center = (WIDTH//2, HEIGHT//2)

    start_time = pygame.time.get_ticks()
    duration = 30000

    # Pause game music
    mixer.music.pause()

    while (pygame.time.get_ticks() - start_time) < duration:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE or event.key == pygame.K_UP:
                    hit = False
                    for note in notes[:]:
                        if not note.hit and not note.missed:
                            distance = abs(note.y - judgement_line_y)
                            if distance < 45:
                                note.hit = True
                                if distance < 15:
                                    score_gain += 100
                                    combo += 1
                                    perfect_count += 1
                                elif distance < 30:
                                    score_gain += 60
                                    combo += 1
                                    good_count += 1
                                else:
                                    score_gain += 30
                                    combo += 1
                                if combo > max_combo:
                                    max_combo = combo
                                try:
                                    powerup_sound.play()
                                except:
                                    pass
                                notes.remove(note)
                                hit = True
                                break
                    if not hit:
                        combo = 0

        next_beat -= 1
        if next_beat <= 0:
            lane = random.randint(0, 2)
            pos_x = note_positions[lane]
            notes.append(PhigrosNote(pos_x, judgement_line_y, lane))
            next_beat = beat_interval
            beat_interval = max(20, beat_interval - 0.5)

        for note in notes[:]:
            if note.update():
                if not note.hit and not note.missed:
                    note.missed = True
                    health_loss += 5
                    miss_count += 1
                    combo = 0
                notes.remove(note)

        # Draw rhythm game
        screen.fill((5, 5, 20))

        for i in range(3):
            alpha = 100 - i * 30
            pygame.draw.line(screen, (0, 255, 255),
                           (0, judgement_line_y + i*2), (WIDTH, judgement_line_y + i*2), 3)
        pygame.draw.line(screen, CYAN, (0, judgement_line_y), (WIDTH, judgement_line_y), 4)
        pygame.draw.line(screen, WHITE, (0, judgement_line_y - 3), (WIDTH, judgement_line_y - 3), 2)
        pygame.draw.line(screen, WHITE, (0, judgement_line_y + 3), (WIDTH, judgement_line_y + 3), 2)

        for i, x in enumerate(note_positions):
            pygame.draw.line(screen, (50, 50, 100), (x, 0), (x, HEIGHT), 3)

        for note in notes:
            note.draw(screen)

        draw_text("PHIGROS PORTAL", font_medium, GOLD, WIDTH//2, 50)
        draw_text("Press SPACE or UP when notes hit the line", font_small, WHITE, WIDTH//2, 100)

        stats_y = 150
        draw_text(f"Score: +{score_gain}", font_small, GREEN, WIDTH//2 - 200, stats_y, False)
        draw_text(f"Combo: x{combo}", font_small, YELLOW, WIDTH//2, stats_y, False)
        draw_text(f"Max Combo: x{max_combo}", font_small, ORANGE, WIDTH//2 + 200, stats_y, False)

        draw_text(f"Perfect: {perfect_count}", font_small, GREEN, WIDTH//2 - 200, stats_y + 35, False)
        draw_text(f"Good: {good_count}", font_small, YELLOW, WIDTH//2, stats_y + 35, False)
        draw_text(f"Miss: {miss_count}", font_small, RED, WIDTH//2 + 200, stats_y + 35, False)
        draw_text(f"Miss Penalty: -{health_loss} HP", font_small, BLOOD_RED, WIDTH//2, stats_y + 70)

        time_left = max(0, (duration - (pygame.time.get_ticks() - start_time)) // 1000)
        draw_text(f"Time left: {time_left}s", font_small, MAGENTA, WIDTH//2, stats_y + 110)

        player.draw(screen)
        draw_high_tech_border()

        pygame.display.flip()
        clock.tick(60)

    # Resume game music
    mixer.music.unpause()

    player.score += score_gain
    player.health -= health_loss
    player.rect.center = original_pos
    return score_gain, health_loss

# ========== LASER CLASSES ==========
class AutoAimLaser:
    def __init__(self, x, y, target_enemy, target_boss, skin_color):
        self.x = x
        self.y = y
        self.target_enemy = target_enemy
        self.target_boss = target_boss
        self.speed = 18
        self.color = IRON_RED
        self.alive = True
        self.rect = pygame.Rect(x - 3, y - 3, 6, 6)
        self.trail = [(x, y)]
        self.trail_length = 5
        self.life_frames = 0

    def get_target_position(self):
        if self.target_enemy is not None:
            try:
                if hasattr(self.target_enemy, 'rect') and self.target_enemy.rect is not None:
                    return (self.target_enemy.rect.centerx, self.target_enemy.rect.centery)
            except:
                pass

        if self.target_boss is not None:
            try:
                if hasattr(self.target_boss, 'rect') and self.target_boss.rect is not None:
                    return (self.target_boss.rect.centerx, self.target_boss.rect.centery)
            except:
                pass
        return None

    def update(self):
        self.life_frames += 1
        if self.life_frames > 90:
            return True

        target_pos = self.get_target_position()
        if target_pos is None:
            return True

        dx = target_pos[0] - self.x
        dy = target_pos[1] - self.y
        distance = math.sqrt(dx*dx + dy*dy)

        if distance > 0:
            self.x += (dx / distance) * self.speed
            self.y += (dy / distance) * self.speed

        self.trail.append((self.x, self.y))
        if len(self.trail) > self.trail_length:
            self.trail.pop(0)

        self.rect.x = int(self.x - 3)
        self.rect.y = int(self.y - 3)

        return (self.rect.bottom < 0 or self.rect.top > HEIGHT or
                self.rect.right < 0 or self.rect.left > WIDTH)

    def draw(self, screen):
        for i, pos in enumerate(self.trail):
            trail_color = (min(255, self.color[0] + 50), self.color[1], self.color[2])
            pygame.draw.circle(screen, trail_color, (int(pos[0]), int(pos[1])), 2)

        pygame.draw.circle(screen, self.color, (int(self.x), int(self.y)), 4)
        if self.target_enemy:
            dx = self.target_enemy.rect.centerx - self.x
            dy = self.target_enemy.rect.centery - self.y
            dist = math.sqrt(dx*dx + dy*dy)
            if dist > 0:
                tip_x = self.x + (dx / dist) * 6
                tip_y = self.y + (dy / dist) * 6
                pygame.draw.circle(screen, BRIGHT_RED, (int(tip_x), int(tip_y)), 2)

class Laser:
    def __init__(self, x, y, color):
        self.rect = pygame.Rect(x - 3, y, 6, 20)
        self.speed = 12
        self.color = color
        self.trail = [(x, y)]
        self.life_frames = 0

    def update(self):
        self.life_frames += 1
        old_y = self.rect.y
        self.rect.y -= self.speed
        self.trail.append((self.rect.centerx, old_y))
        if len(self.trail) > 3:
            self.trail.pop(0)
        if self.life_frames > 100:
            return True
        return self.rect.bottom < 0

    def draw(self, screen):
        for i, pos in enumerate(self.trail):
            trail_color = (min(255, self.color[0] + 50), self.color[1], self.color[2])
            pygame.draw.circle(screen, trail_color, (int(pos[0]), int(pos[1])), 2)
        pygame.draw.rect(screen, self.color, self.rect)
        pygame.draw.rect(screen, BRIGHT_RED, (self.rect.x, self.rect.y - 2, self.rect.width, 3))

class GodModeLaser:
    def __init__(self, x, y, angle, frame):
        self.rect = pygame.Rect(x - 2, y - 10, 4, 15)
        self.x = x
        self.y = y
        self.angle = angle
        self.speed = 16
        self.frame = frame
        self.color = get_rainbow_color(frame + angle)
        rad = math.radians(angle)
        self.vx = math.sin(rad) * self.speed
        self.vy = -math.cos(rad) * self.speed
        self.trail = [(x, y)]
        self.life_frames = 0

    def update(self):
        self.life_frames += 1
        old_x, old_y = self.x, self.y
        self.x += self.vx
        self.y += self.vy
        self.rect.x = int(self.x - 2)
        self.rect.y = int(self.y - 10)
        self.color = get_rainbow_color(self.frame)
        self.frame += 1
        self.trail.append((old_x, old_y))
        if len(self.trail) > 3:
            self.trail.pop(0)
        if self.life_frames > 120:
            return True
        return (self.rect.bottom < 0 or self.rect.top > HEIGHT or
                self.rect.right < 0 or self.rect.left > WIDTH)

    def draw(self, screen):
        for i, pos in enumerate(self.trail):
            trail_color = get_rainbow_color(self.frame - i)
            pygame.draw.circle(screen, trail_color, (int(pos[0]), int(pos[1])), 2)
        pygame.draw.rect(screen, self.color, self.rect)

# ========== ENEMY CLASSES ==========
class BossEnemy:
    def __init__(self):
        self.img = pygame.Surface((70, 70), pygame.SRCALPHA)
        pygame.draw.polygon(self.img, DARK_PURPLE, [(35, 0), (0, 70), (70, 70)])
        for i in range(3):
            spike_x = 10 + i * 25
            pygame.draw.polygon(self.img, SPIKE_GOLD, [(spike_x, 20), (spike_x - 5, 35), (spike_x + 5, 35)])
        pygame.draw.circle(self.img, BLOOD_RED, (35, 45), 12)
        pygame.draw.circle(self.img, BLOOD_RED, (20, 30), 8)
        pygame.draw.circle(self.img, BLOOD_RED, (50, 30), 8)
        pygame.draw.circle(self.img, RED, (25, 25), 5)
        pygame.draw.circle(self.img, RED, (45, 25), 5)
        pygame.draw.circle(self.img, WHITE, (25, 25), 2)
        pygame.draw.circle(self.img, WHITE, (45, 25), 2)

        x = random.randint(70, WIDTH - 70)
        self.rect = self.img.get_rect(center=(x, -70))
        self.speed = random.uniform(0.8, 1.5)
        self.health = 9
        self.max_health = 9
        self.shoot_cooldown = 0
        self.lasers = []
        self.score_value = 500

    def update(self, player_pos):
        self.rect.y += self.speed

        if self.shoot_cooldown <= 0:
            self.shoot(player_pos)
            self.shoot_cooldown = 45
        else:
            self.shoot_cooldown -= 1

        for laser in self.lasers[:]:
            if laser.update():
                self.lasers.remove(laser)

        return self.rect.top > HEIGHT

    def shoot(self, player_pos):
        dx = player_pos[0] - self.rect.centerx
        dy = player_pos[1] - self.rect.centery
        distance = math.sqrt(dx*dx + dy*dy)
        if distance > 0:
            dx /= distance
            dy /= distance
        self.lasers.append(BossLaser(self.rect.centerx, self.rect.centery, dx, dy))

    def draw(self, screen):
        screen.blit(self.img, self.rect)
        bar_width = 70
        bar_height = 8
        health_width = bar_width * (self.health / self.max_health)
        pygame.draw.rect(screen, RED, (self.rect.x, self.rect.y - 12, bar_width, bar_height))
        pygame.draw.rect(screen, GREEN, (self.rect.x, self.rect.y - 12, health_width, bar_height))
        for laser in self.lasers:
            laser.draw(screen)

class BossLaser:
    def __init__(self, x, y, dx, dy):
        self.rect = pygame.Rect(x - 4, y - 4, 8, 8)
        self.x = x
        self.y = y
        self.dx = dx * 10
        self.dy = dy * 10
        self.color = BLOOD_RED

    def update(self):
        self.x += self.dx
        self.y += self.dy
        self.rect.x = int(self.x - 4)
        self.rect.y = int(self.y - 4)
        return (self.rect.bottom < 0 or self.rect.top > HEIGHT or
                self.rect.right < 0 or self.rect.left > WIDTH)

    def draw(self, screen):
        pygame.draw.rect(screen, self.color, self.rect)
        pygame.draw.rect(screen, GOLD, self.rect, 2)

class Enemy:
    def __init__(self, x=None):
        self.img = pygame.Surface((40, 40))
        self.img.fill(RED)
        pygame.draw.polygon(self.img, WHITE, [(20, 40), (5, 5), (35, 5)])
        pygame.draw.circle(self.img, YELLOW, (20, 35), 3)
        if x is None:
            x = random.randint(40, WIDTH - 40)
        self.rect = self.img.get_rect(center=(x, -40))
        self.speed = random.uniform(1.0, 3.0)
        self.health = 30
        self.shoot_cooldown = random.randint(30, 100)
        self.lasers = []

    def update(self):
        self.rect.y += self.speed
        if self.shoot_cooldown > 0:
            self.shoot_cooldown -= 1
        elif random.random() < 0.02:
            self.shoot()
            self.shoot_cooldown = random.randint(60, 150)
        for laser in self.lasers[:]:
            if laser.update():
                self.lasers.remove(laser)
        return self.rect.top > HEIGHT

    def shoot(self):
        self.lasers.append(EnemyLaser(self.rect.centerx, self.rect.bottom))

    def draw(self, screen):
        screen.blit(self.img, self.rect)
        for laser in self.lasers:
            laser.draw(screen)

class EnemyLaser(Laser):
    def __init__(self, x, y):
        super().__init__(x, y, RED)
        self.rect.y = y
        self.speed = -8
        self.color = RED

class Asteroid:
    def __init__(self):
        size = random.randint(25, 75)
        self.img = pygame.Surface((size, size), pygame.SRCALPHA)
        pygame.draw.circle(self.img, (150, 150, 150), (size//2, size//2), size//2)
        crater_size = size // 5
        pygame.draw.circle(self.img, (100, 100, 100), (size//3, size//3), crater_size)
        pygame.draw.circle(self.img, (100, 100, 100), (2*size//3, 2*size//3), crater_size)
        x = random.randint(size, WIDTH - size)
        self.rect = self.img.get_rect(center=(x, -size))
        self.speed = random.uniform(1.0, 4.0)
        self.rotation = 0
        self.rotation_speed = random.uniform(-2, 2)
        self.health = size

    def update(self):
        self.rect.y += self.speed
        self.rotation += self.rotation_speed
        return self.rect.top > HEIGHT

    def draw(self, screen):
        rotated_img = pygame.transform.rotate(self.img, self.rotation)
        new_rect = rotated_img.get_rect(center=self.rect.center)
        screen.blit(rotated_img, new_rect)

class HealthRegion:
    def __init__(self):
        self.rect = pygame.Rect(WIDTH - 140, HEIGHT - 140, 120, 120)
        self.heal_cooldown = 0

    def update(self, player):
        if self.heal_cooldown > 0:
            self.heal_cooldown -= 1
        if self.rect.colliderect(player.rect) and self.heal_cooldown == 0:
            if player.health < player.max_health:
                player.health = min(player.max_health, player.health + 5)
                self.heal_cooldown = 60

    def draw(self, screen):
        s = pygame.Surface((120, 120), pygame.SRCALPHA)
        s.fill((0, 255, 0, 80))
        screen.blit(s, (WIDTH - 140, HEIGHT - 140))
        pygame.draw.rect(screen, GREEN, self.rect, 3)
        draw_text("HEAL ZONE", font_small, WHITE, WIDTH - 80, HEIGHT - 80)

class PowerUp:
    def __init__(self, x=None, y=None):
        powerup_types = ["rapid_fire", "shield", "triple_shot", "heal"]
        self.type = random.choice(powerup_types)

        colors = {
            "rapid_fire": YELLOW, "shield": BLUE, "triple_shot": PURPLE,
            "godmode": GOLD, "heal": HEAL_GREEN
        }
        self.img = pygame.Surface((30, 30))
        self.img.fill(colors[self.type])

        if self.type == "godmode":
            pygame.draw.circle(self.img, WHITE, (15, 15), 10, 2)
            pygame.draw.line(self.img, WHITE, (5, 15), (25, 15), 2)
            pygame.draw.line(self.img, WHITE, (15, 5), (15, 25), 2)
        elif self.type == "heal":
            pygame.draw.line(self.img, WHITE, (15, 5), (15, 25), 3)
            pygame.draw.line(self.img, WHITE, (5, 15), (25, 15), 3)
        elif self.type == "rapid_fire":
            pygame.draw.polygon(self.img, WHITE, [(15, 5), (8, 20), (22, 20)])

        if x is None:
            x = random.randint(25, WIDTH - 25)
        if y is None:
            y = random.randint(25, HEIGHT - 25)
        self.rect = self.img.get_rect(center=(x, y))
        self.speed = random.uniform(0.5, 1.5)
        self.lifetime = 300

    def update(self):
        self.rect.y += self.speed
        self.lifetime -= 1
        return self.rect.top > HEIGHT or self.lifetime <= 0

    def draw(self, screen):
        screen.blit(self.img, self.rect)

class Explosion:
    def __init__(self, x, y, size=1.0):
        self.particles = []
        for _ in range(25):
            angle = random.uniform(0, math.pi * 2)
            speed = random.uniform(2, 6)
            self.particles.append({
                'x': x, 'y': y,
                'dx': math.cos(angle) * speed,
                'dy': math.sin(angle) * speed,
                'size': random.randint(2, 5) * size,
                'life': random.randint(15, 35),
                'color': random.choice([RED, ORANGE, YELLOW])
            })

    def update(self):
        for particle in self.particles[:]:
            particle['x'] += particle['dx']
            particle['y'] += particle['dy']
            particle['life'] -= 1
            if particle['life'] <= 0:
                self.particles.remove(particle)
        return len(self.particles) == 0

    def draw(self, screen):
        for particle in self.particles:
            pygame.draw.circle(screen, particle['color'],
                             (int(particle['x']), int(particle['y'])), int(particle['size']))

# ========== PLAYER CLASS ==========
class Player:
    def __init__(self):
        global selected_skin
        self.skin = selected_skin
        self.img = pygame.Surface((50, 40), pygame.SRCALPHA)
        self.update_skin()
        self.rect = self.img.get_rect(center=(WIDTH//2, HEIGHT//2))
        self.speed = 7
        self.health = 100
        self.max_health = 100
        self.lasers = []
        self.laser_cooldown = 0
        self.score = 0
        self.frame_counter = 0
        self.powerups = {
            "rapid_fire": False,
            "shield": False,
            "triple_shot": False,
            "godmode": False
        }
        self.powerup_timers = {
            "rapid_fire": 0,
            "shield": 0,
            "triple_shot": 0,
            "godmode": 0
        }

        self.godmode_music_playing = False
        self.magazine_size = 200
        self.current_ammo = 200
        self.is_reloading = False
        self.reload_timer = 0
        self.reload_time = 60
        self.booster_particles = []
        self.iron_spider_halo_angle = 0

    def update_skin(self):
        self.img = pygame.Surface((50, 40), pygame.SRCALPHA)
        pygame.draw.polygon(self.img, self.skin["color"], [(25, 0), (0, 40), (50, 40)])
        pygame.draw.polygon(self.img, self.skin["accent"], [(5, 20), (0, 40), (15, 35)])
        pygame.draw.polygon(self.img, self.skin["accent"], [(45, 20), (50, 40), (35, 35)])
        pygame.draw.circle(self.img, CYAN, (25, 15), 5)
        pygame.draw.circle(self.img, WHITE, (25, 15), 2)

    def update(self, keys):
        self.frame_counter += 1
        self.iron_spider_halo_angle += 5

        prev_pos = (self.rect.centerx, self.rect.centery)

        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            self.rect.x -= self.speed
            self.add_booster_particle(prev_pos, 'left')
        if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            self.rect.x += self.speed
            self.add_booster_particle(prev_pos, 'right')
        if keys[pygame.K_UP] or keys[pygame.K_w]:
            self.rect.y -= self.speed
            self.add_booster_particle(prev_pos, 'up')
        if keys[pygame.K_DOWN] or keys[pygame.K_s]:
            self.rect.y += self.speed
            self.add_booster_particle(prev_pos, 'down')

        self.rect.x = max(0, min(WIDTH - self.rect.width, self.rect.x))
        self.rect.y = max(0, min(HEIGHT - self.rect.height, self.rect.y))

        for particle in self.booster_particles[:]:
            particle['life'] -= 1
            particle['x'] += particle['dx']
            particle['y'] += particle['dy']
            if particle['life'] <= 0:
                self.booster_particles.remove(particle)

        for powerup in self.powerup_timers:
            if self.powerup_timers[powerup] > 0:
                self.powerup_timers[powerup] -= 1
                if self.powerup_timers[powerup] == 0:
                    self.powerups[powerup] = False

                    # Stop godmode music when godmode ends
                    if powerup == "godmode" and not self.powerups["godmode"]:
                        try:
                            play_game_music()
                        except:
                            pass

        if self.laser_cooldown > 0:
            self.laser_cooldown -= 1

        self.update_reload()

    def add_booster_particle(self, prev_pos, direction):
        if prev_pos[0] == self.rect.centerx and prev_pos[1] == self.rect.centery:
            return

        if direction == 'left':
            particle_x = self.rect.right + 5
            particle_y = self.rect.centery + random.randint(-10, 10)
            dx = random.uniform(-2, 2)
            dy = random.uniform(-1, 1)
        elif direction == 'right':
            particle_x = self.rect.left - 5
            particle_y = self.rect.centery + random.randint(-10, 10)
            dx = random.uniform(-2, 2)
            dy = random.uniform(-1, 1)
        elif direction == 'up':
            particle_x = self.rect.centerx + random.randint(-10, 10)
            particle_y = self.rect.bottom + 5
            dx = random.uniform(-1, 1)
            dy = random.uniform(1, 3)
        elif direction == 'down':
            particle_x = self.rect.centerx + random.randint(-10, 10)
            particle_y = self.rect.top - 5
            dx = random.uniform(-1, 1)
            dy = random.uniform(-3, -1)
        else:
            return

        self.booster_particles.append({
            'x': particle_x, 'y': particle_y, 'dx': dx, 'dy': dy,
            'life': random.randint(5, 15), 'size': random.randint(2, 4)
        })

    def find_nearest_enemies(self, enemies, bosses, count=3):
        all_targets = []
        for enemy in enemies:
            dist = math.sqrt((enemy.rect.centerx - self.rect.centerx)**2 +
                           (enemy.rect.centery - self.rect.centery)**2)
            all_targets.append((dist, enemy, None))
        for boss in bosses:
            dist = math.sqrt((boss.rect.centerx - self.rect.centerx)**2 +
                           (boss.rect.centery - self.rect.centery)**2)
            all_targets.append((dist, None, boss))
        all_targets.sort(key=lambda x: x[0])
        return all_targets[:count]

    def shoot(self):
        if self.is_reloading and not self.powerups["godmode"]:
            return

        if self.powerups["godmode"]:
            if self.laser_cooldown == 0:
                try:
                    laser_sound.play()
                except:
                    pass
                for angle in range(0, 360, 15):
                    self.lasers.append(GodModeLaser(self.rect.centerx, self.rect.centery, angle, self.frame_counter))
                self.laser_cooldown = 1
            return

        if self.powerups["rapid_fire"]:
            return  # Handled by shoot_auto_aim_with_targets

        if self.current_ammo <= 0:
            self.start_reload()
            return

        if self.laser_cooldown == 0:
            try:
                laser_sound.play()
            except:
                pass

            if self.powerups["triple_shot"]:
                self.lasers.append(Laser(self.rect.centerx - 20, self.rect.top, self.skin["laser_color"]))
                self.lasers.append(Laser(self.rect.centerx, self.rect.top, self.skin["laser_color"]))
                self.lasers.append(Laser(self.rect.centerx + 20, self.rect.top, self.skin["laser_color"]))
                self.current_ammo -= 3
            else:
                self.lasers.append(Laser(self.rect.centerx, self.rect.top, self.skin["laser_color"]))
                self.current_ammo -= 1

            self.laser_cooldown = 0

            if self.current_ammo <= 0:
                self.start_reload()

    def shoot_auto_aim_with_targets(self, enemies, bosses):
        if self.is_reloading:
            return

        if self.current_ammo <= 0:
            self.start_reload()
            return

        if self.laser_cooldown == 0:
            try:
                laser_sound.play()
            except:
                pass

            targets = self.find_nearest_enemies(enemies, bosses, 3)
            lasers_created = 0
            for dist, enemy, boss in targets:
                if enemy or boss:
                    self.lasers.append(AutoAimLaser(self.rect.centerx, self.rect.top, enemy, boss, self.skin["color"]))
                    lasers_created += 1

            if lasers_created == 0:
                self.lasers.append(Laser(self.rect.centerx - 15, self.rect.top, IRON_RED))
                self.lasers.append(Laser(self.rect.centerx, self.rect.top, IRON_RED))
                self.lasers.append(Laser(self.rect.centerx + 15, self.rect.top, IRON_RED))

            self.current_ammo -= 1
            self.laser_cooldown = 0

            if self.current_ammo <= 0:
                self.start_reload()

    def start_reload(self):
        if not self.is_reloading and self.current_ammo < self.magazine_size:
            self.is_reloading = True
            self.reload_timer = self.reload_time

    def update_reload(self):
        if self.is_reloading:
            self.reload_timer -= 1
            if self.reload_timer <= 0:
                self.current_ammo = self.magazine_size
                self.is_reloading = False

    def draw(self, screen):
        for particle in self.booster_particles:
            color = (self.skin["booster_color"][0], self.skin["booster_color"][1], self.skin["booster_color"][2])
            pygame.draw.circle(screen, color, (int(particle['x']), int(particle['y'])), particle['size'])

        screen.blit(self.img, self.rect)

        if self.powerups["rapid_fire"]:
            for ring in range(3):
                ring_radius = 28 + ring * 6 + (self.frame_counter % 20) / 4
                ring_surf = pygame.Surface((ring_radius * 2 + 10, ring_radius * 2 + 10), pygame.SRCALPHA)
                pygame.draw.circle(ring_surf, (255, 50, 50, 80 - ring * 20),
                                 (ring_radius + 5, ring_radius + 5), int(ring_radius), 2)
                screen.blit(ring_surf, (self.rect.centerx - ring_radius - 5, self.rect.centery - ring_radius - 5))

            for i in range(4):
                angle_rad = math.radians(self.iron_spider_halo_angle + i * 90)
                blade_end_x = self.rect.centerx + math.cos(angle_rad) * 35
                blade_end_y = self.rect.centery + math.sin(angle_rad) * 35
                pygame.draw.line(screen, (255, 50, 50), self.rect.center, (blade_end_x, blade_end_y), 4)
                pygame.draw.line(screen, (255, 150, 50), self.rect.center, (blade_end_x, blade_end_y), 2)

            pygame.draw.circle(screen, BRIGHT_RED, (self.rect.centerx, self.rect.top - 3), 8)
            pygame.draw.circle(screen, (255, 100, 100), (self.rect.centerx, self.rect.top - 3), 4)

        if self.powerups["godmode"]:
            for i in range(4):
                glow_rect = pygame.Rect(0, 0, 85 + i*12, 75 + i*12)
                glow_rect.center = self.rect.center
                pygame.draw.ellipse(screen, (GOLD[0], GOLD[1], GOLD[2], 100 - i*25), glow_rect, 3)
            for angle in range(0, 360, 30):
                rad = math.radians(angle + self.frame_counter * 5)
                px = self.rect.centerx + math.cos(rad) * 40
                py = self.rect.centery + math.sin(rad) * 40
                pygame.draw.circle(screen, get_rainbow_color(self.frame_counter + angle), (int(px), int(py)), 3)

        if self.powerups["shield"]:
            shield_rect = pygame.Rect(0, 0, 75, 65)
            shield_rect.center = self.rect.center
            pygame.draw.ellipse(screen, (0, 255, 255, 100), shield_rect, 3)

        if not self.powerups["godmode"]:
            if self.is_reloading:
                reload_progress = (self.reload_time - self.reload_timer) / self.reload_time
                draw_text(f"RELOADING: {int(reload_progress * 100)}%", font_small, RED, 160, 85)
                bar_width = 200
                progress_width = bar_width * reload_progress
                pygame.draw.rect(screen, (100, 0, 0), (60, 95, bar_width, 8))
                pygame.draw.rect(screen, RED, (60, 95, progress_width, 8))
            else:
                ammo_color = YELLOW if self.current_ammo > 50 else ORANGE if self.current_ammo > 20 else RED
                draw_text(f"Ammo: {self.current_ammo}/{self.magazine_size}", font_small, ammo_color, 160, 85)
                bar_width = 200
                ammo_width = bar_width * (self.current_ammo / self.magazine_size)
                pygame.draw.rect(screen, (50, 50, 50), (60, 95, bar_width, 8))
                pygame.draw.rect(screen, ammo_color, (60, 95, ammo_width, 8))
        else:
            draw_text("GODMODE ACTIVE", font_small, GOLD, 160, 85)
            draw_text("INFINITE AMMO", font_small, CYAN, 160, 105)

        pygame.draw.rect(screen, RED, (15, 15, 280, 25))
        pygame.draw.rect(screen, GREEN, (15, 15, 280 * (self.health/self.max_health), 25))
        draw_text(f"Health: {self.health}/{self.max_health}", font_small, WHITE, 155, 30)

# ========== INSTRUCTIONS PAGE ==========
def instructions_page():
    clock = pygame.time.Clock()

    float_offset = 0
    float_direction = 1

    while True:
        screen.fill(BLACK)
        draw_starfield()
        draw_high_tech_border()

        float_offset += 0.5 * float_direction
        if float_offset > 10 or float_offset < 0:
            float_direction *= -1

        for i in range(5, 0, -1):
            draw_text("GALACTIC SPACE EXPLORER", font_large, (0, 100, 200), WIDTH//2, 45 - i//2)
        draw_text("GALACTIC SPACE EXPLORER", font_large, CYAN, WIDTH//2, 40)
        draw_text("========================================", font_small, GOLD, WIDTH//2, 85)

        left_panel = pygame.Rect(50, 110, WIDTH//2 - 70, HEIGHT - 160)
        right_panel = pygame.Rect(WIDTH//2 + 20, 110, WIDTH//2 - 70, HEIGHT - 160)

        pygame.draw.rect(screen, (0, 0, 30), left_panel, border_radius=15)
        pygame.draw.rect(screen, CYAN, left_panel, 2, border_radius=15)
        pygame.draw.rect(screen, (0, 0, 30), right_panel, border_radius=15)
        pygame.draw.rect(screen, CYAN, right_panel, 2, border_radius=15)

        left_x = left_panel.centerx
        right_x = right_panel.centerx

        y = 140
        draw_text("CONTROLS", font_medium, GOLD, left_x, y)
        y += 45
        draw_text("WASD or Arrow Keys - Move ship", font_small, WHITE, left_x, y)
        y += 35
        draw_text("SPACE - Shoot (hold for auto-fire)", font_small, WHITE, left_x, y)
        y += 35
        draw_text("ESC - Pause game", font_small, WHITE, left_x, y)
        y += 50

        draw_text("GAME ELEMENTS", font_medium, GOLD, left_x, y)
        y += 45
        draw_text("Your Ship", font_small, BLUE, left_x - 100, y)
        pygame.draw.circle(screen, BLUE, (left_x + 50, y - 5), 8)
        y += 35
        draw_text("Enemy Ship", font_small, RED, left_x - 100, y)
        pygame.draw.polygon(screen, RED, [(left_x + 50, y - 8), (left_x + 40, y + 4), (left_x + 60, y + 4)])
        y += 35
        draw_text("BOSS", font_small, DARK_PURPLE, left_x - 100, y)
        pygame.draw.circle(screen, DARK_PURPLE, (left_x + 50, y - 5), 6)
        y += 35
        draw_text("Asteroid", font_small, (150,150,150), left_x - 100, y)
        pygame.draw.circle(screen, (150,150,150), (left_x + 50, y - 5), 6)
        y += 35
        draw_text("Heal Zone", font_small, GREEN, left_x - 100, y)
        pygame.draw.rect(screen, GREEN, (left_x + 40, y - 12, 20, 20))
        y += 50

        draw_text("PORTAL MINIGAME", font_medium, MAGENTA, left_x, y)
        y += 45
        draw_text("Enter the swirling blue portal", font_small, YELLOW, left_x, y)
        y += 35
        draw_text("Press SPACE/UP on the beat", font_small, WHITE, left_x, y)
        y += 35
        draw_text("Perfect hit = +100 points", font_small, GREEN, left_x, y)
        y += 35
        draw_text("Miss = -5 HP", font_small, RED, left_x, y)

        y = 140
        draw_text("POWER-UPS", font_medium, GOLD, right_x, y)
        y += 45
        draw_text("YELLOW - IRON SPIDER", font_small, YELLOW, right_x, y)
        draw_text("3 homing lasers, halo effect", font_tiny, WHITE, right_x, y + 20)
        y += 45
        draw_text("PURPLE - Triple Shot", font_small, PURPLE, right_x, y)
        draw_text("Shoots 3 lasers at once", font_tiny, WHITE, right_x, y + 20)
        y += 45
        draw_text("BLUE - Shield", font_small, BLUE, right_x, y)
        draw_text("Temporary invincibility", font_tiny, WHITE, right_x, y + 20)
        y += 45
        draw_text("GREEN - Heal", font_small, HEAL_GREEN, right_x, y)
        draw_text("Restores 15 HP instantly", font_tiny, WHITE, right_x, y + 20)
        y += 45
        draw_text("GOLD - GODMODE", font_small, GOLD, right_x, y)
        draw_text("360 degree rainbow lasers", font_tiny, WHITE, right_x, y + 20)
        y += 60

        draw_text("BOSS INFO", font_medium, RED, right_x, y)
        y += 45
        draw_text("Takes 9 hits to kill", font_small, WHITE, right_x, y)
        y += 35
        draw_text("Shoots directly at YOU", font_small, BLOOD_RED, right_x, y)
        y += 35
        draw_text("20 damage (pierces shield)", font_small, BLOOD_RED, right_x, y)
        y += 35
        draw_text("Touch = INSTANT DEATH", font_small, BLOOD_RED, right_x, y)

        continue_btn = draw_button("CONTINUE TO MENU", WIDTH//2, HEIGHT - 45, 350, 50, GREEN, (0, 200, 0), "continue")

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        if continue_btn == "continue":
            return

        pygame.display.flip()
        clock.tick(60)

# ========== SKIN CAROUSEL MENU ==========
def carousel_menu():
    global current_skin_index, selected_skin

    clock = pygame.time.Clock()
    while True:
        screen.fill(BLACK)
        draw_starfield()
        draw_high_tech_border()

        draw_text("SELECT STARSHIP SKIN", font_large, GOLD, WIDTH//2, 70)
        draw_text(f"{len(SKINS)} SKINS AVAILABLE", font_medium, CYAN, WIDTH//2, 125)
        draw_text("LEFT / RIGHT arrows to browse", font_small, WHITE, WIDTH//2, 165)
        draw_text("Press ENTER to select", font_small, YELLOW, WIDTH//2, 195)

        s = SKINS[current_skin_index]

        preview_rect = pygame.Rect(WIDTH//2 - 160, HEIGHT//2 - 160, 320, 320)
        pygame.draw.rect(screen, (20, 20, 40), preview_rect, border_radius=20)
        pygame.draw.rect(screen, s["color"], preview_rect, 4, border_radius=20)

        preview_ship = pygame.Surface((120, 100), pygame.SRCALPHA)
        pygame.draw.polygon(preview_ship, s["color"], [(60, 0), (0, 100), (120, 100)])
        pygame.draw.polygon(preview_ship, s["accent"], [(15, 50), (0, 100), (35, 85)])
        pygame.draw.polygon(preview_ship, s["accent"], [(105, 50), (120, 100), (85, 85)])
        pygame.draw.circle(preview_ship, CYAN, (60, 35), 12)
        pygame.draw.circle(preview_ship, WHITE, (60, 35), 5)

        rotated_ship = pygame.transform.rotate(preview_ship, math.sin(pygame.time.get_ticks() / 500) * 5)
        preview_rect_ship = rotated_ship.get_rect(center=(WIDTH//2, HEIGHT//2))
        screen.blit(rotated_ship, preview_rect_ship)

        draw_text(s["name"], font_medium, s["color"], WIDTH//2, preview_rect.bottom + 45)

        if s["unlock"] == 0:
            draw_text("STARTING SKIN", font_small, GOLD, WIDTH//2, preview_rect.bottom + 85)
        elif high_score >= s["unlock"]:
            draw_text(f"UNLOCKED (Need {s['unlock']} pts)", font_small, GREEN, WIDTH//2, preview_rect.bottom + 85)
        else:
            draw_text(f"LOCKED (Need {s['unlock']} pts)", font_small, RED, WIDTH//2, preview_rect.bottom + 85)

        draw_text(f"{current_skin_index + 1} / {len(SKINS)}", font_small, WHITE, WIDTH//2, preview_rect.bottom + 125)

        back_btn = draw_button("BACK", 150, HEIGHT - 60, 160, 50, (100, 100, 150), (150, 150, 200), "back")
        select_btn = draw_button("SELECT", WIDTH - 150, HEIGHT - 60, 160, 50, (50, 150, 50), (100, 200, 100), "select")

        pygame.display.update()
        clock.tick(60)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT:
                    current_skin_index = (current_skin_index - 1) % len(SKINS)
                elif event.key == pygame.K_RIGHT:
                    current_skin_index = (current_skin_index + 1) % len(SKINS)
                elif event.key == pygame.K_RETURN or event.key == pygame.K_SPACE:
                    if high_score >= SKINS[current_skin_index]["unlock"]:
                        selected_skin = s
                        settings["skin"] = s["name"]
                        save_settings(settings)
                        return
                elif event.key == pygame.K_ESCAPE:
                    return

        if back_btn == "back":
            return
        if select_btn == "select" and high_score >= SKINS[current_skin_index]["unlock"]:
            selected_skin = s
            settings["skin"] = s["name"]
            save_settings(settings)
            return

# ========== MAIN MENU ==========
def main_menu():
    global selected_skin, high_score

    clock = pygame.time.Clock()

    play_menu_music()

    while True:
        screen.fill(BLACK)
        draw_starfield()
        draw_high_tech_border()

        title_y = HEIGHT//2 - 250 + math.sin(pygame.time.get_ticks() / 800) * 3
        for i in range(5, 0, -1):
            draw_text("GALACTIC SPACE EXPLORER", font_large, (0, 100, 200), WIDTH//2, title_y - i)
        draw_text("GALACTIC SPACE EXPLORER", font_large, CYAN, WIDTH//2, title_y)

        draw_text("Shoot, Loot, and Portal to Scoot!", font_medium, WHITE, WIDTH//2, HEIGHT//2 - 180)

        high_score = load_highscore()
        draw_text(f"HIGH SCORE: {high_score}", font_medium, GOLD, WIDTH//2, HEIGHT//2 - 130)
        draw_text(f"Current Skin: {selected_skin['name']}", font_small, selected_skin["color"], WIDTH//2, HEIGHT//2 - 90)

        draw_text("NEW: PHIGROS PORTAL!", font_medium, MAGENTA, WIDTH//2, HEIGHT//2 - 40)
        draw_text("Enter the portal for a rhythm mini-game!", font_small, CYAN, WIDTH//2, HEIGHT//2 - 10)

        start_btn = draw_button("START GAME", WIDTH//2, HEIGHT//2 + 60, 280, 55, GREEN, (0, 200, 0), "start")
        skin_btn = draw_button("SELECT SKIN", WIDTH//2, HEIGHT//2 + 130, 280, 55, PURPLE, (150, 0, 150), "skin")
        quit_btn = draw_button("QUIT", WIDTH//2, HEIGHT//2 + 200, 280, 55, RED, (200, 0, 0), "quit")

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        if start_btn == "start":
            return True
        if skin_btn == "skin":
            carousel_menu()
        if quit_btn == "quit":
            return False

        pygame.display.flip()
        clock.tick(60)

# ========== MAIN GAME LOOP ==========
def main_game():
    global selected_skin, high_score

    play_game_music()

    player = Player()
    player.skin = selected_skin
    player.update_skin()

    health_region = HealthRegion()
    enemies = []
    bosses = []
    asteroids = []
    powerups = []
    portals = []
    explosions = []
    enemy_spawn_timer = 0
    boss_spawn_timer = random.randint(600, 1200)
    asteroid_spawn_timer = 0
    powerup_spawn_timer = random.randint(500, 800)
    godmode_spawn_timer = random.randint(1800, 3600)
    portal_spawn_timer = 30  # Spawn portal quickly for testing
    level = 1
    game_over = False
    paused = False
    auto_fire_timer = 0

    clock = pygame.time.Clock()

    while not game_over:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    paused = not paused
                elif event.key == pygame.K_SPACE:
                    if player.powerups["godmode"]:
                        player.shoot()
                    elif player.powerups["rapid_fire"]:
                        player.shoot_auto_aim_with_targets(enemies, bosses)
                    else:
                        player.shoot()
                    auto_fire_timer = 5

        if auto_fire_timer > 0:
            auto_fire_timer -= 1
        elif pygame.key.get_pressed()[pygame.K_SPACE]:
            if player.powerups["godmode"]:
                player.shoot()
            elif player.powerups["rapid_fire"]:
                player.shoot_auto_aim_with_targets(enemies, bosses)
            else:
                player.shoot()
            auto_fire_timer = 5

        if paused:
            screen.fill(BLACK)
            draw_high_tech_border()
            draw_text("PAUSED", font_large, WHITE, WIDTH//2, HEIGHT//2)
            draw_text("Press ESC to continue", font_medium, CYAN, WIDTH//2, HEIGHT//2 + 70)
            pygame.display.flip()
            clock.tick(60)
            continue

        # Spawn enemies
        enemy_spawn_timer -= 1
        if enemy_spawn_timer <= 0:
            enemies.append(Enemy())
            enemy_spawn_timer = max(10, 50 - level)

        # Spawn boss
        boss_spawn_timer -= 1
        if boss_spawn_timer <= 0 and len(bosses) == 0:
            bosses.append(BossEnemy())
            boss_spawn_timer = random.randint(900, 1500)

        # Spawn asteroids
        asteroid_spawn_timer -= 1
        if asteroid_spawn_timer <= 0:
            asteroids.append(Asteroid())
            asteroid_spawn_timer = random.randint(30, 100)

        # Spawn powerups
        powerup_spawn_timer -= 1
        if powerup_spawn_timer <= 0:
            powerups.append(PowerUp())
            powerup_spawn_timer = random.randint(500, 800)

        # Spawn godmode powerup
        godmode_spawn_timer -= 1
        if godmode_spawn_timer <= 0:
            godmode_powerup = PowerUp()
            godmode_powerup.type = "godmode"
            godmode_powerup.img = pygame.Surface((30, 30))
            godmode_powerup.img.fill(GOLD)
            pygame.draw.circle(godmode_powerup.img, WHITE, (15, 15), 10, 2)
            pygame.draw.line(godmode_powerup.img, WHITE, (5, 15), (25, 15), 2)
            pygame.draw.line(godmode_powerup.img, WHITE, (15, 5), (15, 25), 2)
            powerups.append(godmode_powerup)
            godmode_spawn_timer = random.randint(2400, 4800)

        # SPAWN PORTAL - Increased frequency
        portal_spawn_timer -= 1
        if portal_spawn_timer <= 0 and len(portals) == 0:
            portal_x = random.randint(100, WIDTH - 100)
            portal_y = random.randint(100, HEIGHT - 100)
            portals.append(PhigrosPortal(portal_x, portal_y))
            portal_spawn_timer = random.randint(600, 1200)  # Spawn every 10-20 seconds
            try:
                powerup_sound.play()
            except:
                pass

        keys = pygame.key.get_pressed()
        player.update(keys)
        health_region.update(player)

        # Update portals
        for portal in portals[:]:
            if not portal.update():
                portals.remove(portal)
                continue
            if player.rect.colliderect(portal.rect):
                portals.remove(portal)
                mixer.music.pause()
                score_gain, health_loss = phigros_minigame(player, portal)
                mixer.music.unpause()
                try:
                    powerup_sound.play()
                except:
                    pass

        # Update lasers
        for laser in player.lasers[:]:
            if laser.update():
                player.lasers.remove(laser)

        # Update bosses
        for boss in bosses[:]:
            if boss.update((player.rect.centerx, player.rect.centery)):
                bosses.remove(boss)
                continue

            if player.rect.colliderect(boss.rect):
                game_over = True
                break

            for laser in boss.lasers[:]:
                if player.rect.colliderect(laser.rect):
                    if not player.powerups["godmode"]:
                        player.health -= 20
                    boss.lasers.remove(laser)
                    if player.health <= 0:
                        game_over = True

            for laser in player.lasers[:]:
                if boss.rect.colliderect(laser.rect):
                    boss.health -= 1
                    player.lasers.remove(laser)
                    if boss.health <= 0:
                        player.score += boss.score_value
                        explosions.append(Explosion(boss.rect.centerx, boss.rect.centery, 2.0))
                        bosses.remove(boss)
                        try:
                            explosion_sound.play()
                        except:
                            pass
                    break

        # Update enemies
        for enemy in enemies[:]:
            if enemy.update():
                enemies.remove(enemy)
                continue

            for laser in player.lasers[:]:
                if enemy.rect.colliderect(laser.rect):
                    enemy.health -= 10
                    player.lasers.remove(laser)
                    if enemy.health <= 0:
                        player.score += 100
                        explosions.append(Explosion(enemy.rect.centerx, enemy.rect.centery))
                        if enemy in enemies:
                            enemies.remove(enemy)
                        try:
                            explosion_sound.play()
                        except:
                            pass
                        if random.random() < 0.15:
                            powerups.append(PowerUp(enemy.rect.centerx, enemy.rect.centery))
                    break

            if player.rect.colliderect(enemy.rect):
                if not player.powerups["shield"] and not player.powerups["godmode"]:
                    player.health -= 20
                    explosions.append(Explosion(enemy.rect.centerx, enemy.rect.centery))
                    if enemy in enemies:
                        enemies.remove(enemy)
                    try:
                        explosion_sound.play()
                    except:
                        pass
                    if player.health <= 0:
                        game_over = True
                elif player.powerups["godmode"]:
                    explosions.append(Explosion(enemy.rect.centerx, enemy.rect.centery))
                    if enemy in enemies:
                        enemies.remove(enemy)
                    try:
                        explosion_sound.play()
                    except:
                        pass
                    player.score += 50
                continue

            for laser in enemy.lasers[:]:
                if player.rect.colliderect(laser.rect):
                    if not player.powerups["shield"] and not player.powerups["godmode"]:
                        player.health -= 5
                    enemy.lasers.remove(laser)
                    if player.health <= 0:
                        game_over = True

        # Update asteroids
        for asteroid in asteroids[:]:
            if asteroid.update():
                asteroids.remove(asteroid)
                continue

            if player.rect.colliderect(asteroid.rect):
                if not player.powerups["shield"] and not player.powerups["godmode"]:
                    player.health -= asteroid.health // 5
                    asteroid.health -= 50
                    if asteroid.health <= 0:
                        player.score += 50
                        explosions.append(Explosion(asteroid.rect.centerx, asteroid.rect.centery, 1.5))
                        asteroids.remove(asteroid)
                        try:
                            explosion_sound.play()
                        except:
                            pass
                    if player.health <= 0:
                        game_over = True
                elif player.powerups["godmode"]:
                    player.score += 50
                    explosions.append(Explosion(asteroid.rect.centerx, asteroid.rect.centery, 1.5))
                    asteroids.remove(asteroid)
                    try:
                        explosion_sound.play()
                    except:
                        pass
                    continue

            if asteroid in asteroids:
                for laser in player.lasers[:]:
                    if asteroid.rect.colliderect(laser.rect):
                        asteroid.health -= 10
                        player.lasers.remove(laser)
                        if asteroid.health <= 0:
                            player.score += 50
                            explosions.append(Explosion(asteroid.rect.centerx, asteroid.rect.centery, 1.5))
                            asteroids.remove(asteroid)
                            try:
                                explosion_sound.play()
                            except:
                                pass
                        break

        # Update powerups
        for powerup in powerups[:]:
            if powerup.update():
                powerups.remove(powerup)
                continue

            if player.rect.colliderect(powerup.rect):
                if powerup.type == "godmode":
                    player.powerups["godmode"] = True
                    player.powerup_timers["godmode"] = 900
                    player.current_ammo = player.magazine_size
                    player.is_reloading = False
                    play_godmode_music()
                elif powerup.type == "heal":
                    player.health = min(player.max_health, player.health + 15)
                    try:
                        powerup_sound.play()
                    except:
                        pass
                else:
                    player.powerups[powerup.type] = True
                    player.powerup_timers[powerup.type] = 600
                    try:
                        powerup_sound.play()
                    except:
                        pass
                powerups.remove(powerup)

        # Update explosions
        for explosion in explosions[:]:
            if explosion.update():
                explosions.remove(explosion)

        if player.score >= level * 1000:
            level += 1

        # DRAW EVERYTHING
        screen.fill(BLACK)
        draw_starfield()

        for laser in player.lasers:
            laser.draw(screen)

        player.draw(screen)
        health_region.draw(screen)

        for boss in bosses:
            boss.draw(screen)
        for enemy in enemies:
            enemy.draw(screen)
        for asteroid in asteroids:
            asteroid.draw(screen)
        for powerup in powerups:
            powerup.draw(screen)
        for portal in portals:
            portal.draw(screen)
            portal.draw_minimap_indicator(screen)
        for explosion in explosions:
            explosion.draw(screen)

        draw_high_tech_border()

        draw_text(f"Score: {player.score}", font_small, WHITE, 90, 140)
        draw_text(f"Level: {level}", font_small, WHITE, 90, 175)

        y_pos = 220
        for powerup, active in player.powerups.items():
            if active:
                if powerup == "godmode":
                    color = GOLD
                    text = f"GODMODE: {player.powerup_timers[powerup] // 60}s"
                elif powerup == "rapid_fire":
                    color = YELLOW
                    text = f"IRON SPIDER: {player.powerup_timers[powerup] // 60}s"
                elif powerup == "triple_shot":
                    color = PURPLE
                    text = f"Triple Shot: {player.powerup_timers[powerup] // 60}s"
                elif powerup == "shield":
                    color = CYAN
                    text = f"Shield: {player.powerup_timers[powerup] // 60}s"
                else:
                    color = GREEN
                    text = f"{powerup.replace('_', ' ').title()}: {player.powerup_timers[powerup] // 60}s"
                draw_text(text, font_small, color, 140, y_pos, False)
                y_pos += 30

        pygame.display.flip()
        clock.tick(60)

    # Game Over
    stop_music()
    try:
        death_sound.play()
        pygame.time.wait(500)
    except:
        pass

    is_new_high = save_highscore(player.score)
    high_score = load_highscore()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

        screen.fill(BLACK)
        draw_starfield()
        draw_high_tech_border()

        draw_text("GAME OVER", font_large, RED, WIDTH//2, HEIGHT//2 - 100)
        draw_text(f"Final Score: {player.score}", font_medium, WHITE, WIDTH//2, HEIGHT//2 - 30)
        draw_text(f"Level Reached: {level}", font_medium, WHITE, WIDTH//2, HEIGHT//2 + 25)

        if is_new_high:
            draw_text("NEW HIGH SCORE!", font_medium, GOLD, WIDTH//2, HEIGHT//2 + 80)

        restart = draw_button("PLAY AGAIN", WIDTH//2, HEIGHT//2 + 160, 240, 55, GREEN, (0, 200, 0), "restart")
        menu_btn = draw_button("MAIN MENU", WIDTH//2, HEIGHT//2 + 230, 240, 55, BLUE, (0, 0, 200), "menu")
        quit_btn = draw_button("QUIT", WIDTH//2, HEIGHT//2 + 300, 240, 55, RED, (200, 0, 0), "quit")

        if restart == "restart":
            return True
        if menu_btn == "menu":
            return "menu"
        if quit_btn == "quit":
            return False

        pygame.display.flip()
        clock.tick(60)

# ========== RUN GAME ==========
if __name__ == "__main__":
    instructions_page()

    while True:
        if main_menu():
            result = main_game()
            if result == "menu":
                continue
            elif not result:
                break
    pygame.quit()




您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|RealDevClub ( 沪ICP备2024093864号-1 )

GMT+8, 7-15-2026 05:25 , Processed in 0.063414 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表