Загрузка данных
import pygame
import random
import math
pygame.init()
WIDTH = 800
HEIGHT = 650
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("CYBER VOID // NEON OVERDRIVE")
clock = pygame.time.Clock()
FPS = 60
# Неоновая палитра
BG_DARK = (8, 9, 18)
NEON_CYAN = (0, 245, 255)
NEON_PINK = (255, 20, 147)
NEON_YELLOW = (255, 230, 60)
NEON_ORANGE = (255, 120, 30)
NEON_PURPLE = (180, 50, 255)
NEON_GREEN = (50, 255, 140)
WHITE = (255, 255, 255)
font_sm = pygame.font.SysFont("consolas", 18, bold=True)
font_md = pygame.font.SysFont("consolas", 26, bold=True)
font_lg = pygame.font.SysFont("consolas", 52, bold=True)
def draw_glow_circle(surf, color, center, radius, glow_factor=3):
glow_surf = pygame.Surface((radius * glow_factor * 2, radius * glow_factor * 2), pygame.SRCALPHA)
pygame.draw.circle(glow_surf, (*color, 45), (radius * glow_factor, radius * glow_factor), radius * glow_factor)
pygame.draw.circle(glow_surf, (*color, 120), (radius * glow_factor, radius * glow_factor), int(radius * 1.5))
pygame.draw.circle(glow_surf, color, (radius * glow_factor, radius * glow_factor), radius)
surf.blit(glow_surf, (center[0] - radius * glow_factor, center[1] - radius * glow_factor), special_flags=pygame.BLEND_ADD)
class DamageText:
def __init__(self, x, y, text, color=WHITE):
self.x = x + random.randint(-12, 12)
self.y = y
self.text = str(text)
self.color = color
self.life = 35
def update(self):
self.y -= 1.2
self.life -= 1
def draw(self, surf):
alpha = min(255, self.life * 8)
rendered = font_sm.render(self.text, True, self.color)
rendered.set_alpha(alpha)
surf.blit(rendered, (self.x, self.y))
class Player:
def __init__(self):
self.x = WIDTH // 2
self.y = HEIGHT - 90
self.speed = 7
self.cooldown = 0
self.shield = 0
self.triple_timer = 0
self.bombs = 2
self.trail = []
def update(self, keys):
moved = False
if (keys[pygame.K_LEFT] or keys[pygame.K_a]) and self.x > 30:
self.x -= self.speed
moved = True
if (keys[pygame.K_RIGHT] or keys[pygame.K_d]) and self.x < WIDTH - 30:
self.x += self.speed
moved = True
if (keys[pygame.K_UP] or keys[pygame.K_w]) and self.y > 40:
self.y -= self.speed
moved = True
if (keys[pygame.K_DOWN] or keys[pygame.K_s]) and self.y < HEIGHT - 40:
self.y += self.speed
moved = True
# След реактивного сопла
self.trail.append((self.x, self.y + 18, 14))
for i in range(len(self.trail) - 1, -1, -1):
x, y, r = self.trail[i]
if r <= 1:
self.trail.pop(i)
else:
self.trail[i] = (x + random.uniform(-1, 1), y + 3, r - 1.2)
if self.cooldown > 0:
self.cooldown -= 1
if self.triple_timer > 0:
self.triple_timer -= 1
def draw(self, surf):
# Двигатели
for x, y, r in self.trail:
pygame.draw.circle(surf, NEON_ORANGE, (int(x), int(y)), int(r))
# Корпус истребителя
pts = [(self.x, self.y - 24), (self.x - 22, self.y + 18), (self.x, self.y + 8), (self.x + 22, self.y + 18)]
glow_pts = [(self.x, self.y - 27), (self.x - 25, self.y + 21), (self.x, self.y + 10), (self.x + 25, self.y + 21)]
pygame.draw.polygon(surf, (*NEON_CYAN, 70), glow_pts)
pygame.draw.polygon(surf, NEON_CYAN, pts, 3)
pygame.draw.line(surf, WHITE, (self.x, self.y - 18), (self.x, self.y + 6), 2)
# Силовой щит
if self.shield > 0:
draw_glow_circle(surf, NEON_PURPLE, (int(self.x), int(self.y)), 32, glow_factor=2)
class Bullet:
def __init__(self, x, y, dx=0, dy=-14, color=NEON_YELLOW, is_enemy=False):
self.x = x
self.y = y
self.dx = dx
self.dy = dy
self.color = color
self.is_enemy = is_enemy
self.radius = 5 if is_enemy else 4
def update(self):
self.x += self.dx
self.y += self.dy
def draw(self, surf):
pygame.draw.circle(surf, self.color, (int(self.x), int(self.y)), self.radius)
trail_start = (int(self.x - self.dx * 1.5), int(self.y - self.dy * 1.5))
pygame.draw.line(surf, self.color, (int(self.x), int(self.y)), trail_start, 3)
class PowerUp:
def __init__(self, x, y):
self.x = x
self.y = y
self.type = random.choice(["triple", "shield", "bomb"])
self.color = NEON_GREEN if self.type == "triple" else (NEON_PURPLE if self.type == "shield" else NEON_ORANGE)
self.radius = 12
self.pulse = 0
def update(self):
self.y += 2
self.pulse += 0.1
def draw(self, surf):
r = int(self.radius + math.sin(self.pulse) * 3)
draw_glow_circle(surf, self.color, (int(self.x), int(self.y)), r, glow_factor=2)
letter = "3" if self.type == "triple" else ("S" if self.type == "shield" else "B")
txt = font_sm.render(letter, True, WHITE)
surf.blit(txt, (self.x - txt.get_width() // 2, self.y - txt.get_height() // 2))
class DroneEnemy:
def __init__(self, speed_mult):
self.x = random.randint(40, WIDTH - 40)
self.y = -30
self.speed = random.uniform(2.5, 4.2) * speed_mult
self.radius = 18
self.hp = 2
self.rot = 0
def update(self):
self.y += self.speed
self.rot += 0.08
def draw(self, surf):
pts = [
(self.x + math.cos(self.rot + i * math.pi / 2) * self.radius,
self.y + math.sin(self.rot + i * math.pi / 2) * self.radius)
for i in range(4)
]
pygame.draw.polygon(surf, NEON_PINK, pts, 2)
pygame.draw.circle(surf, WHITE, (int(self.x), int(self.y)), 3)
# БОСС 1: Тяжёлый разрушитель (Стреляет веерными залпами)
class DestroyerBoss:
def __init__(self):
self.x = WIDTH // 2
self.y = -100
self.target_y = 110
self.max_hp = 80
self.hp = self.max_hp
self.radius = 50
self.timer = 0
self.dir = 2.5
self.name = "CRUISER PROTO-9"
def update(self, bullets):
if self.y < self.target_y:
self.y += 2
else:
self.x += self.dir
if self.x < 100 or self.x > WIDTH - 100:
self.dir = -self.dir
self.timer += 1
if self.timer % 40 == 0:
for a in [-0.5, -0.25, 0, 0.25, 0.5]:
bullets.append(Bullet(self.x, self.y + 40, math.sin(a) * 6, math.cos(a) * 6, NEON_PINK, True))
def draw(self, surf):
pts = [(self.x, self.y + 45), (self.x - 55, self.y - 30), (self.x, self.y - 15), (self.x + 55, self.y - 30)]
pygame.draw.polygon(surf, NEON_PINK, pts, 3)
draw_glow_circle(surf, NEON_ORANGE, (int(self.x), int(self.y)), 16, glow_factor=2)
# БОСС 2: Снайпер-винг (Быстрый, круговая спиральная атака)
class DreadnoughtBoss:
def __init__(self):
self.x = WIDTH // 2
self.y = -120
self.target_y = 130
self.max_hp = 130
self.hp = self.max_hp
self.radius = 60
self.timer = 0
self.spiral_angle = 0
self.name = "CYBER DREADNOUGHT"
def update(self, bullets):
if self.y < self.target_y:
self.y += 2
else:
self.timer += 1
self.x = WIDTH // 2 + math.sin(self.timer * 0.03) * 220
# Спиральные залпы
if self.timer % 7 == 0:
self.spiral_angle += 0.4
vx = math.cos(self.spiral_angle) * 5
vy = math.sin(self.spiral_angle) * 5
bullets.append(Bullet(self.x, self.y, vx, vy, NEON_PURPLE, True))
def draw(self, surf):
# Двойное неоновое кольцо с шипами
pygame.draw.circle(surf, NEON_PURPLE, (int(self.x), int(self.y)), 52, 3)
pygame.draw.circle(surf, NEON_CYAN, (int(self.x), int(self.y)), 28, 2)
draw_glow_circle(surf, WHITE, (int(self.x), int(self.y)), 12, glow_factor=2)
class Particle:
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
angle = random.uniform(0, math.pi * 2)
speed = random.uniform(2, 7)
self.vx = math.cos(angle) * speed
self.vy = math.sin(angle) * speed
self.life = random.randint(18, 30)
def update(self):
self.x += self.vx
self.y += self.vy
self.life -= 1
def draw(self, surf):
if self.life > 0:
pygame.draw.circle(surf, self.color, (int(self.x), int(self.y)), max(1, self.life // 6))
def main():
player = Player()
bullets = []
enemies = []
particles = []
powerups = []
dmg_texts = []
boss = None
boss_sequence = 1
next_boss_score = 150
score = 0
shake = 0
game_over = False
# 3-слойный звёздный параллакс
stars = [
[random.randint(0, WIDTH), random.randint(0, HEIGHT), random.choice([1, 2, 3])]
for _ in range(90)
]
running = True
while running:
clock.tick(FPS)
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if game_over and event.key == pygame.K_r:
main()
return
# Ульта / EMP Бомба
if not game_over and event.key == pygame.K_e and player.bombs > 0:
player.bombs -= 1
shake = 28
bullets = [b for b in bullets if not b.is_enemy]
for e in enemies:
score += 15
for _ in range(12):
particles.append(Particle(e.x, e.y, NEON_ORANGE))
enemies.clear()
if boss:
boss.hp -= 25
dmg_texts.append(DamageText(boss.x, boss.y, 25, NEON_YELLOW))
if not game_over:
player.update(keys)
# Стрельба
if (keys[pygame.K_SPACE] or keys[pygame.K_j]) and player.cooldown == 0:
if player.triple_timer > 0:
bullets.append(Bullet(player.x, player.y - 20, 0, -15, NEON_YELLOW))
bullets.append(Bullet(player.x - 12, player.y - 12, -3.5, -14, NEON_YELLOW))
bullets.append(Bullet(player.x + 12, player.y - 12, 3.5, -14, NEON_YELLOW))
else:
bullets.append(Bullet(player.x, player.y - 20, 0, -15, NEON_YELLOW))
player.cooldown = 10
# Спавн боссов
if score >= next_boss_score and boss is None:
boss = DestroyerBoss() if boss_sequence % 2 != 0 else DreadnoughtBoss()
next_boss_score += 250
boss_sequence += 1
# Спавн обычных мобов
if boss is None and random.randint(1, 40) == 1:
enemies.append(DroneEnemy(1.0 + score / 600))
# Логика пуль
for b in bullets[:]:
b.update()
if b.y < -20 or b.y > HEIGHT + 20 or b.x < -20 or b.x > WIDTH + 20:
bullets.remove(b)
continue
if b.is_enemy:
if math.hypot(b.x - player.x, b.y - player.y) < 22:
bullets.remove(b)
if player.shield > 0:
player.shield -= 1
shake = 8
else:
game_over = True
shake = 30
else:
# Попадание по мобам
for e in enemies[:]:
if math.hypot(b.x - e.x, b.y - e.y) < e.radius + 6:
e.hp -= 1
dmg_texts.append(DamageText(e.x, e.y, 1))
if b in bullets:
bullets.remove(b)
if e.hp <= 0:
for _ in range(15):
particles.append(Particle(e.x, e.y, NEON_PINK))
if random.random() < 0.28:
powerups.append(PowerUp(e.x, e.y))
enemies.remove(e)
score += 15
shake = 4
break
# Попадание по боссу
if boss and b in bullets:
if math.hypot(b.x - boss.x, b.y - boss.y) < boss.radius:
boss.hp -= 1
dmg_texts.append(DamageText(boss.x, boss.y, 1))
bullets.remove(b)
if boss.hp <= 0:
for _ in range(60):
particles.append(Particle(boss.x, boss.y, NEON_ORANGE))
score += 200
shake = 35
boss = None
break
# Обновление босса
if boss:
boss.update(bullets)
# Обновление обычных мобов
for e in enemies[:]:
e.update()
if math.hypot(e.x - player.x, e.y - player.y) < e.radius + 18:
if player.shield > 0:
player.shield -= 1
enemies.remove(e)
shake = 10
else:
game_over = True
shake = 30
elif e.y > HEIGHT + 40:
enemies.remove(e)
# Подбор бонусов
for p in powerups[:]:
p.update()
if math.hypot(p.x - player.x, p.y - player.y) < 32:
if p.type == "triple":
player.triple_timer = 400
elif p.type == "shield":
player.shield = 1
elif p.type == "bomb":
player.bombs = min(3, player.bombs + 1)
powerups.remove(p)
elif p.y > HEIGHT:
powerups.remove(p)
# Тексты урона и частицы
for t in dmg_texts[:]:
t.update()
if t.life <= 0:
dmg_texts.remove(t)
for pt in particles[:]:
pt.update()
if pt.life <= 0:
particles.remove(pt)
# Движение фона
for s in stars:
s[1] += s[2] * 0.9
if s[1] > HEIGHT:
s[1] = 0
s[0] = random.randint(0, WIDTH)
# Виртуальный холст для отрисовки шейка
canvas = pygame.Surface((WIDTH, HEIGHT))
canvas.fill(BG_DARK)
for s in stars:
col = (100, 110, 150) if s[2] == 1 else (200, 220, 255)
pygame.draw.circle(canvas, col, (int(s[0]), int(s[1])), s[2] // 2 + 1)
for pt in particles:
pt.draw(canvas)
for p in powerups:
p.draw(canvas)
for b in bullets:
b.draw(canvas)
for e in enemies:
e.draw(canvas)
if boss:
boss.draw(canvas)
if not game_over:
player.draw(canvas)
for t in dmg_texts:
t.draw(canvas)
# Интерфейс
canvas.blit(font_md.render(f"SCORE: {score}", True, NEON_CYAN), (25, 20))
canvas.blit(font_sm.render(f"EMP BOMBS [E]: {'■ ' * player.bombs}", True, NEON_ORANGE), (25, 55))
if player.triple_timer > 0:
canvas.blit(font_sm.render("TRIPLE SHOT ACTIVE", True, NEON_GREEN), (25, 80))
# Полоса HP босса сверху
if boss:
bar_w = 400
bar_h = 12
bx = WIDTH // 2 - bar_w // 2
by = 25
ratio = max(0, boss.hp / boss.max_hp)
pygame.draw.rect(canvas, (40, 20, 40), (bx, by, bar_w, bar_h))
pygame.draw.rect(canvas, NEON_PINK, (bx, by, int(bar_w * ratio), bar_h))
pygame.draw.rect(canvas, WHITE, (bx, by, bar_w, bar_h), 1)
b_txt = font_sm.render(boss.name, True, WHITE)
canvas.blit(b_txt, (WIDTH // 2 - b_txt.get_width() // 2, by + 16))
if game_over:
t1 = font_lg.render("SYSTEM CRITICAL", True, NEON_PINK)
t2 = font_md.render("PRESS 'R' TO REBOOT", True, WHITE)
canvas.blit(t1, (WIDTH // 2 - t1.get_width() // 2, HEIGHT // 2 - 40))
canvas.blit(t2, (WIDTH // 2 - t2.get_width() // 2, HEIGHT // 2 + 30))
offset = [0, 0]
if shake > 0:
offset = [random.randint(-shake, shake), random.randint(-shake, shake)]
shake = max(0, shake - 2)
screen.blit(canvas, offset)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()