Загрузка данных
import pygame
import random
import math
import array
pygame.init()
pygame.mixer.init(frequency=22050, size=-16, channels=1, buffer=512)
WIDTH = 900
HEIGHT = 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("CYBER VOID // NEON OVERDRIVE: ULTIMATE")
clock = pygame.time.Clock()
FPS = 60
# Цветовая гамма
BG_COLOR = (6, 7, 14)
CYAN = (0, 245, 255)
PINK = (255, 30, 140)
YELLOW = (255, 235, 60)
ORANGE = (255, 120, 20)
PURPLE = (180, 50, 255)
GREEN = (40, 255, 130)
RED = (255, 60, 60)
WHITE = (255, 255, 255)
font_xs = pygame.font.SysFont("consolas", 14, bold=True)
font_sm = pygame.font.SysFont("consolas", 18, bold=True)
font_md = pygame.font.SysFont("consolas", 24, bold=True)
font_lg = pygame.font.SysFont("consolas", 56, bold=True)
# Процедурный генератор 8-bit звуков без внешних файлов
def make_sound(freq_start, freq_end, duration_sec=0.1, wave_type="square", vol=0.15):
sample_rate = 22050
n_samples = int(sample_rate * duration_sec)
buf = array.array('h')
for i in range(n_samples):
t = i / sample_rate
cur_freq = freq_start + (freq_end - freq_start) * (i / n_samples)
if wave_type == "square":
val = 1.0 if math.sin(2 * math.pi * cur_freq * t) > 0 else -1.0
elif wave_type == "noise":
val = random.uniform(-1.0, 1.0)
else: # sine
val = math.sin(2 * math.pi * cur_freq * t)
envelope = 1.0 - (i / n_samples)
sample = int(val * envelope * 32767 * vol)
buf.append(sample)
return pygame.mixer.Sound(buf)
try:
snd_pew = make_sound(880, 440, 0.08, "square", 0.08)
snd_rocket = make_sound(200, 60, 0.22, "noise", 0.18)
snd_boom = make_sound(160, 40, 0.35, "noise", 0.25)
snd_power = make_sound(400, 1200, 0.2, "sine", 0.2)
snd_emp = make_sound(300, 80, 0.6, "square", 0.3)
except Exception:
class DummySound:
def play(self): pass
snd_pew = snd_rocket = snd_boom = snd_power = snd_emp = DummySound()
def draw_glow_circle(surf, color, center, radius, glow_mult=2):
r_g = radius * glow_mult
g_surf = pygame.Surface((r_g * 2, r_g * 2), pygame.SRCALPHA)
pygame.draw.circle(g_surf, (*color, 35), (r_g, r_g), r_g)
pygame.draw.circle(g_surf, (*color, 110), (r_g, r_g), int(radius * 1.3))
pygame.draw.circle(g_surf, color, (r_g, r_g), radius)
surf.blit(g_surf, (center[0] - r_g, center[1] - r_g), special_flags=pygame.BLEND_ADD)
class DamageText:
def __init__(self, x, y, text, color=WHITE):
self.x = x + random.randint(-15, 15)
self.y = y
self.text = str(text)
self.color = color
self.life = 35
def update(self):
self.y -= 1.3
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 - 100
self.speed = 6.5
self.cooldown = 0
self.missile_cooldown = 0
self.shield = 2
self.max_shield = 3
self.bombs = 2
self.weapon_level = 1
self.angle = 0
self.trail = []
def update(self, keys, mouse_pos):
# Движение
if (keys[pygame.K_a] or keys[pygame.K_LEFT]) and self.x > 30:
self.x -= self.speed
if (keys[pygame.K_d] or keys[pygame.K_RIGHT]) and self.x < WIDTH - 30:
self.x += self.speed
if (keys[pygame.K_w] or keys[pygame.K_UP]) and self.y > 40:
self.y -= self.speed
if (keys[pygame.K_s] or keys[pygame.K_DOWN]) and self.y < HEIGHT - 40:
self.y += self.speed
# Вращение корпуса к курсору
dx = mouse_pos[0] - self.x
dy = mouse_pos[1] - self.y
self.angle = math.degrees(math.atan2(-dy, dx)) - 90
# Реактивный хвост
self.trail.append((self.x, self.y, 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(-0.8, 0.8), y + 2.5, r - 1.2)
if self.cooldown > 0:
self.cooldown -= 1
if self.missile_cooldown > 0:
self.missile_cooldown -= 1
def draw(self, surf):
for x, y, r in self.trail:
pygame.draw.circle(surf, ORANGE, (int(x), int(y)), int(r))
ship_surf = pygame.Surface((60, 60), pygame.SRCALPHA)
pts = [(30, 6), (10, 50), (30, 40), (50, 50)]
pygame.draw.polygon(ship_surf, CYAN, pts, 3)
pygame.draw.line(ship_surf, WHITE, (30, 10), (30, 36), 2)
rot_surf = pygame.transform.rotate(ship_surf, self.angle)
rect = rot_surf.get_rect(center=(self.x, self.y))
surf.blit(rot_surf, rect.topleft)
if self.shield > 0:
col = CYAN if self.shield == 1 else (PURPLE if self.shield == 2 else GREEN)
draw_glow_circle(surf, col, (int(self.x), int(self.y)), 30, glow_mult=2)
class Bullet:
def __init__(self, x, y, vx, vy, color=YELLOW, is_enemy=False, is_missile=False, dmg=1):
self.x = x
self.y = y
self.vx = vx
self.vy = vy
self.color = color
self.is_enemy = is_enemy
self.is_missile = is_missile
self.dmg = dmg
self.radius = 8 if is_missile else (5 if is_enemy else 4)
def update(self):
self.x += self.vx
self.y += self.vy
def draw(self, surf):
pygame.draw.circle(surf, self.color, (int(self.x), int(self.y)), self.radius)
if self.is_missile:
draw_glow_circle(surf, RED, (int(self.x), int(self.y)), 6, 2)
class Enemy:
def __init__(self, enemy_type, mult=1.0):
self.type = enemy_type # 'drone', 'interceptor', 'assault'
self.x = random.randint(50, WIDTH - 50)
self.y = -30
self.timer = 0
if self.type == "drone":
self.hp = 2
self.speed = 3.0 * mult
self.radius = 18
self.color = PINK
elif self.type == "interceptor":
self.hp = 1
self.speed = 5.2 * mult
self.radius = 14
self.color = ORANGE
elif self.type == "assault":
self.hp = 6
self.speed = 1.8 * mult
self.radius = 24
self.color = RED
def update(self, bullets, player_x, player_y):
self.y += self.speed
self.timer += 1
# Assault стреляет прицельным лазером
if self.type == "assault" and self.timer % 65 == 0:
angle = math.atan2(player_y - self.y, player_x - self.x)
bullets.append(Bullet(self.x, self.y, math.cos(angle)*5, math.sin(angle)*5, RED, True))
def draw(self, surf):
if self.type == "drone":
pts = [(self.x, self.y - self.radius), (self.x - self.radius, self.y + self.radius),
(self.x, self.y + 8), (self.x + self.radius, self.y + self.radius)]
pygame.draw.polygon(surf, self.color, pts, 2)
elif self.type == "interceptor":
pts = [(self.x, self.y + self.radius), (self.x - self.radius//2, self.y - self.radius),
(self.x + self.radius//2, self.y - self.radius)]
pygame.draw.polygon(surf, self.color, pts, 2)
else:
pygame.draw.circle(surf, self.color, (int(self.x), int(self.y)), self.radius, 2)
pygame.draw.circle(surf, WHITE, (int(self.x), int(self.y)), 6)
class Boss:
def __init__(self, btype=1):
self.btype = btype
self.x = WIDTH // 2
self.y = -120
self.target_y = 125
self.timer = 0
self.dir = 2.8
self.spiral = 0.0
if btype == 1:
self.name = "CORVETTE PROMETHEUS"
self.max_hp = 100
self.radius = 55
self.color = PINK
elif btype == 2:
self.name = "DREADNOUGHT VORTEX"
self.max_hp = 180
self.radius = 65
self.color = PURPLE
else:
self.name = "CYBER CORE TITAN"
self.max_hp = 260
self.radius = 75
self.color = RED
self.hp = self.max_hp
def update(self, bullets, player_x, player_y):
if self.y < self.target_y:
self.y += 2
else:
self.timer += 1
if self.btype == 1:
self.x += self.dir
if self.x < 110 or self.x > WIDTH - 110:
self.dir = -self.dir
if self.timer % 32 == 0:
for a in [-0.4, -0.2, 0, 0.2, 0.4]:
bullets.append(Bullet(self.x, self.y + 35, math.sin(a)*6, math.cos(a)*6, PINK, True))
elif self.btype == 2:
self.x = WIDTH // 2 + math.sin(self.timer * 0.035) * 260
if self.timer % 5 == 0:
self.spiral += 0.42
bullets.append(Bullet(self.x, self.y, math.cos(self.spiral)*5.5, math.sin(self.spiral)*5.5, PURPLE, True))
else: # Titan
self.x = WIDTH // 2 + math.cos(self.timer * 0.02) * 180
if self.timer % 40 == 0:
ang = math.atan2(player_y - self.y, player_x - self.x)
for spread in [-0.2, 0, 0.2]:
bullets.append(Bullet(self.x, self.y, math.cos(ang+spread)*7, math.sin(ang+spread)*7, RED, True, dmg=2))
def draw(self, surf):
draw_glow_circle(surf, self.color, (int(self.x), int(self.y)), self.radius - 10, glow_mult=2)
pygame.draw.circle(surf, WHITE, (int(self.x), int(self.y)), self.radius, 3)
class PowerUp:
def __init__(self, x, y):
self.x = x
self.y = y
self.type = random.choice(["weapon", "shield", "bomb"])
self.radius = 13
self.pulse = 0
if self.type == "weapon":
self.color = YELLOW
self.label = "W"
elif self.type == "shield":
self.color = CYAN
self.label = "S"
else:
self.color = ORANGE
self.label = "B"
def update(self):
self.y += 2
self.pulse += 0.1
def draw(self, surf):
r = int(self.radius + math.sin(self.pulse) * 2.5)
draw_glow_circle(surf, self.color, (int(self.x), int(self.y)), r, glow_mult=2)
txt = font_sm.render(self.label, True, WHITE)
surf.blit(txt, (self.x - txt.get_width() // 2, self.y - txt.get_height() // 2))
class Particle:
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
ang = random.uniform(0, math.pi * 2)
spd = random.uniform(2, 7.5)
self.vx = math.cos(ang) * spd
self.vy = math.sin(ang) * spd
self.life = random.randint(20, 36)
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
score = 0
combo = 0
combo_timer = 0
boss_cycle = 1
next_boss_score = 250
shake = 0
game_over = False
stars = [[random.randint(0, WIDTH), random.randint(0, HEIGHT), random.choice([1, 2, 3])] for _ in range(110)]
running = True
while running:
clock.tick(FPS)
keys = pygame.key.get_pressed()
mouse_pos = pygame.mouse.get_pos()
mouse_pressed = pygame.mouse.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 = 30
snd_emp.play()
bullets = [b for b in bullets if not b.is_enemy]
for e in enemies:
score += 20
for _ in range(12):
particles.append(Particle(e.x, e.y, ORANGE))
enemies.clear()
if boss:
boss.hp -= 35
dmg_texts.append(DamageText(boss.x, boss.y, 35, YELLOW))
if not game_over:
player.update(keys, mouse_pos)
# Стрельба на ЛКМ (Primary Gun)
if mouse_pressed[0] and player.cooldown == 0:
snd_pew.play()
ang = math.atan2(mouse_pos[1] - player.y, mouse_pos[0] - player.x)
spd = 16
if player.weapon_level == 1:
bullets.append(Bullet(player.x, player.y, math.cos(ang)*spd, math.sin(ang)*spd, YELLOW))
elif player.weapon_level == 2:
p1 = (player.x + math.cos(ang + math.pi/2)*10, player.y + math.sin(ang + math.pi/2)*10)
p2 = (player.x + math.cos(ang - math.pi/2)*10, player.y + math.sin(ang - math.pi/2)*10)
bullets.append(Bullet(p1[0], p1[1], math.cos(ang)*spd, math.sin(ang)*spd, YELLOW))
bullets.append(Bullet(p2[0], p2[1], math.cos(ang)*spd, math.sin(ang)*spd, YELLOW))
elif player.weapon_level == 3:
for spread in [-0.18, 0, 0.18]:
bullets.append(Bullet(player.x, player.y, math.cos(ang+spread)*spd, math.sin(ang+spread)*spd, GREEN))
else: # Level 4 Overdrive
for spread in [-0.3, -0.15, 0, 0.15, 0.3]:
bullets.append(Bullet(player.x, player.y, math.cos(ang+spread)*spd, math.sin(ang+spread)*spd, CYAN))
player.cooldown = 9
# Тяжёлая ракета на ПКМ (Secondary Weapon)
if mouse_pressed[2] and player.missile_cooldown == 0:
snd_rocket.play()
ang = math.atan2(mouse_pos[1] - player.y, mouse_pos[0] - player.x)
bullets.append(Bullet(player.x, player.y, math.cos(ang)*11, math.sin(ang)*11, ORANGE, is_missile=True, dmg=5))
player.missile_cooldown = 35
# Таймер комбо
if combo_timer > 0:
combo_timer -= 1
else:
combo = 0
# Спавн боссов
if score >= next_boss_score and boss is None:
b_type = (boss_cycle % 3)
boss = Boss(3 if b_type == 0 else b_type)
next_boss_score += 350
boss_cycle += 1
# Спавн врагов волнами
if boss is None and random.randint(1, 35) == 1:
e_choice = random.choices(["drone", "interceptor", "assault"], weights=[60, 25, 15])[0]
enemies.append(Enemy(e_choice, 1.0 + score / 800))
# Обновление снарядов
for b in bullets[:]:
b.update()
if b.y < -30 or b.y > HEIGHT + 30 or b.x < -30 or b.x > WIDTH + 30:
bullets.remove(b)
continue
if b.is_enemy:
if math.hypot(b.x - player.x, b.y - player.y) < 24:
bullets.remove(b)
if player.shield > 0:
player.shield -= 1
shake = 10
snd_boom.play()
else:
game_over = True
shake = 35
snd_boom.play()
else:
# Попадание по мобам
for e in enemies[:]:
if math.hypot(b.x - e.x, b.y - e.y) < e.radius + b.radius:
e.hp -= b.dmg
dmg_texts.append(DamageText(e.x, e.y, b.dmg, YELLOW if not b.is_missile else ORANGE))
if not b.is_missile and b in bullets:
bullets.remove(b)
if e.hp <= 0:
snd_boom.play()
for _ in range(16):
particles.append(Particle(e.x, e.y, e.color))
if random.random() < 0.25:
powerups.append(PowerUp(e.x, e.y))
enemies.remove(e)
combo += 1
combo_timer = 90
score += 10 * min(5, combo)
shake = 4
break
# Попадание по боссу
if boss and b in bullets:
if math.hypot(b.x - boss.x, b.y - boss.y) < boss.radius + b.radius:
boss.hp -= b.dmg
dmg_texts.append(DamageText(boss.x, boss.y, b.dmg, RED))
if not b.is_missile:
bullets.remove(b)
if boss.hp <= 0:
snd_boom.play()
for _ in range(65):
particles.append(Particle(boss.x, boss.y, boss.color))
score += 300
shake = 35
boss = None
break
if boss:
boss.update(bullets, player.x, player.y)
# Обновление мобов
for e in enemies[:]:
e.update(bullets, player.x, player.y)
if math.hypot(e.x - player.x, e.y - player.y) < e.radius + 20:
if player.shield > 0:
player.shield -= 1
enemies.remove(e)
shake = 12
else:
game_over = True
shake = 35
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:
snd_power.play()
if p.type == "weapon":
player.weapon_level = min(4, player.weapon_level + 1)
elif p.type == "shield":
player.shield = min(player.max_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] * 1.1
if s[1] > HEIGHT:
s[1] = 0
s[0] = random.randint(0, WIDTH)
# Холст с эффектом тряски экрана
canvas = pygame.Surface((WIDTH, HEIGHT))
canvas.fill(BG_COLOR)
for s in stars:
col = (90, 100, 140) if s[2] == 1 else (180, 210, 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)
# Прицел на позиции мыши
mx, my = mouse_pos
pygame.draw.circle(canvas, CYAN, (mx, my), 10, 1)
pygame.draw.line(canvas, CYAN, (mx - 14, my), (mx + 14, my), 1)
pygame.draw.line(canvas, CYAN, (mx, my - 14), (mx, my + 14), 1)
# HUD / Интерфейс
canvas.blit(font_md.render(f"SCORE: {score}", True, CYAN), (25, 20))
if combo > 1:
canvas.blit(font_sm.render(f"COMBO: x{combo}", True, YELLOW), (25, 52))
canvas.blit(font_sm.render(f"WEAPON LVL: {player.weapon_level}/4", True, GREEN), (25, 80))
canvas.blit(font_sm.render(f"SHIELDS: {'▲ ' * player.shield}", True, CYAN), (25, 105))
canvas.blit(font_sm.render(f"EMP BOMBS [E]: {'■ ' * player.bombs}", True, ORANGE), (25, 130))
# Перезарядка ракеты (ПКМ)
m_bar_w = 100
m_fill = int((1.0 - (player.missile_cooldown / 35)) * m_bar_w)
pygame.draw.rect(canvas, (40, 40, 50), (25, 160, m_bar_w, 8))
pygame.draw.rect(canvas, ORANGE, (25, 160, m_fill, 8))
canvas.blit(font_xs.render("ROCKET [RMB]", True, WHITE), (135, 156))
# Полоса HP босса
if boss:
bar_w = 460
bx = WIDTH // 2 - bar_w // 2
by = 25
ratio = max(0, boss.hp / boss.max_hp)
pygame.draw.rect(canvas, (40, 20, 30), (bx, by, bar_w, 14))
pygame.draw.rect(canvas, boss.color, (bx, by, int(bar_w * ratio), 14))
pygame.draw.rect(canvas, WHITE, (bx, by, bar_w, 14), 2)
btxt = font_sm.render(f"{boss.name} [{int(boss.hp)}/{boss.max_hp}]", True, WHITE)
canvas.blit(btxt, (WIDTH // 2 - btxt.get_width() // 2, by + 18))
if game_over:
t1 = font_lg.render("SYSTEM FAILURE", True, PINK)
t2 = font_md.render("PRESS 'R' TO RESTART OPERATION", True, WHITE)
canvas.blit(t1, (WIDTH // 2 - t1.get_width() // 2, HEIGHT // 2 - 50))
canvas.blit(t2, (WIDTH // 2 - t2.get_width() // 2, HEIGHT // 2 + 25))
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()