Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save shricodev/fe396931474cae6df1af36f6f752b0b3 to your computer and use it in GitHub Desktop.
Save shricodev/fe396931474cae6df1af36f6f752b0b3 to your computer and use it in GitHub Desktop.
import random
import sys
import pygame
# -- Configuration ---------------------------------------------------------
WIDTH, HEIGHT = 480, 640
FPS = 60
PLAYER_SPEED = 5
PLAYER_SIZE = 40
BULLET_SPEED = 7
BULLET_W, BULLET_H = 4, 10
SHOOT_COOLDOWN = 300 # ms between player shots
ENEMY_SPEED = 2
ENEMY_SIZE = 40
MAX_ENEMIES = 6
SPAWN_DELAY = 1000 # ms between enemy spawns
ENEMY_SHOOT_DELAY = 1200 # ms between enemy shots
ENEMY_BULLET_SPEED = 4
ENEMY_BULLET_W, ENEMY_BULLET_H = 4, 10
STARTING_LIVES = 3
STAR_COUNT = 80
# -- Pygame Setup ---------------------------------------------------------
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Galaga‐MVP w/ Explosions")
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 32)
# -- Classes --------------------------------------------------------------
class Star:
def __init__(self):
self.x = random.randrange(0, WIDTH)
self.y = random.randrange(0, HEIGHT)
self.speed = random.uniform(1, 3)
self.size = random.randint(1, 3)
def update(self):
self.y += self.speed
if self.y > HEIGHT:
self.y = 0
self.x = random.randrange(0, WIDTH)
def draw(self, surf):
pygame.draw.circle(surf, (200, 200, 200), (int(self.x), int(self.y)), self.size)
class Player:
def __init__(self):
self.rect = pygame.Rect(
(WIDTH - PLAYER_SIZE) // 2,
HEIGHT - PLAYER_SIZE - 10,
PLAYER_SIZE,
PLAYER_SIZE,
)
self.last_shot = 0
self.lives = STARTING_LIVES
def move(self, dx):
self.rect.x = max(0, min(WIDTH - PLAYER_SIZE, self.rect.x + dx))
def can_shoot(self):
return pygame.time.get_ticks() - self.last_shot >= SHOOT_COOLDOWN
def shoot(self):
self.last_shot = pygame.time.get_ticks()
bx = self.rect.centerx - BULLET_W // 2
by = self.rect.top - BULLET_H
return Bullet(bx, by, -BULLET_SPEED, (255, 255, 0), BULLET_W, BULLET_H)
def draw(self, surf):
x, y, s = self.rect.x, self.rect.y, self.rect.width
pts = [(x + s // 2, y), (x, y + s), (x + s, y + s)]
pygame.draw.polygon(surf, (0, 255, 0), pts)
class Bullet:
def __init__(self, x, y, dy, color, w, h):
self.rect = pygame.Rect(x, y, w, h)
self.dy = dy
self.color = color
def update(self):
self.rect.y += self.dy
def off_screen(self):
return self.rect.bottom < 0 or self.rect.top > HEIGHT
def draw(self, surf):
pygame.draw.rect(surf, self.color, self.rect)
class Enemy:
def __init__(self):
x = random.randrange(0, WIDTH - ENEMY_SIZE)
self.rect = pygame.Rect(x, -ENEMY_SIZE, ENEMY_SIZE, ENEMY_SIZE)
def update(self):
self.rect.y += ENEMY_SPEED
def off_screen(self):
return self.rect.top > HEIGHT
def draw(self, surf):
x, y, s = self.rect.x, self.rect.y, self.rect.width
pts = [(x, y), (x + s, y), (x + s // 2, y + s)]
pygame.draw.polygon(surf, (255, 0, 0), pts)
class Explosion:
def __init__(self, x, y):
self.x = x
self.y = y
self.start = pygame.time.get_ticks()
self.duration = 500 # ms
self.max_radius = 30
def draw(self, surf, now):
elapsed = now - self.start
if elapsed > self.duration:
return False
ratio = elapsed / self.duration
r = int(ratio * self.max_radius)
# outer glow
pygame.draw.circle(surf, (255, 200, 0), (self.x, self.y), r)
# inner core
pygame.draw.circle(surf, (255, 80, 0), (self.x, self.y), int(r * 0.6))
return True
# -- Helpers -------------------------------------------------------------
def draw_text(surf, text, x, y, color=(255, 255, 255)):
img = font.render(text, True, color)
surf.blit(img, (x, y))
def reset_game():
player = Player()
bullets = []
enemies = []
e_bullets = []
explosions = []
stars = [Star() for _ in range(STAR_COUNT)]
score = 0
last_spawn = pygame.time.get_ticks()
last_enemy_shot = pygame.time.get_ticks()
return (
player,
bullets,
enemies,
e_bullets,
explosions,
stars,
score,
last_spawn,
last_enemy_shot,
)
# -- Main Loop -----------------------------------------------------------
def main():
(
player,
bullets,
enemies,
e_bullets,
explosions,
stars,
score,
last_spawn,
last_enemy_shot,
) = reset_game()
game_over = False
while True:
dt = clock.tick(FPS)
now = pygame.time.get_ticks()
# --- Events ---
for ev in pygame.event.get():
if ev.type == pygame.QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed()
# --- Game Over Screen ---
if game_over:
screen.fill((0, 0, 0))
draw_text(screen, "GAME OVER", WIDTH // 2 - 90, HEIGHT // 2 - 50)
draw_text(screen, f"Score: {score}", WIDTH // 2 - 60, HEIGHT // 2)
draw_text(
screen, "Press Enter to Restart", WIDTH // 2 - 140, HEIGHT // 2 + 50
)
pygame.display.flip()
if keys[pygame.K_RETURN]:
(
player,
bullets,
enemies,
e_bullets,
explosions,
stars,
score,
last_spawn,
last_enemy_shot,
) = reset_game()
game_over = False
continue
# --- Player Input ---
dx = 0
if keys[pygame.K_LEFT]:
dx -= PLAYER_SPEED
if keys[pygame.K_RIGHT]:
dx += PLAYER_SPEED
player.move(dx)
if keys[pygame.K_SPACE] and player.can_shoot():
bullets.append(player.shoot())
# --- Spawn Enemies ---
if now - last_spawn >= SPAWN_DELAY and len(enemies) < MAX_ENEMIES:
enemies.append(Enemy())
last_spawn = now
# --- Enemy Shooting ---
if now - last_enemy_shot >= ENEMY_SHOOT_DELAY and enemies:
shooter = random.choice(enemies)
bx = shooter.rect.centerx - ENEMY_BULLET_W // 2
by = shooter.rect.bottom
e_bullets.append(
Bullet(
bx,
by,
ENEMY_BULLET_SPEED,
(255, 100, 100),
ENEMY_BULLET_W,
ENEMY_BULLET_H,
)
)
last_enemy_shot = now
# --- Update Entities ---
for s in stars:
s.update()
for b in bullets:
b.update()
for e in enemies:
e.update()
for eb in e_bullets:
eb.update()
# --- Off‑screen cleanup ---
bullets = [b for b in bullets if not b.off_screen()]
enemies = [e for e in enemies if not e.off_screen()]
e_bullets = [eb for eb in e_bullets if not eb.off_screen()]
# --- Collisions: Player bullets → Enemies ---
new_b = []
for b in bullets:
hit = False
for e in enemies:
if b.rect.colliderect(e.rect):
explosions.append(Explosion(e.rect.centerx, e.rect.centery))
enemies.remove(e)
score += 100
hit = True
break
if not hit:
new_b.append(b)
bullets = new_b
# --- Collisions: Enemy bullets → Player ---
for eb in e_bullets[:]:
if eb.rect.colliderect(player.rect):
e_bullets.remove(eb)
explosions.append(Explosion(player.rect.centerx, player.rect.centery))
player.lives -= 1
if player.lives <= 0:
game_over = True
break
# --- Collisions: Enemy → Player ---
for e in enemies[:]:
if e.rect.colliderect(player.rect):
enemies.remove(e)
explosions.append(Explosion(player.rect.centerx, player.rect.centery))
player.lives -= 1
if player.lives <= 0:
game_over = True
break
# --- Draw ---
screen.fill((0, 0, 0))
for s in stars:
s.draw(screen)
player.draw(screen)
for b in bullets:
b.draw(screen)
for eb in e_bullets:
eb.draw(screen)
for e in enemies:
e.draw(screen)
# draw & clean explosions
explosions = [ex for ex in explosions if ex.draw(screen, now)]
# UI
draw_text(screen, f"Score: {score}", 10, 10)
draw_text(screen, f"Lives: {player.lives}", WIDTH - 130, 10)
pygame.display.flip()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment