Created
April 20, 2025 14:05
-
-
Save shricodev/ca9f4c79460d760209c4128a610505c0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import random | |
| import sys | |
| import pygame | |
| # --- Constants --- | |
| SCREEN_WIDTH = 800 | |
| SCREEN_HEIGHT = 600 | |
| BLACK = (0, 0, 0) | |
| WHITE = (255, 255, 255) | |
| RED = (255, 0, 0) | |
| GREEN = (0, 255, 0) | |
| BLUE = (0, 0, 255) | |
| DARK_GREY = (50, 50, 50) | |
| LIGHT_GREY = (150, 150, 150) | |
| PLAYER_WIDTH = 50 | |
| PLAYER_HEIGHT = 40 | |
| PLAYER_SPEED = 7 | |
| ENEMY_WIDTH = 40 | |
| ENEMY_HEIGHT = 30 | |
| ENEMY_SPEED = 2 | |
| ENEMY_SPAWN_RATE = 60 # Lower number means more frequent spawns (roughly frames) | |
| BULLET_WIDTH = 5 | |
| BULLET_HEIGHT = 15 | |
| BULLET_SPEED = 10 | |
| FPS = 60 | |
| # --- Starfield Constants --- | |
| NUM_STARS_NEAR = 50 | |
| NUM_STARS_MID = 100 | |
| NUM_STARS_FAR = 150 | |
| STAR_SPEED_NEAR = 2 | |
| STAR_SPEED_MID = 1 | |
| STAR_SPEED_FAR = 0.5 # Can be float | |
| STAR_COLOR_NEAR = WHITE | |
| STAR_COLOR_MID = LIGHT_GREY | |
| STAR_COLOR_FAR = DARK_GREY | |
| STAR_RADIUS_NEAR = 2 | |
| STAR_RADIUS_MID = 1 | |
| STAR_RADIUS_FAR = 1 | |
| # --- Player Class --- | |
| class Player(pygame.sprite.Sprite): | |
| def __init__(self): | |
| super().__init__() | |
| # Create a simple block image for the player | |
| self.image = pygame.Surface([PLAYER_WIDTH, PLAYER_HEIGHT]) | |
| self.image.fill(GREEN) | |
| self.rect = self.image.get_rect() | |
| # Set initial position | |
| self.rect.centerx = SCREEN_WIDTH // 2 | |
| self.rect.bottom = SCREEN_HEIGHT - 10 | |
| self.speed_x = 0 | |
| def update(self): | |
| # Reset speed for each frame | |
| self.speed_x = 0 | |
| # Get pressed keys | |
| keystate = pygame.key.get_pressed() | |
| if keystate[pygame.K_LEFT]: | |
| self.speed_x = -PLAYER_SPEED | |
| if keystate[pygame.K_RIGHT]: | |
| self.speed_x = PLAYER_SPEED | |
| # Move the player | |
| self.rect.x += self.speed_x | |
| # Keep player on screen | |
| if self.rect.right > SCREEN_WIDTH: | |
| self.rect.right = SCREEN_WIDTH | |
| if self.rect.left < 0: | |
| self.rect.left = 0 | |
| def shoot(self, all_sprites, bullets): | |
| bullet = Bullet(self.rect.centerx, self.rect.top) | |
| all_sprites.add(bullet) | |
| bullets.add(bullet) | |
| # --- Enemy Class --- | |
| class Enemy(pygame.sprite.Sprite): | |
| def __init__(self): | |
| super().__init__() | |
| # Create a simple block image for the enemy | |
| self.image = pygame.Surface([ENEMY_WIDTH, ENEMY_HEIGHT]) | |
| self.image.fill(RED) | |
| self.rect = self.image.get_rect() | |
| # Set initial position (random x at the top) | |
| self.rect.x = random.randrange(SCREEN_WIDTH - self.rect.width) | |
| self.rect.y = random.randrange(-100, -40) # Start slightly off-screen | |
| self.speed_y = ENEMY_SPEED | |
| def update(self): | |
| self.rect.y += self.speed_y | |
| # Remove enemy if it goes off the bottom of the screen | |
| if self.rect.top > SCREEN_HEIGHT + 10: | |
| self.kill() # Remove sprite from all groups | |
| # --- Bullet Class --- | |
| class Bullet(pygame.sprite.Sprite): | |
| def __init__(self, x, y): | |
| super().__init__() | |
| # Create a simple block image for the bullet | |
| self.image = pygame.Surface([BULLET_WIDTH, BULLET_HEIGHT]) | |
| self.image.fill(WHITE) | |
| self.rect = self.image.get_rect() | |
| # Set initial position based on player | |
| self.rect.centerx = x | |
| self.rect.bottom = y | |
| self.speed_y = -BULLET_SPEED | |
| def update(self): | |
| self.rect.y += self.speed_y | |
| # Remove bullet if it goes off the top of the screen | |
| if self.rect.bottom < 0: | |
| self.kill() | |
| # --- Star Function --- | |
| def create_stars(number, speed, color, radius): | |
| """Creates a list of star data [x, y, speed, color, radius].""" | |
| stars = [] | |
| for _ in range(number): | |
| x = random.randrange(0, SCREEN_WIDTH) | |
| y = random.randrange( | |
| 0, SCREEN_HEIGHT | |
| ) # Start stars anywhere on screen initially | |
| stars.append([x, y, speed, color, radius]) | |
| return stars | |
| def update_and_draw_stars(screen, stars): | |
| """Moves and draws stars. Resets them if they go off screen.""" | |
| for star in stars: | |
| # Move star | |
| star[1] += star[2] # star[1] is y, star[2] is speed | |
| # Check if star is off screen | |
| if star[1] > SCREEN_HEIGHT: | |
| # Reset star to top with a new random x | |
| star[1] = random.randrange(-20, 0) | |
| star[0] = random.randrange(0, SCREEN_WIDTH) | |
| # Draw star (using integer coordinates for drawing) | |
| pygame.draw.circle(screen, star[3], (int(star[0]), int(star[1])), star[4]) | |
| # --- Game Initialization --- | |
| pygame.init() | |
| pygame.mixer.init() # For sound (optional) | |
| screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) | |
| pygame.display.set_caption("Galaga MVP") | |
| clock = pygame.time.Clock() | |
| font = pygame.font.Font(None, 36) # Default font, size 36 | |
| # --- Create Star Lists --- | |
| stars_far = create_stars(NUM_STARS_FAR, STAR_SPEED_FAR, STAR_COLOR_FAR, STAR_RADIUS_FAR) | |
| stars_mid = create_stars(NUM_STARS_MID, STAR_SPEED_MID, STAR_COLOR_MID, STAR_RADIUS_MID) | |
| stars_near = create_stars( | |
| NUM_STARS_NEAR, STAR_SPEED_NEAR, STAR_COLOR_NEAR, STAR_RADIUS_NEAR | |
| ) | |
| # --- Sprite Groups --- | |
| all_sprites = pygame.sprite.Group() | |
| enemies = pygame.sprite.Group() | |
| bullets = pygame.sprite.Group() | |
| # --- Create Player --- | |
| player = Player() | |
| all_sprites.add(player) | |
| # --- Game Variables --- | |
| score = 0 | |
| enemy_spawn_timer = 0 | |
| game_over = False | |
| # --- Game Loop --- | |
| running = True | |
| while running: | |
| # Keep loop running at the right speed | |
| clock.tick(FPS) | |
| # --- Event Handling --- | |
| for event in pygame.event.get(): | |
| if event.type == pygame.QUIT: | |
| running = False | |
| elif event.type == pygame.KEYDOWN: | |
| if not game_over and event.key == pygame.K_SPACE: | |
| player.shoot(all_sprites, bullets) | |
| elif game_over and event.key == pygame.K_r: # Restart game | |
| # Reset everything (Consider resetting stars if needed, but they just loop) | |
| all_sprites.empty() | |
| enemies.empty() | |
| bullets.empty() | |
| player = Player() | |
| all_sprites.add(player) | |
| score = 0 | |
| enemy_spawn_timer = 0 | |
| game_over = False | |
| # --- Update Game Logic --- | |
| if not game_over: | |
| # Enemy Spawning | |
| enemy_spawn_timer += 1 | |
| if enemy_spawn_timer >= ENEMY_SPAWN_RATE: | |
| if random.random() > 0.3: | |
| enemy = Enemy() | |
| all_sprites.add(enemy) | |
| enemies.add(enemy) | |
| enemy_spawn_timer = 0 | |
| # Update Sprites | |
| all_sprites.update() # Calls update() on every sprite in the group | |
| # Collision Detection: Bullet-Enemy | |
| hits = pygame.sprite.groupcollide(bullets, enemies, True, True) | |
| for hit in hits: | |
| score += 10 | |
| # Collision Detection: Player-Enemy | |
| player_hits = pygame.sprite.spritecollide(player, enemies, True) | |
| if player_hits: | |
| game_over = True | |
| # player.kill() # Optional | |
| # --- Draw / Render --- | |
| screen.fill(BLACK) # Fill background | |
| # --- Update and Draw Stars (Draw behind everything else) --- | |
| # Update star positions regardless of game_over state for continuous scroll | |
| update_and_draw_stars(screen, stars_far) | |
| update_and_draw_stars(screen, stars_mid) | |
| update_and_draw_stars(screen, stars_near) | |
| # Draw Game Sprites | |
| all_sprites.draw(screen) | |
| # Draw Score | |
| score_text = font.render(f"Score: {score}", True, WHITE) | |
| screen.blit(score_text, (10, 10)) | |
| # Draw Game Over screen | |
| if game_over: | |
| game_over_text = font.render("GAME OVER", True, RED) | |
| restart_text = font.render("Press R to Restart", True, WHITE) | |
| screen.blit( | |
| game_over_text, | |
| ( | |
| SCREEN_WIDTH // 2 - game_over_text.get_width() // 2, | |
| SCREEN_HEIGHT // 2 - 50, | |
| ), | |
| ) | |
| screen.blit( | |
| restart_text, | |
| (SCREEN_WIDTH // 2 - restart_text.get_width() // 2, SCREEN_HEIGHT // 2), | |
| ) | |
| # *After* drawing everything, flip the display | |
| pygame.display.flip() | |
| # --- Quit Pygame --- | |
| pygame.quit() | |
| sys.exit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment