Загрузка данных


import pygame, random, math

pygame.init()
W, H = 900, 650
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption("Neon Survival")
clock = pygame.time.Clock()
font_big = pygame.font.SysFont("arial", 70, bold=True)
font = pygame.font.SysFont("arial", 30)
font_small = pygame.font.SysFont("arial", 22)

# ---------- ЦВЕТА ----------
BG_TOP = (10, 8, 30)
BG_BOTTOM = (30, 10, 50)
PLAYER_COLOR = (80, 220, 255)
ENEMY_COLOR = (255, 60, 100)
GEM_COLOR = (255, 220, 60)

def lerp(a, b, t):
    return a + (b - a) * t

def gradient_background(surf):
    for y in range(H):
        t = y / H
        r = lerp(BG_TOP[0], BG_BOTTOM[0], t)
        g = lerp(BG_TOP[1], BG_BOTTOM[1], t)
        b = lerp(BG_TOP[2], BG_BOTTOM[2], t)
        pygame.draw.line(surf, (r, g, b), (0, y), (W, y))

bg_surface = pygame.Surface((W, H))
gradient_background(bg_surface)

# статичные "звёзды" на фоне
stars = [(random.randint(0, W), random.randint(0, H), random.randint(1, 3)) for _ in range(120)]

def draw_glow_circle(surf, color, pos, radius, glow_strength=3):
    """Рисует круг со свечением (несколько полупрозрачных слоёв)"""
    glow_surf = pygame.Surface((radius*4, radius*4), pygame.SRCALPHA)
    cx, cy = radius*2, radius*2
    for i in range(glow_strength, 0, -1):
        alpha = int(40 / i)
        r = radius + i * 5
        pygame.draw.circle(glow_surf, (*color, alpha), (cx, cy), r)
    pygame.draw.circle(glow_surf, (*color, 255), (cx, cy), radius)
    surf.blit(glow_surf, (pos[0] - radius*2, pos[1] - radius*2), special_flags=pygame.BLEND_RGBA_ADD)


class Particle:
    def __init__(self, x, y, color):
        self.x, self.y = x, y
        angle = random.uniform(0, math.pi * 2)
        speed = random.uniform(1, 4)
        self.vx = math.cos(angle) * speed
        self.vy = math.sin(angle) * speed
        self.life = random.uniform(20, 40)
        self.max_life = self.life
        self.color = color
        self.radius = random.uniform(2, 4)

    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.vx *= 0.96
        self.vy *= 0.96
        self.life -= 1

    def draw(self, surf):
        if self.life > 0:
            alpha = int(255 * (self.life / self.max_life))
            s = pygame.Surface((int(self.radius*2)+2, int(self.radius*2)+2), pygame.SRCALPHA)
            pygame.draw.circle(s, (*self.color, alpha), (int(self.radius), int(self.radius)), int(self.radius))
            surf.blit(s, (self.x - self.radius, self.y - self.radius))


class Player:
    def __init__(self):
        self.x, self.y = W // 2, H // 2
        self.radius = 14
        self.trail = []

    def update(self, keys):
        speed = 5.5
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            self.x -= speed
        if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            self.x += speed
        if keys[pygame.K_UP] or keys[pygame.K_w]:
            self.y -= speed
        if keys[pygame.K_DOWN] or keys[pygame.K_s]:
            self.y += speed
        self.x = max(self.radius, min(W - self.radius, self.x))
        self.y = max(self.radius, min(H - self.radius, self.y))

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

    def draw(self, surf):
        for i, (tx, ty) in enumerate(self.trail):
            alpha_r = int(self.radius * (i / len(self.trail)))
            if alpha_r > 0:
                s = pygame.Surface((alpha_r*2, alpha_r*2), pygame.SRCALPHA)
                a = int(120 * (i / len(self.trail)))
                pygame.draw.circle(s, (*PLAYER_COLOR, a), (alpha_r, alpha_r), alpha_r)
                surf.blit(s, (tx - alpha_r, ty - alpha_r))
        draw_glow_circle(surf, PLAYER_COLOR, (self.x, self.y), self.radius, glow_strength=4)


class Enemy:
    def __init__(self, difficulty):
        side = random.choice(["top", "bottom", "left", "right"])
        if side == "top":
            self.x, self.y = random.randint(0, W), -20
        elif side == "bottom":
            self.x, self.y = random.randint(0, W), H + 20
        elif side == "left":
            self.x, self.y = -20, random.randint(0, H)
        else:
            self.x, self.y = W + 20, random.randint(0, H)

        angle = math.atan2(H/2 - self.y, W/2 - self.x)
        angle += random.uniform(-0.5, 0.5)
        speed = random.uniform(1.5, 2.5) + difficulty * 0.35
        self.vx = math.cos(angle) * speed
        self.vy = math.sin(angle) * speed
        self.radius = random.randint(10, 18)
        self.pulse = random.uniform(0, math.pi*2)

    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.pulse += 0.15

    def draw(self, surf):
        r = self.radius + math.sin(self.pulse) * 2
        draw_glow_circle(surf, ENEMY_COLOR, (self.x, self.y), int(r), glow_strength=3)

    def offscreen(self):
        return self.x < -60 or self.x > W + 60 or self.y < -60 or self.y > H + 60


class Gem:
    def __init__(self):
        self.x = random.randint(40, W - 40)
        self.y = random.randint(40, H - 40)
        self.radius = 9
        self.pulse = random.uniform(0, math.pi*2)

    def update(self):
        self.pulse += 0.1

    def draw(self, surf):
        r = self.radius + math.sin(self.pulse) * 2
        draw_glow_circle(surf, GEM_COLOR, (self.x, self.y), int(r), glow_strength=3)


player = Player()
enemies = []
gems = [Gem() for _ in range(4)]
particles = []

score = 0
survival_time = 0
spawn_timer = 0
game_over = False
shake = 0

running = True
while running:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN and event.key == pygame.K_r and game_over:
            player = Player()
            enemies = []
            gems = [Gem() for _ in range(4)]
            particles = []
            score = 0
            survival_time = 0
            spawn_timer = 0
            game_over = False

    keys = pygame.key.get_pressed()

    if not game_over:
        survival_time += 1 / 60
        difficulty = survival_time / 10

        player.update(keys)

        spawn_timer += 1
        spawn_rate = max(15, 45 - int(difficulty * 3))
        if spawn_timer > spawn_rate:
            spawn_timer = 0
            enemies.append(Enemy(difficulty))

        for e in enemies[:]:
            e.update()
            if e.offscreen():
                enemies.remove(e)
            dist = math.hypot(e.x - player.x, e.y - player.y)
            if dist < e.radius + player.radius - 4:
                game_over = True
                shake = 25
                for _ in range(40):
                    particles.append(Particle(player.x, player.y, ENEMY_COLOR))

        for g in gems[:]:
            g.update()
            dist = math.hypot(g.x - player.x, g.y - player.y)
            if dist < g.radius + player.radius:
                score += 10
                for _ in range(15):
                    particles.append(Particle(g.x, g.y, GEM_COLOR))
                gems.remove(g)
                gems.append(Gem())

        for p in particles[:]:
            p.update()
            if p.life <= 0:
                particles.remove(p)

    # ---------- ОТРИСОВКА ----------
    offset_x = random.randint(-shake, shake) if shake > 0 else 0
    offset_y = random.randint(-shake, shake) if shake > 0 else 0
    if shake > 0:
        shake -= 1

    screen.blit(bg_surface, (offset_x, offset_y))
    for (sx, sy, sr) in stars:
        pygame.draw.circle(screen, (200, 200, 255), (sx + offset_x, sy + offset_y), sr)

    for g in gems:
        g.draw(screen)
    for e in enemies:
        e.draw(screen)
    for p in particles:
        p.draw(screen)
    if not game_over:
        player.draw(screen)

    score_text = font.render(f"Счёт: {score}", True, (255, 255, 255))
    time_text = font_small.render(f"Время: {survival_time:.1f}с", True, (200, 200, 220))
    screen.blit(score_text, (20, 20))
    screen.blit(time_text, (20, 55))

    if game_over:
        overlay = pygame.Surface((W, H), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 150))
        screen.blit(overlay, (0, 0))
        over_text = font_big.render("ИГРА ОКОНЧЕНА", True, (255, 60, 100))
        screen.blit(over_text, (W//2 - over_text.get_width()//2, H//2 - 100))
        final_score = font.render(f"Финальный счёт: {score}", True, (255, 255, 255))
        screen.blit(final_score, (W//2 - final_score.get_width()//2, H//2))
        restart = font_small.render("Нажми R чтобы начать заново", True, (200, 200, 220))
        screen.blit(restart, (W//2 - restart.get_width()//2, H//2 + 50))

    pygame.display.flip()

pygame.quit()