1162 lines
49 KiB
Python
1162 lines
49 KiB
Python
import pygame
|
|
import random
|
|
import sys
|
|
|
|
# --- Initialize Pygame and Mixer ---
|
|
pygame.init()
|
|
pygame.mixer.init()
|
|
|
|
# --- Screen Settings ---
|
|
SCREEN_WIDTH = 800
|
|
SCREEN_HEIGHT = 600
|
|
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
|
|
pygame.display.set_caption("Cosmic Pixels")
|
|
clock = pygame.time.Clock()
|
|
|
|
# --- Colors ---
|
|
BLACK = (0, 0, 0)
|
|
WHITE = (255, 255, 255)
|
|
CYAN = (0, 255, 255)
|
|
YELLOW = (255, 255, 0)
|
|
PLAYER_COLOR = (0, 200, 255) # Fallback color
|
|
RED = (255, 0, 0)
|
|
GREEN = (0, 255, 0)
|
|
ORANGE = (255, 165, 0)
|
|
|
|
# --- Load Assets (Font and Music) ---
|
|
try:
|
|
title_font = pygame.font.Font('pixel_font.ttf', 72)
|
|
prompt_font = pygame.font.Font('pixel_font.ttf', 30)
|
|
score_font = pygame.font.Font('pixel_font.ttf', 24)
|
|
except FileNotFoundError:
|
|
title_font = pygame.font.SysFont('Consolas', 72, bold=True)
|
|
prompt_font = pygame.font.SysFont('Consolas', 30)
|
|
score_font = pygame.font.SysFont('Consolas', 24)
|
|
|
|
|
|
# --- Load Sound Effects ---
|
|
try:
|
|
shoot_sound = pygame.mixer.Sound('laser_shoot.wav')
|
|
explosion_sound = pygame.mixer.Sound('explosion.wav')
|
|
death_sound = pygame.mixer.Sound('player_death.wav')
|
|
print("Sound effects loaded.")
|
|
except pygame.error:
|
|
print("Warning: One or more sound effect files are missing.")
|
|
shoot_sound = None
|
|
explosion_sound = None
|
|
death_sound = None
|
|
|
|
# --- Starfield Setup ---
|
|
stars = []
|
|
for _ in range(200):
|
|
x = random.randrange(0, SCREEN_WIDTH)
|
|
y = random.randrange(0, SCREEN_HEIGHT)
|
|
speed = random.randint(1, 3)
|
|
stars.append([x, y, speed])
|
|
|
|
# --- Bullet Class ---
|
|
class Bullet:
|
|
def __init__(self, x, y, dx, dy):
|
|
self.rect = pygame.Rect(x, y, 10, 5)
|
|
self.dx = dx
|
|
self.dy = dy
|
|
|
|
def update(self):
|
|
self.rect.x += self.dx
|
|
self.rect.y += self.dy
|
|
|
|
# --- Letter Class for Animation ---
|
|
class Letter:
|
|
def __init__(self, char, font, color, start_pos, end_pos, anim_duration=0.5):
|
|
self.surface = font.render(char, True, color)
|
|
self.start_pos = pygame.Vector2(start_pos)
|
|
self.end_pos = pygame.Vector2(end_pos)
|
|
self.current_pos = pygame.Vector2(start_pos)
|
|
self.anim_duration_ms = anim_duration * 1000
|
|
self.anim_start_time = 0
|
|
self.is_animating = False
|
|
self.is_finished = False
|
|
|
|
def start_animation(self):
|
|
self.is_animating = True
|
|
self.anim_start_time = pygame.time.get_ticks()
|
|
|
|
def update(self):
|
|
if not self.is_animating: return
|
|
elapsed_time = pygame.time.get_ticks() - self.anim_start_time
|
|
progress = min(elapsed_time / self.anim_duration_ms, 1.0)
|
|
progress = 1 - (1 - progress) ** 3
|
|
self.current_pos = self.start_pos.lerp(self.end_pos, progress)
|
|
if progress >= 1.0:
|
|
self.is_animating = False
|
|
self.is_finished = True
|
|
|
|
def draw(self, screen):
|
|
screen.blit(self.surface, self.current_pos)
|
|
|
|
# --- Game Loop Function (Level 1) ---
|
|
def game_loop():
|
|
"""This function runs the main gameplay for Level 1."""
|
|
|
|
pygame.mixer.music.stop()
|
|
try:
|
|
pygame.mixer.music.load('level1.wav')
|
|
pygame.mixer.music.play(-1)
|
|
except pygame.error:
|
|
print("Warning: Music file 'level1.wav' not found.")
|
|
|
|
try:
|
|
player_image = pygame.image.load('layer.png').convert_alpha()
|
|
player_image = pygame.transform.scale(player_image, (80, 40))
|
|
except pygame.error:
|
|
player_image = None
|
|
player_rect = player_image.get_rect() if player_image else pygame.Rect(0, 0, 80, 40)
|
|
player_rect.x = 50
|
|
player_rect.centery = SCREEN_HEIGHT / 2
|
|
PLAYER_SPEED = 5
|
|
player_health = 100
|
|
max_health = 100
|
|
player_dead = False
|
|
death_timer_start = 0
|
|
|
|
score = 0
|
|
kill_count = 0
|
|
kills_for_boss = 20
|
|
boss_fight_active = False
|
|
boss_defeated = False
|
|
|
|
player_bullets = []
|
|
enemy_bullets = []
|
|
boss_bullets = []
|
|
|
|
try:
|
|
enemy_image = pygame.image.load('enemy_ship.png').convert_alpha()
|
|
enemy_image = pygame.transform.scale(enemy_image, (50, 50))
|
|
except pygame.error:
|
|
enemy_image = None
|
|
enemies = []
|
|
ENEMY_SPEED = 3
|
|
ENEMY_SPAWN_EVENT = pygame.USEREVENT + 1
|
|
pygame.time.set_timer(ENEMY_SPAWN_EVENT, 1000)
|
|
|
|
try:
|
|
boss_image = pygame.image.load('boss_level1.png').convert_alpha()
|
|
boss_image = pygame.transform.scale(boss_image, (150, 100))
|
|
except pygame.error:
|
|
boss_image = None
|
|
boss_rect = None
|
|
boss_health = 200
|
|
boss_max_health = 200
|
|
boss_speed = 2
|
|
boss_direction = 1
|
|
boss_is_entering = False
|
|
|
|
thruster_length = 10
|
|
|
|
running = True
|
|
while running:
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT:
|
|
pygame.quit()
|
|
sys.exit()
|
|
|
|
if event.type == pygame.KEYDOWN and not boss_defeated and not player_dead:
|
|
if event.key == pygame.K_SPACE:
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, 0))
|
|
if shoot_sound: shoot_sound.play()
|
|
|
|
if event.type == ENEMY_SPAWN_EVENT and not boss_fight_active:
|
|
enemy_y_pos = random.randint(50, SCREEN_HEIGHT - 50)
|
|
enemy_rect = enemy_image.get_rect(midleft=(SCREEN_WIDTH + 20, enemy_y_pos)) if enemy_image else pygame.Rect(SCREEN_WIDTH + 20, enemy_y_pos, 50, 50)
|
|
enemies.append(enemy_rect)
|
|
|
|
if not boss_defeated and not player_dead:
|
|
keys = pygame.key.get_pressed()
|
|
is_moving_forward = False
|
|
if keys[pygame.K_LEFT]: player_rect.x -= PLAYER_SPEED
|
|
if keys[pygame.K_RIGHT]:
|
|
player_rect.x += PLAYER_SPEED
|
|
is_moving_forward = True
|
|
if keys[pygame.K_UP]: player_rect.y -= PLAYER_SPEED
|
|
if keys[pygame.K_DOWN]: player_rect.y += PLAYER_SPEED
|
|
thruster_length = 25 if is_moving_forward else 10
|
|
|
|
if not player_dead:
|
|
if player_rect.left < 0: player_rect.left = 0
|
|
if player_rect.right > SCREEN_WIDTH and not boss_defeated: player_rect.right = SCREEN_WIDTH
|
|
if player_rect.top < 0: player_rect.top = 0
|
|
if player_rect.bottom > SCREEN_HEIGHT: player_rect.bottom = SCREEN_HEIGHT
|
|
|
|
for bullet in player_bullets: bullet.update()
|
|
for bullet in enemy_bullets: bullet.x -= 10
|
|
for bullet in boss_bullets: bullet.x -= 12
|
|
for enemy in enemies:
|
|
enemy.x -= ENEMY_SPEED
|
|
if random.randint(0, 150) == 1:
|
|
enemy_bullet = pygame.Rect(enemy.left, enemy.centery - 2, 10, 5)
|
|
enemy_bullets.append(enemy_bullet)
|
|
|
|
if not player_dead:
|
|
for bullet in player_bullets[:]:
|
|
bullet_removed = False
|
|
for enemy in enemies[:]:
|
|
if bullet.rect.colliderect(enemy):
|
|
enemies.remove(enemy)
|
|
player_bullets.remove(bullet)
|
|
score += 10
|
|
kill_count += 1
|
|
if explosion_sound: explosion_sound.play()
|
|
bullet_removed = True
|
|
break
|
|
if bullet_removed: continue
|
|
|
|
for enemy in enemies[:]:
|
|
if player_rect.colliderect(enemy):
|
|
enemies.remove(enemy)
|
|
player_health -= 25
|
|
if explosion_sound: explosion_sound.play()
|
|
|
|
for bullet in enemy_bullets[:] + boss_bullets[:]:
|
|
if player_rect.colliderect(bullet):
|
|
if bullet in enemy_bullets: enemy_bullets.remove(bullet)
|
|
if bullet in boss_bullets: boss_bullets.remove(bullet)
|
|
player_health -= 10
|
|
|
|
if boss_fight_active and boss_rect and not boss_defeated:
|
|
if boss_is_entering:
|
|
entry_target_x = SCREEN_WIDTH - boss_rect.width - 20
|
|
if boss_rect.x > entry_target_x: boss_rect.x -= 5
|
|
else: boss_is_entering = False
|
|
else:
|
|
boss_rect.y += boss_speed * boss_direction
|
|
if boss_rect.top <= 0 or boss_rect.bottom >= SCREEN_HEIGHT: boss_direction *= -1
|
|
if random.randint(0, 40) == 1:
|
|
boss_bullet = pygame.Rect(boss_rect.left, boss_rect.centery, 15, 8)
|
|
boss_bullets.append(boss_bullet)
|
|
|
|
for bullet in player_bullets[:]:
|
|
if bullet.rect.colliderect(boss_rect):
|
|
player_bullets.remove(bullet)
|
|
boss_health -= 5
|
|
if boss_health <= 0:
|
|
boss_defeated = True
|
|
if explosion_sound: explosion_sound.play()
|
|
pygame.mixer.music.fadeout(2000)
|
|
boss_rect = None
|
|
enemy_bullets.clear()
|
|
boss_bullets.clear()
|
|
break
|
|
|
|
if kill_count >= kills_for_boss and not boss_fight_active:
|
|
boss_fight_active = True
|
|
boss_is_entering = True
|
|
enemies.clear()
|
|
pygame.time.set_timer(ENEMY_SPAWN_EVENT, 0)
|
|
print("BOSS FIGHT STARTED!")
|
|
boss_rect = boss_image.get_rect(midleft=(SCREEN_WIDTH, SCREEN_HEIGHT / 2)) if boss_image else pygame.Rect(SCREEN_WIDTH, SCREEN_HEIGHT/2 - 50, 150, 100)
|
|
|
|
if player_health <= 0 and not player_dead:
|
|
player_dead = True
|
|
if death_sound: death_sound.play()
|
|
death_timer_start = pygame.time.get_ticks()
|
|
pygame.mixer.music.stop()
|
|
|
|
if player_dead:
|
|
if pygame.time.get_ticks() - death_timer_start > 2000:
|
|
fade_surface = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
|
|
fade_surface.fill(BLACK)
|
|
for alpha in range(0, 255, 5):
|
|
fade_surface.set_alpha(alpha)
|
|
screen.blit(fade_surface, (0,0))
|
|
pygame.display.flip()
|
|
pygame.time.delay(30)
|
|
|
|
died_text = title_font.render("YOU DIED", True, RED)
|
|
died_rect = died_text.get_rect(center=(SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
|
|
screen.blit(died_text, died_rect)
|
|
pygame.display.flip()
|
|
pygame.time.wait(3000)
|
|
return
|
|
|
|
if boss_defeated:
|
|
player_rect.x += PLAYER_SPEED
|
|
if player_rect.left > SCREEN_WIDTH:
|
|
fade_surface = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
|
|
fade_surface.fill(BLACK)
|
|
for alpha in range(0, 255, 5):
|
|
fade_surface.set_alpha(alpha)
|
|
screen.blit(fade_surface, (0,0))
|
|
pygame.display.flip()
|
|
pygame.time.delay(30)
|
|
|
|
level2_text = title_font.render("LEVEL 2", True, WHITE)
|
|
level2_rect = level2_text.get_rect(center=(SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
|
|
screen.blit(level2_text, level2_rect)
|
|
pygame.display.flip()
|
|
pygame.time.wait(3000)
|
|
level_2_loop(player_health, score)
|
|
running = False
|
|
|
|
screen.fill(BLACK)
|
|
for star in stars:
|
|
star[0] -= star[2]
|
|
if star[0] < 0: star[0] = SCREEN_WIDTH; star[1] = random.randrange(0, SCREEN_HEIGHT)
|
|
pygame.draw.rect(screen, WHITE, (star[0], star[1], star[2], star[2]))
|
|
|
|
player_bullets = [b for b in player_bullets if b.rect.left < SCREEN_WIDTH]
|
|
for bullet in player_bullets: pygame.draw.rect(screen, YELLOW, bullet.rect)
|
|
|
|
enemy_bullets = [b for b in enemy_bullets if b.right > 0]
|
|
for bullet in enemy_bullets: pygame.draw.rect(screen, RED, bullet)
|
|
|
|
boss_bullets = [b for b in boss_bullets if b.right > 0]
|
|
for bullet in boss_bullets: pygame.draw.rect(screen, RED, bullet)
|
|
|
|
enemies = [e for e in enemies if e.right > 0]
|
|
for enemy in enemies:
|
|
if enemy_image: screen.blit(enemy_image, enemy)
|
|
else: pygame.draw.rect(screen, RED, enemy)
|
|
|
|
if boss_rect:
|
|
if boss_image: screen.blit(boss_image, boss_rect)
|
|
else: pygame.draw.rect(screen, CYAN, boss_rect)
|
|
|
|
if not player_dead:
|
|
if boss_defeated:
|
|
thruster_length = 25 # Keep thrust on during fly-off
|
|
thruster_rect = pygame.Rect(player_rect.left - thruster_length, player_rect.centery - 5, thruster_length, 10)
|
|
pygame.draw.rect(screen, ORANGE, thruster_rect)
|
|
if player_image: screen.blit(player_image, player_rect)
|
|
else: pygame.draw.rect(screen, PLAYER_COLOR, player_rect)
|
|
|
|
health_bar_width = max(0, (player_health / max_health) * 200)
|
|
pygame.draw.rect(screen, RED, (10, 10, 200, 20))
|
|
pygame.draw.rect(screen, GREEN, (10, 10, health_bar_width, 20))
|
|
|
|
score_text = score_font.render(f"Score: {score}", True, WHITE)
|
|
screen.blit(score_text, score_text.get_rect(center=(SCREEN_WIDTH / 2, 20)))
|
|
|
|
if boss_fight_active and not boss_defeated and boss_rect:
|
|
boss_health_width = max(0, (boss_health / boss_max_health) * 200)
|
|
pygame.draw.rect(screen, RED, (SCREEN_WIDTH - 210, 10, 200, 20))
|
|
pygame.draw.rect(screen, GREEN, (SCREEN_WIDTH - 210, 10, boss_health_width, 20))
|
|
|
|
pygame.display.flip()
|
|
clock.tick(60)
|
|
|
|
def level_2_loop(player_health, score):
|
|
pygame.mixer.music.stop()
|
|
try:
|
|
pygame.mixer.music.load('level2.wav')
|
|
pygame.mixer.music.play(-1)
|
|
except pygame.error:
|
|
print("Warning: Music file 'level2.wav' not found.")
|
|
|
|
try:
|
|
player_image = pygame.image.load('layer.png').convert_alpha()
|
|
player_image = pygame.transform.scale(player_image, (80, 40))
|
|
except pygame.error:
|
|
player_image = None
|
|
player_rect = player_image.get_rect() if player_image else pygame.Rect(0, 0, 80, 40)
|
|
player_rect.x = 50
|
|
player_rect.centery = SCREEN_HEIGHT / 2
|
|
PLAYER_SPEED = 5
|
|
max_health = 100
|
|
player_dead = False
|
|
death_timer_start = 0
|
|
|
|
player_has_triple_shot = False
|
|
powerup_spawned = False
|
|
powerup_active_start_time = 0
|
|
POWERUP_DURATION = 30000
|
|
try:
|
|
powerup_image = pygame.image.load('powerup_triple_shot.png').convert_alpha()
|
|
powerup_image = pygame.transform.scale(powerup_image, (40, 40))
|
|
except pygame.error:
|
|
powerup_image = None
|
|
powerup_rect = None
|
|
|
|
try:
|
|
mine_image = pygame.image.load('space_mine.png').convert_alpha()
|
|
mine_image = pygame.transform.scale(mine_image, (40, 40))
|
|
except pygame.error:
|
|
mine_image = None
|
|
mines = []
|
|
MINE_SPAWN_EVENT = pygame.USEREVENT + 2
|
|
pygame.time.set_timer(MINE_SPAWN_EVENT, 2000)
|
|
|
|
try:
|
|
enemy_image = pygame.image.load('enemy_ship.png').convert_alpha()
|
|
enemy_image = pygame.transform.scale(enemy_image, (50, 50))
|
|
except pygame.error:
|
|
enemy_image = None
|
|
enemies = []
|
|
ENEMY_SPEED_L2 = 4
|
|
ENEMY_SPAWN_EVENT_L2 = pygame.USEREVENT + 3
|
|
pygame.time.set_timer(ENEMY_SPAWN_EVENT_L2, 800)
|
|
|
|
kill_count = 0
|
|
kills_for_powerup = 10
|
|
kills_for_boss = 40
|
|
|
|
boss_fight_active = False
|
|
boss_defeated = False
|
|
try:
|
|
boss_image = pygame.image.load('boss_level2.png').convert_alpha()
|
|
boss_image = pygame.transform.scale(boss_image, (170, 120))
|
|
except pygame.error:
|
|
print("Warning: 'boss_level2.png' not found.")
|
|
boss_image = None
|
|
boss_rect = None
|
|
boss_health = 400
|
|
boss_max_health = 400
|
|
boss_speed = 3
|
|
boss_direction = 1
|
|
boss_is_entering = False
|
|
|
|
player_bullets = []
|
|
enemy_bullets = []
|
|
boss_bullets = []
|
|
thruster_length = 10
|
|
|
|
running = True
|
|
while running:
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT:
|
|
pygame.quit()
|
|
sys.exit()
|
|
|
|
if event.type == pygame.KEYDOWN and not boss_defeated and not player_dead:
|
|
if event.key == pygame.K_SPACE:
|
|
if player_has_triple_shot:
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, -2))
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, 0))
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, 2))
|
|
else:
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, 0))
|
|
if shoot_sound: shoot_sound.play()
|
|
|
|
if event.type == MINE_SPAWN_EVENT and not boss_fight_active:
|
|
mine_y = random.randint(20, SCREEN_HEIGHT - 20)
|
|
mine_rect = mine_image.get_rect(center=(SCREEN_WIDTH + 20, mine_y)) if mine_image else pygame.Rect(SCREEN_WIDTH + 20, mine_y, 40, 40)
|
|
mines.append(mine_rect)
|
|
|
|
if event.type == ENEMY_SPAWN_EVENT_L2 and not boss_fight_active:
|
|
enemy_y_pos = random.randint(50, SCREEN_HEIGHT - 50)
|
|
enemy_rect = enemy_image.get_rect(midleft=(SCREEN_WIDTH + 20, enemy_y_pos)) if enemy_image else pygame.Rect(SCREEN_WIDTH + 20, enemy_y_pos, 50, 50)
|
|
enemies.append(enemy_rect)
|
|
|
|
if not boss_defeated and not player_dead:
|
|
keys = pygame.key.get_pressed()
|
|
is_moving_forward = False
|
|
if keys[pygame.K_LEFT]: player_rect.x -= PLAYER_SPEED
|
|
if keys[pygame.K_RIGHT]:
|
|
player_rect.x += PLAYER_SPEED
|
|
is_moving_forward = True
|
|
if keys[pygame.K_UP]: player_rect.y -= PLAYER_SPEED
|
|
if keys[pygame.K_DOWN]: player_rect.y += PLAYER_SPEED
|
|
thruster_length = 25 if is_moving_forward else 10
|
|
|
|
if not player_dead:
|
|
if player_rect.left < 0: player_rect.left = 0
|
|
if player_rect.right > SCREEN_WIDTH and not boss_defeated: player_rect.right = SCREEN_WIDTH
|
|
if player_rect.top < 0: player_rect.top = 0
|
|
if player_rect.bottom > SCREEN_HEIGHT: player_rect.bottom = SCREEN_HEIGHT
|
|
|
|
if kill_count >= kills_for_powerup and not powerup_spawned:
|
|
powerup_spawned = True
|
|
powerup_rect = powerup_image.get_rect(center=(SCREEN_WIDTH + 30, SCREEN_HEIGHT / 2)) if powerup_image else pygame.Rect(SCREEN_WIDTH + 30, SCREEN_HEIGHT / 2, 40, 40)
|
|
|
|
if player_has_triple_shot:
|
|
elapsed_time = pygame.time.get_ticks() - powerup_active_start_time
|
|
if elapsed_time > POWERUP_DURATION:
|
|
player_has_triple_shot = False
|
|
|
|
for bullet in player_bullets: bullet.update()
|
|
for bullet in enemy_bullets: bullet.x -= 10
|
|
for bullet in boss_bullets: bullet.update()
|
|
for enemy in enemies:
|
|
enemy.x -= ENEMY_SPEED_L2
|
|
if random.randint(0, 120) == 1:
|
|
enemy_bullet = pygame.Rect(enemy.left, enemy.centery - 2, 10, 5)
|
|
enemy_bullets.append(enemy_bullet)
|
|
for mine in mines: mine.x -= 2
|
|
if powerup_rect: powerup_rect.x -= 3
|
|
|
|
if not player_dead:
|
|
for mine in mines[:]:
|
|
if player_rect.colliderect(mine):
|
|
mines.remove(mine)
|
|
player_health -= 20
|
|
if explosion_sound: explosion_sound.play()
|
|
|
|
for bullet in player_bullets[:]:
|
|
bullet_removed = False
|
|
for enemy in enemies[:]:
|
|
if bullet.rect.colliderect(enemy):
|
|
enemies.remove(enemy)
|
|
player_bullets.remove(bullet)
|
|
score += 15
|
|
kill_count += 1
|
|
if explosion_sound: explosion_sound.play()
|
|
bullet_removed = True
|
|
break
|
|
if bullet_removed: continue
|
|
|
|
for enemy in enemies[:]:
|
|
if player_rect.colliderect(enemy):
|
|
enemies.remove(enemy)
|
|
player_health -= 25
|
|
if explosion_sound: explosion_sound.play()
|
|
|
|
for bullet in enemy_bullets[:] + [b.rect for b in boss_bullets]:
|
|
if player_rect.colliderect(bullet):
|
|
if isinstance(bullet, pygame.Rect) and bullet in enemy_bullets:
|
|
enemy_bullets.remove(bullet)
|
|
else:
|
|
for b in boss_bullets[:]:
|
|
if b.rect == bullet:
|
|
boss_bullets.remove(b)
|
|
break
|
|
player_health -= 10
|
|
|
|
if powerup_rect and player_rect.colliderect(powerup_rect):
|
|
player_has_triple_shot = True
|
|
powerup_active_start_time = pygame.time.get_ticks()
|
|
powerup_rect = None
|
|
|
|
if kill_count >= kills_for_boss and not boss_fight_active:
|
|
boss_fight_active = True
|
|
boss_is_entering = True
|
|
enemies.clear()
|
|
mines.clear()
|
|
pygame.time.set_timer(ENEMY_SPAWN_EVENT_L2, 0)
|
|
pygame.time.set_timer(MINE_SPAWN_EVENT, 0)
|
|
boss_rect = boss_image.get_rect(midleft=(SCREEN_WIDTH, SCREEN_HEIGHT / 2)) if boss_image else pygame.Rect(SCREEN_WIDTH, SCREEN_HEIGHT/2-60, 170, 120)
|
|
|
|
if boss_fight_active and boss_rect and not boss_defeated:
|
|
if boss_is_entering:
|
|
entry_target_x = SCREEN_WIDTH - boss_rect.width - 20
|
|
if boss_rect.x > entry_target_x:
|
|
boss_rect.x -= 5
|
|
else:
|
|
boss_is_entering = False
|
|
else:
|
|
boss_rect.y += boss_speed * boss_direction
|
|
if boss_rect.top <= 0 or boss_rect.bottom >= SCREEN_HEIGHT:
|
|
boss_direction *= -1
|
|
if random.randint(0, 50) == 1:
|
|
boss_bullets.append(Bullet(boss_rect.left, boss_rect.centery, -12, -2))
|
|
boss_bullets.append(Bullet(boss_rect.left, boss_rect.centery, -12, 0))
|
|
boss_bullets.append(Bullet(boss_rect.left, boss_rect.centery, -12, 2))
|
|
|
|
for bullet in player_bullets[:]:
|
|
if bullet.rect.colliderect(boss_rect):
|
|
player_bullets.remove(bullet)
|
|
boss_health -= 5
|
|
if boss_health <= 0:
|
|
boss_defeated = True
|
|
if explosion_sound: explosion_sound.play()
|
|
pygame.mixer.music.fadeout(2000)
|
|
boss_rect = None
|
|
break
|
|
|
|
if player_health <= 0 and not player_dead:
|
|
player_dead = True
|
|
if death_sound: death_sound.play()
|
|
death_timer_start = pygame.time.get_ticks()
|
|
pygame.mixer.music.stop()
|
|
|
|
if player_dead:
|
|
if pygame.time.get_ticks() - death_timer_start > 2000:
|
|
fade_surface = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
|
|
fade_surface.fill(BLACK)
|
|
for alpha in range(0, 255, 5):
|
|
fade_surface.set_alpha(alpha)
|
|
screen.blit(fade_surface, (0,0))
|
|
pygame.display.flip()
|
|
pygame.time.delay(30)
|
|
|
|
died_text = title_font.render("YOU DIED", True, RED)
|
|
died_rect = died_text.get_rect(center=(SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
|
|
screen.blit(died_text, died_rect)
|
|
pygame.display.flip()
|
|
pygame.time.wait(3000)
|
|
return
|
|
|
|
if boss_defeated:
|
|
player_rect.x += PLAYER_SPEED
|
|
if player_rect.left > SCREEN_WIDTH:
|
|
fade_surface = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
|
|
fade_surface.fill(BLACK)
|
|
for alpha in range(0, 255, 4):
|
|
fade_surface.set_alpha(alpha)
|
|
screen.blit(fade_surface, (0,0))
|
|
pygame.display.flip()
|
|
pygame.time.delay(30)
|
|
|
|
level3_text = title_font.render("LEVEL 3", True, WHITE)
|
|
level3_rect = level3_text.get_rect(center=(SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
|
|
screen.blit(level3_text, level3_rect)
|
|
pygame.display.flip()
|
|
pygame.time.wait(3000)
|
|
level_3_loop(player_health, score)
|
|
running = False
|
|
|
|
screen.fill(BLACK)
|
|
for star in stars:
|
|
star[0] -= star[2]
|
|
if star[0] < 0: star[0] = SCREEN_WIDTH; star[1] = random.randrange(0, SCREEN_HEIGHT)
|
|
pygame.draw.rect(screen, WHITE, (star[0], star[1], star[2], star[2]))
|
|
|
|
for bullet in player_bullets: pygame.draw.rect(screen, YELLOW, bullet.rect)
|
|
for bullet in enemy_bullets: pygame.draw.rect(screen, RED, bullet)
|
|
for bullet in boss_bullets: pygame.draw.rect(screen, RED, bullet.rect)
|
|
|
|
for enemy in enemies:
|
|
if enemy_image: screen.blit(enemy_image, enemy)
|
|
else: pygame.draw.rect(screen, RED, enemy)
|
|
|
|
for mine in mines:
|
|
if mine_image: screen.blit(mine_image, mine)
|
|
else: pygame.draw.rect(screen, RED, mine)
|
|
|
|
if powerup_rect:
|
|
if powerup_image: screen.blit(powerup_image, powerup_rect)
|
|
else: pygame.draw.rect(screen, CYAN, powerup_rect)
|
|
|
|
if boss_rect:
|
|
if boss_image: screen.blit(boss_image, boss_rect)
|
|
else: pygame.draw.rect(screen, CYAN, boss_rect)
|
|
|
|
if not player_dead:
|
|
if boss_defeated:
|
|
thruster_length = 25
|
|
thruster_rect = pygame.Rect(player_rect.left - thruster_length, player_rect.centery - 5, thruster_length, 10)
|
|
pygame.draw.rect(screen, ORANGE, thruster_rect)
|
|
if player_image: screen.blit(player_image, player_rect)
|
|
else: pygame.draw.rect(screen, PLAYER_COLOR, player_rect)
|
|
|
|
health_bar_width = max(0, (player_health / max_health) * 200)
|
|
pygame.draw.rect(screen, RED, (10, 10, 200, 20))
|
|
pygame.draw.rect(screen, GREEN, (10, 10, health_bar_width, 20))
|
|
score_text = score_font.render(f"Score: {score}", True, WHITE)
|
|
screen.blit(score_text, score_text.get_rect(center=(SCREEN_WIDTH / 2, 20)))
|
|
level_text = score_font.render("Level 2", True, WHITE)
|
|
screen.blit(level_text, level_text.get_rect(topright=(SCREEN_WIDTH - 10, 10)))
|
|
|
|
if player_has_triple_shot:
|
|
powerup_icon = pygame.transform.scale(powerup_image, (20, 20)) if powerup_image else None
|
|
if powerup_icon: screen.blit(powerup_icon, (10, 35))
|
|
elapsed_time = pygame.time.get_ticks() - powerup_active_start_time
|
|
remaining_ratio = 1 - (elapsed_time / POWERUP_DURATION)
|
|
timer_bar_width = max(0, remaining_ratio * 175)
|
|
pygame.draw.rect(screen, RED, (35, 35, 175, 20))
|
|
pygame.draw.rect(screen, YELLOW, (35, 35, timer_bar_width, 20))
|
|
|
|
if boss_fight_active and not boss_defeated and boss_rect:
|
|
boss_health_width = max(0, (boss_health / boss_max_health) * 200)
|
|
pygame.draw.rect(screen, RED, (SCREEN_WIDTH - 210, 10, 200, 20))
|
|
pygame.draw.rect(screen, GREEN, (SCREEN_WIDTH - 210, 10, boss_health_width, 20))
|
|
|
|
pygame.display.flip()
|
|
clock.tick(60)
|
|
|
|
def level_3_loop(player_health, score, cheat_mode=False):
|
|
pygame.mixer.music.stop()
|
|
try:
|
|
pygame.mixer.music.load('level3.wav')
|
|
pygame.mixer.music.play(-1)
|
|
except pygame.error:
|
|
print("Warning: Music file 'level3.wav' not found.")
|
|
|
|
try:
|
|
player_image = pygame.image.load('layer.png').convert_alpha()
|
|
player_image = pygame.transform.scale(player_image, (80, 40))
|
|
except pygame.error:
|
|
player_image = None
|
|
player_rect = player_image.get_rect() if player_image else pygame.Rect(0, 0, 80, 40)
|
|
player_rect.x = 50
|
|
player_rect.centery = SCREEN_HEIGHT / 2
|
|
PLAYER_SPEED = 5
|
|
max_health = 100
|
|
player_dead = False
|
|
death_timer_start = 0
|
|
if cheat_mode: player_health = 999999
|
|
|
|
player_has_triple_shot = False
|
|
powerup_spawned = False
|
|
powerup_active_start_time = 0
|
|
POWERUP_DURATION = 30000
|
|
|
|
try:
|
|
powerup_image = pygame.image.load('powerup_triple_shot.png').convert_alpha()
|
|
powerup_image = pygame.transform.scale(powerup_image, (40, 40))
|
|
except pygame.error:
|
|
powerup_image = None
|
|
powerup_rect = None
|
|
|
|
heal_powerup_spawned = False
|
|
try:
|
|
heal_image = pygame.image.load('powerup_heal.png').convert_alpha()
|
|
heal_image = pygame.transform.scale(heal_image, (40, 40))
|
|
except pygame.error:
|
|
heal_image = None
|
|
heal_rect = None
|
|
|
|
try:
|
|
asteroid_image = pygame.image.load('asteroid.png').convert_alpha()
|
|
except pygame.error:
|
|
asteroid_image = None
|
|
asteroids = []
|
|
ASTEROID_SPAWN_EVENT = pygame.USEREVENT + 4
|
|
pygame.time.set_timer(ASTEROID_SPAWN_EVENT, 1500)
|
|
|
|
try:
|
|
enemy_image = pygame.image.load('enemy_ship.png').convert_alpha()
|
|
enemy_image = pygame.transform.scale(enemy_image, (50, 50))
|
|
except pygame.error:
|
|
enemy_image = None
|
|
enemies = []
|
|
ENEMY_SPEED_L3 = 5
|
|
ENEMY_SPAWN_EVENT_L3 = pygame.USEREVENT + 5
|
|
pygame.time.set_timer(ENEMY_SPAWN_EVENT_L3, 700)
|
|
|
|
kill_count = 0
|
|
kills_for_powerup = 15
|
|
kills_for_heal = 30
|
|
kills_for_boss = 50
|
|
|
|
boss_fight_active = False
|
|
boss_defeated = False
|
|
try:
|
|
boss_image = pygame.image.load('boss_level3.png').convert_alpha()
|
|
boss_image = pygame.transform.scale(boss_image, (200, 150))
|
|
except pygame.error:
|
|
boss_image = None
|
|
boss_rect = None
|
|
boss_health = 600
|
|
boss_max_health = 600
|
|
boss_speed = 4
|
|
boss_direction = 1
|
|
boss_is_entering = False
|
|
|
|
player_bullets = []
|
|
enemy_bullets = []
|
|
boss_bullets = []
|
|
thruster_length = 10
|
|
|
|
running = True
|
|
while running:
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT:
|
|
pygame.quit()
|
|
sys.exit()
|
|
|
|
if event.type == pygame.KEYDOWN and not boss_defeated and not player_dead:
|
|
if event.key == pygame.K_SPACE:
|
|
if player_has_triple_shot:
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, -2))
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, 0))
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, 2))
|
|
else:
|
|
player_bullets.append(Bullet(player_rect.right, player_rect.centery - 2, 10, 0))
|
|
if shoot_sound: shoot_sound.play()
|
|
|
|
if event.type == ASTEROID_SPAWN_EVENT and not boss_fight_active:
|
|
size = random.randint(30, 60)
|
|
asteroid_y = random.randint(0, SCREEN_HEIGHT - size)
|
|
asteroid_rect = pygame.Rect(SCREEN_WIDTH + size, asteroid_y, size, size)
|
|
asteroids.append({'rect': asteroid_rect, 'speed': random.randint(2, 4)})
|
|
|
|
if event.type == ENEMY_SPAWN_EVENT_L3 and not boss_fight_active:
|
|
enemy_y_pos = random.randint(50, SCREEN_HEIGHT - 50)
|
|
enemy_rect = enemy_image.get_rect(midleft=(SCREEN_WIDTH + 20, enemy_y_pos)) if enemy_image else pygame.Rect(SCREEN_WIDTH + 20, enemy_y_pos, 50, 50)
|
|
enemies.append(enemy_rect)
|
|
|
|
if not boss_defeated and not player_dead:
|
|
keys = pygame.key.get_pressed()
|
|
is_moving_forward = False
|
|
if keys[pygame.K_LEFT]: player_rect.x -= PLAYER_SPEED
|
|
if keys[pygame.K_RIGHT]:
|
|
player_rect.x += PLAYER_SPEED
|
|
is_moving_forward = True
|
|
if keys[pygame.K_UP]: player_rect.y -= PLAYER_SPEED
|
|
if keys[pygame.K_DOWN]: player_rect.y += PLAYER_SPEED
|
|
thruster_length = 25 if is_moving_forward else 10
|
|
|
|
if not player_dead:
|
|
if player_rect.left < 0: player_rect.left = 0
|
|
if player_rect.right > SCREEN_WIDTH and not boss_defeated: player_rect.right = SCREEN_WIDTH
|
|
if player_rect.top < 0: player_rect.top = 0
|
|
if player_rect.bottom > SCREEN_HEIGHT: player_rect.bottom = SCREEN_HEIGHT
|
|
|
|
if kill_count >= kills_for_powerup and not powerup_spawned:
|
|
powerup_spawned = True
|
|
powerup_rect = powerup_image.get_rect(center=(SCREEN_WIDTH + 30, SCREEN_HEIGHT / 2)) if powerup_image else pygame.Rect(SCREEN_WIDTH + 30, SCREEN_HEIGHT / 2, 40, 40)
|
|
|
|
if kill_count >= kills_for_heal and not heal_powerup_spawned:
|
|
heal_powerup_spawned = True
|
|
heal_rect = heal_image.get_rect(center=(SCREEN_WIDTH + 30, SCREEN_HEIGHT / 3)) if heal_image else pygame.Rect(SCREEN_WIDTH+30, SCREEN_HEIGHT/3, 40, 40)
|
|
|
|
if player_has_triple_shot:
|
|
elapsed_time = pygame.time.get_ticks() - powerup_active_start_time
|
|
if elapsed_time > POWERUP_DURATION:
|
|
player_has_triple_shot = False
|
|
|
|
for bullet in player_bullets: bullet.update()
|
|
for bullet in enemy_bullets: bullet.x -= 10
|
|
for bullet in boss_bullets: bullet.update()
|
|
for enemy in enemies:
|
|
enemy.x -= ENEMY_SPEED_L3
|
|
if random.randint(0, 100) == 1:
|
|
enemy_bullet = pygame.Rect(enemy.left, enemy.centery - 2, 10, 5)
|
|
enemy_bullets.append(enemy_bullet)
|
|
for asteroid in asteroids: asteroid['rect'].x -= asteroid['speed']
|
|
if powerup_rect: powerup_rect.x -= 3
|
|
if heal_rect: heal_rect.x -= 3
|
|
|
|
if not player_dead:
|
|
for bullet in player_bullets[:]:
|
|
bullet_removed = False
|
|
for asteroid_dict in asteroids[:]:
|
|
if bullet.rect.colliderect(asteroid_dict['rect']):
|
|
try:
|
|
asteroids.remove(asteroid_dict)
|
|
player_bullets.remove(bullet)
|
|
if explosion_sound: explosion_sound.play()
|
|
bullet_removed = True
|
|
except ValueError:
|
|
pass
|
|
break
|
|
if bullet_removed: continue
|
|
|
|
for enemy in enemies[:]:
|
|
if bullet.rect.colliderect(enemy):
|
|
try:
|
|
enemies.remove(enemy)
|
|
player_bullets.remove(bullet)
|
|
score += 20
|
|
kill_count += 1
|
|
if explosion_sound: explosion_sound.play()
|
|
except ValueError:
|
|
pass
|
|
break
|
|
|
|
for asteroid_dict in asteroids[:]:
|
|
if player_rect.colliderect(asteroid_dict['rect']):
|
|
asteroids.remove(asteroid_dict)
|
|
if not cheat_mode: player_health -= 35
|
|
if explosion_sound: explosion_sound.play()
|
|
|
|
for enemy in enemies[:]:
|
|
if player_rect.colliderect(enemy):
|
|
enemies.remove(enemy)
|
|
if not cheat_mode: player_health -= 25
|
|
if explosion_sound: explosion_sound.play()
|
|
|
|
for bullet in enemy_bullets[:] + [b.rect for b in boss_bullets]:
|
|
if player_rect.colliderect(bullet):
|
|
if isinstance(bullet, pygame.Rect) and bullet in enemy_bullets:
|
|
enemy_bullets.remove(bullet)
|
|
else:
|
|
for b in boss_bullets[:]:
|
|
if b.rect == bullet:
|
|
boss_bullets.remove(b)
|
|
break
|
|
if not cheat_mode: player_health -= 10
|
|
|
|
if powerup_rect and player_rect.colliderect(powerup_rect):
|
|
player_has_triple_shot = True
|
|
powerup_active_start_time = pygame.time.get_ticks()
|
|
powerup_rect = None
|
|
|
|
if heal_rect and player_rect.colliderect(heal_rect):
|
|
player_health = min(max_health, player_health + 25)
|
|
heal_rect = None
|
|
|
|
if kill_count >= kills_for_boss and not boss_fight_active:
|
|
boss_fight_active = True
|
|
boss_is_entering = True
|
|
enemies.clear()
|
|
asteroids.clear()
|
|
pygame.time.set_timer(ENEMY_SPAWN_EVENT_L3, 0)
|
|
pygame.time.set_timer(ASTEROID_SPAWN_EVENT, 0)
|
|
boss_rect = boss_image.get_rect(midleft=(SCREEN_WIDTH, SCREEN_HEIGHT / 2)) if boss_image else pygame.Rect(SCREEN_WIDTH, SCREEN_HEIGHT/2-75, 200, 150)
|
|
|
|
if boss_fight_active and boss_rect and not boss_defeated:
|
|
if boss_is_entering:
|
|
entry_target_x = SCREEN_WIDTH - boss_rect.width - 20
|
|
if boss_rect.x > entry_target_x:
|
|
boss_rect.x -= 5
|
|
else:
|
|
boss_is_entering = False
|
|
else:
|
|
boss_rect.y += boss_speed * boss_direction
|
|
if boss_rect.top <= 0 or boss_rect.bottom >= SCREEN_HEIGHT:
|
|
boss_direction *= -1
|
|
if random.randint(0, 30) == 1:
|
|
boss_bullets.append(Bullet(boss_rect.left, boss_rect.centery, -15, -3))
|
|
boss_bullets.append(Bullet(boss_rect.left, boss_rect.centery, -15, 0))
|
|
boss_bullets.append(Bullet(boss_rect.left, boss_rect.centery, -15, 3))
|
|
|
|
for bullet in player_bullets[:]:
|
|
if bullet.rect.colliderect(boss_rect):
|
|
player_bullets.remove(bullet)
|
|
boss_health -= 5
|
|
if boss_health <= 0:
|
|
boss_defeated = True
|
|
if explosion_sound: explosion_sound.play()
|
|
pygame.mixer.music.fadeout(2000)
|
|
boss_rect = None
|
|
break
|
|
|
|
if player_health <= 0 and not player_dead:
|
|
player_dead = True
|
|
if death_sound: death_sound.play()
|
|
death_timer_start = pygame.time.get_ticks()
|
|
pygame.mixer.music.stop()
|
|
|
|
if player_dead:
|
|
if pygame.time.get_ticks() - death_timer_start > 2000:
|
|
fade_surface = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
|
|
fade_surface.fill(BLACK)
|
|
for alpha in range(0, 255, 5):
|
|
fade_surface.set_alpha(alpha)
|
|
screen.blit(fade_surface, (0,0))
|
|
pygame.display.flip()
|
|
pygame.time.delay(30)
|
|
|
|
died_text = title_font.render("YOU DIED", True, RED)
|
|
died_rect = died_text.get_rect(center=(SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
|
|
screen.blit(died_text, died_rect)
|
|
pygame.display.flip()
|
|
pygame.time.wait(3000)
|
|
return
|
|
|
|
if boss_defeated:
|
|
player_rect.x += PLAYER_SPEED
|
|
if player_rect.left > SCREEN_WIDTH:
|
|
fade_surface = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
|
|
fade_surface.fill(BLACK)
|
|
for alpha in range(0, 255, 4):
|
|
fade_surface.set_alpha(alpha)
|
|
screen.blit(fade_surface, (0,0))
|
|
pygame.display.flip()
|
|
pygame.time.delay(30)
|
|
|
|
win_text = title_font.render("YOU WIN!", True, WHITE)
|
|
win_rect = win_text.get_rect(center=(SCREEN_WIDTH/2, SCREEN_HEIGHT/2))
|
|
screen.blit(win_text, win_rect)
|
|
pygame.display.flip()
|
|
pygame.time.wait(3000)
|
|
credits_screen()
|
|
running = False
|
|
|
|
screen.fill(BLACK)
|
|
for star in stars:
|
|
star[0] -= star[2]
|
|
if star[0] < 0: star[0] = SCREEN_WIDTH; star[1] = random.randrange(0, SCREEN_HEIGHT)
|
|
pygame.draw.rect(screen, WHITE, (star[0], star[1], star[2], star[2]))
|
|
|
|
for bullet in player_bullets: pygame.draw.rect(screen, YELLOW, bullet.rect)
|
|
for bullet in enemy_bullets: pygame.draw.rect(screen, RED, bullet)
|
|
for bullet in boss_bullets: pygame.draw.rect(screen, RED, bullet.rect)
|
|
|
|
for asteroid_dict in asteroids:
|
|
if asteroid_image:
|
|
scaled_asteroid = pygame.transform.scale(asteroid_image, (asteroid_dict['rect'].width, asteroid_dict['rect'].height))
|
|
screen.blit(scaled_asteroid, asteroid_dict['rect'])
|
|
else:
|
|
pygame.draw.rect(screen, WHITE, asteroid_dict['rect'])
|
|
|
|
for enemy in enemies:
|
|
if enemy_image: screen.blit(enemy_image, enemy)
|
|
else: pygame.draw.rect(screen, RED, enemy)
|
|
|
|
if powerup_rect:
|
|
if powerup_image: screen.blit(powerup_image, powerup_rect)
|
|
else: pygame.draw.rect(screen, CYAN, powerup_rect)
|
|
|
|
if heal_rect:
|
|
if heal_image: screen.blit(heal_image, heal_rect)
|
|
else: pygame.draw.rect(screen, GREEN, heal_rect)
|
|
|
|
if boss_rect:
|
|
if boss_image: screen.blit(boss_image, boss_rect)
|
|
else: pygame.draw.rect(screen, CYAN, boss_rect)
|
|
|
|
if not player_dead:
|
|
if boss_defeated:
|
|
thruster_length = 25
|
|
thruster_rect = pygame.Rect(player_rect.left - thruster_length, player_rect.centery - 5, thruster_length, 10)
|
|
pygame.draw.rect(screen, ORANGE, thruster_rect)
|
|
if player_image: screen.blit(player_image, player_rect)
|
|
else: pygame.draw.rect(screen, PLAYER_COLOR, player_rect)
|
|
|
|
health_bar_width = max(0, (player_health / max_health) * 200) if not cheat_mode else 200
|
|
pygame.draw.rect(screen, RED, (10, 10, 200, 20))
|
|
pygame.draw.rect(screen, GREEN, (10, 10, health_bar_width, 20))
|
|
score_text = score_font.render(f"Score: {score}", True, WHITE)
|
|
screen.blit(score_text, score_text.get_rect(center=(SCREEN_WIDTH / 2, 20)))
|
|
level_text = score_font.render("Level 3", True, WHITE)
|
|
screen.blit(level_text, level_text.get_rect(topright=(SCREEN_WIDTH - 10, 10)))
|
|
|
|
if player_has_triple_shot:
|
|
powerup_icon = pygame.transform.scale(powerup_image, (20, 20)) if powerup_image else None
|
|
if powerup_icon: screen.blit(powerup_icon, (10, 35))
|
|
elapsed_time = pygame.time.get_ticks() - powerup_active_start_time
|
|
remaining_ratio = 1 - (elapsed_time / POWERUP_DURATION)
|
|
timer_bar_width = max(0, remaining_ratio * 175)
|
|
pygame.draw.rect(screen, RED, (35, 35, 175, 20))
|
|
pygame.draw.rect(screen, YELLOW, (35, 35, timer_bar_width, 20))
|
|
|
|
if boss_fight_active and not boss_defeated and boss_rect:
|
|
boss_health_width = max(0, (boss_health / boss_max_health) * 200)
|
|
pygame.draw.rect(screen, RED, (SCREEN_WIDTH - 210, 10, 200, 20))
|
|
pygame.draw.rect(screen, GREEN, (SCREEN_WIDTH - 210, 10, boss_health_width, 20))
|
|
|
|
pygame.display.flip()
|
|
clock.tick(60)
|
|
|
|
def credits_screen():
|
|
pygame.mixer.music.stop()
|
|
try:
|
|
pygame.mixer.music.load('credits.wav')
|
|
pygame.mixer.music.play(-1)
|
|
pygame.mixer.music.set_volume(0.5)
|
|
except pygame.error:
|
|
print("Warning: 'credits.wav' not found.")
|
|
|
|
credit_lines = [ "Credits", "", "Coding: Google Gemini", "Graphics: Google Gemini", "Music: Suno.com", "", "Pygame", "", "Other then me (Michael Howard)", "putting it all together", "A.I. created this game", "", "Thanks for playing" ]
|
|
credit_surfaces = []
|
|
line_height = 60 # Increased spacing
|
|
start_y = SCREEN_HEIGHT + 50
|
|
for i, line in enumerate(credit_lines):
|
|
font = title_font if i == 0 else prompt_font
|
|
text_surface = font.render(line, True, WHITE)
|
|
text_rect = text_surface.get_rect(center=(SCREEN_WIDTH / 2, start_y + i * line_height))
|
|
credit_surfaces.append({'surf': text_surface, 'rect': text_rect})
|
|
|
|
credit_stars = [[random.uniform(-SCREEN_WIDTH / 2, SCREEN_WIDTH / 2), random.uniform(-SCREEN_HEIGHT / 2, SCREEN_HEIGHT / 2), random.uniform(1, SCREEN_WIDTH)] for _ in range(400)]
|
|
scroll_speed = 1.0 # Slower scroll
|
|
credits_finished_scrolling = False
|
|
prompt_alpha = 0
|
|
|
|
running = True
|
|
while running:
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT:
|
|
pygame.quit()
|
|
sys.exit()
|
|
if event.type == pygame.KEYDOWN and credits_finished_scrolling:
|
|
return # Go back to main menu loop
|
|
|
|
screen.fill(BLACK)
|
|
for star in credit_stars:
|
|
star[2] -= 2
|
|
if star[2] < 1:
|
|
star[2] = SCREEN_WIDTH
|
|
star[0], star[1] = random.uniform(-SCREEN_WIDTH / 2, SCREEN_WIDTH / 2), random.uniform(-SCREEN_HEIGHT / 2, SCREEN_HEIGHT / 2)
|
|
k = 128.0 / star[2]
|
|
sx, sy = int(star[0] * k + SCREEN_WIDTH / 2), int(star[1] * k + SCREEN_HEIGHT / 2)
|
|
if 0 < sx < SCREEN_WIDTH and 0 < sy < SCREEN_HEIGHT:
|
|
size = (1 - star[2] / SCREEN_WIDTH) * 4
|
|
pygame.draw.rect(screen, WHITE, (sx, sy, size, size))
|
|
|
|
last_rect_bottom = 0
|
|
if not credits_finished_scrolling:
|
|
for item in credit_surfaces:
|
|
item['rect'].y -= scroll_speed
|
|
screen.blit(item['surf'], item['rect'])
|
|
last_rect_bottom = item['rect'].bottom
|
|
|
|
if last_rect_bottom < -50:
|
|
credits_finished_scrolling = True
|
|
else:
|
|
if prompt_alpha < 255:
|
|
prompt_alpha = min(prompt_alpha + 3, 255)
|
|
prompt_surface = prompt_font.render("Press any key to continue", True, WHITE)
|
|
prompt_surface.set_alpha(prompt_alpha)
|
|
prompt_rect = prompt_surface.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT - 50))
|
|
screen.blit(prompt_surface, prompt_rect)
|
|
|
|
pygame.display.flip()
|
|
clock.tick(60)
|
|
|
|
def main_menu():
|
|
try:
|
|
pygame.mixer.music.load('CosmicPixels.wav')
|
|
pygame.mixer.music.play(-1)
|
|
except pygame.error:
|
|
print("Warning: Music file 'CosmicPixels.wav' not found.")
|
|
|
|
game_title = "COSMIC PIXELS"
|
|
full_title_surface = title_font.render(game_title, True, CYAN)
|
|
total_width = full_title_surface.get_width()
|
|
initial_x = (SCREEN_WIDTH - total_width) / 2
|
|
|
|
title_letters = []
|
|
current_x = initial_x
|
|
for char in game_title:
|
|
char_surface = title_font.render(char, True, CYAN)
|
|
end_pos = (current_x, SCREEN_HEIGHT / 4)
|
|
start_pos = (current_x, SCREEN_HEIGHT)
|
|
letter = Letter(char, title_font, CYAN, start_pos, end_pos, anim_duration=0.7)
|
|
title_letters.append(letter)
|
|
current_x += char_surface.get_width()
|
|
|
|
next_letter_index, stagger_delay_ms = 0, 80
|
|
last_letter_time = pygame.time.get_ticks()
|
|
title_animation_complete = False
|
|
prompt_alpha, prompt_fade_speed = 0, 3
|
|
|
|
running = True
|
|
while running:
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.QUIT:
|
|
pygame.quit()
|
|
sys.exit()
|
|
if event.type == pygame.KEYDOWN and title_animation_complete:
|
|
if event.key == pygame.K_0:
|
|
level_3_loop(100, 0, cheat_mode=True)
|
|
else:
|
|
game_loop()
|
|
# After a game, the loops will return here, and we just let the main menu loop continue
|
|
|
|
screen.fill(BLACK)
|
|
for star in stars:
|
|
star[0] -= star[2]
|
|
if star[0] < 0:
|
|
star[0] = SCREEN_WIDTH; star[1] = random.randrange(0, SCREEN_HEIGHT)
|
|
pygame.draw.rect(screen, WHITE, (star[0], star[1], star[2], star[2]))
|
|
|
|
current_time = pygame.time.get_ticks()
|
|
if not title_animation_complete and next_letter_index < len(title_letters):
|
|
if current_time - last_letter_time > stagger_delay_ms:
|
|
title_letters[next_letter_index].start_animation()
|
|
next_letter_index += 1
|
|
last_letter_time = current_time
|
|
|
|
all_letters_finished = True
|
|
for letter in title_letters:
|
|
letter.update(); letter.draw(screen)
|
|
if not letter.is_finished: all_letters_finished = False
|
|
|
|
if all_letters_finished: title_animation_complete = True
|
|
|
|
if title_animation_complete:
|
|
if prompt_alpha < 255: prompt_alpha = min(prompt_alpha + prompt_fade_speed, 255)
|
|
prompt_surface = prompt_font.render("PRESS ANY KEY TO START", True, YELLOW)
|
|
prompt_surface.set_alpha(prompt_alpha)
|
|
prompt_rect = prompt_surface.get_rect(center=(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2))
|
|
screen.blit(prompt_surface, prompt_rect)
|
|
|
|
pygame.display.flip()
|
|
clock.tick(60)
|
|
|
|
if __name__ == "__main__":
|
|
while True:
|
|
main_menu()
|
|
|