Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .coverage
Binary file not shown.
Binary file added Capture.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 🚀 Galaxy Invaders
# 🚀 Galaxy Invaderss

A classic arcade-style space shooter game built using Python and the Pygame library.

Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
pygame>=2.5.0
pytest>=7.3.1
pytest-mock>=3.10.0
pytest-cov>=4.0.0
88 changes: 52 additions & 36 deletions space_adventure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import random
import sys
import os

#rate
# Initialize pygame
pygame.init()

Expand Down Expand Up @@ -65,6 +65,7 @@ def __init__(self):
self.hide_timer = 0
self.power_level = 1
self.power_timer = 0
self.power_display_timer = 0 # New timer for power-up display

def update(self):
# Unhide if hidden
Expand All @@ -77,31 +78,42 @@ def update(self):
if self.power_level > 1 and pygame.time.get_ticks() - self.power_timer > 5000:
self.power_level -= 1
self.power_timer = pygame.time.get_ticks()
self.power_display_timer = pygame.time.get_ticks() # Set display timer when power decreases

# Movement
self.speed_x = 0
keystate = pygame.key.get_pressed()
if keystate[pygame.K_LEFT]:
self.speed_x = 8
self.speed_x = -8 # Fixed: Changed to negative for left movement
if keystate[pygame.K_RIGHT]:
self.speed_x = -8
self.speed_x = 8 # Fixed: Changed to positive for right movement

self.rect.x += self.speed_x
if self.rect.right > SCREEN_WIDTH + 20:
self.rect.right = SCREEN_WIDTH + 20
if self.rect.left < -20:
self.rect.left = -20
# Fix boundary checks to 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):
def shoot(self, all_sprites_group, bullets_group):
if not self.hidden:
bullets_shot = []
if self.power_level == 1:
bullet = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
all_sprites_group.add(bullet)
bullets_group.add(bullet)
bullets_shot.append(bullet)
elif self.power_level >= 2:
bullet1 = Bullet(self.rect.centerx, self.rect.top)
all_sprites.add(bullet1)
bullets.add(bullet1)
# Enhanced spread pattern for powered-up shots
spread = 15 # Angle of spread between bullets
for i in range(self.power_level):
offset = (i - (self.power_level - 1) / 2) * spread
bullet = Bullet(self.rect.centerx, self.rect.top, offset)
all_sprites_group.add(bullet)
bullets_group.add(bullet)
bullets_shot.append(bullet)
return bullets_shot
return []

def hide(self):
self.hidden = True
Expand All @@ -111,6 +123,7 @@ def hide(self):
def powerup(self):
self.power_level += 1
self.power_timer = pygame.time.get_ticks()
self.power_display_timer = pygame.time.get_ticks() # Set display timer when power increases

# Enemy class
class Enemy(pygame.sprite.Sprite):
Expand Down Expand Up @@ -139,17 +152,19 @@ def update(self):

# Bullet class
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
def __init__(self, x, y, offset=0):
super().__init__()
self.image = bullet_img
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.bottom = y
self.speedy = 1
self.speedy = -10
self.speedx = offset * 0.3 # Scale the spread effect

def update(self):
self.rect.y += self.speedy
if self.rect.bottom < 0:
self.rect.x += self.speedx
if self.rect.bottom < 0 or self.rect.left < 0 or self.rect.right > SCREEN_WIDTH:
self.kill()

# Powerup class
Expand Down Expand Up @@ -261,28 +276,33 @@ def main_game():
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
player.shoot()
player.shoot(all_sprites, bullets)

# Update
all_sprites.update()

# Check bullet-enemy collisions
hits = pygame.sprite.groupcollide(enemies, bullets, False, True)
hits = pygame.sprite.groupcollide(enemies, bullets, True, True)
for hit in hits:
score += 10
# Create explosion
score += 100
explosion = Explosion(hit.rect.center, 30)
all_sprites.add(explosion)
# Spawn new enemy
new_enemy = Enemy()
all_sprites.add(new_enemy)
enemies.add(new_enemy)
# Random chance for power-up
if random.random() > 0.5: # 50% chance
if random.random() > 0.9:
powerup = Powerup()
all_sprites.add(powerup)
powerups.add(powerup)

# Check player-powerup collisions
hits = pygame.sprite.spritecollide(player, powerups, True)
for hit in hits:
if hit.type == 'shield':
player.shield = min(100, player.shield + 20)
elif hit.type == 'power':
player.powerup()

# Check player-enemy collisions
hits = pygame.sprite.spritecollide(player, enemies, True)
for hit in hits:
Expand All @@ -293,24 +313,16 @@ def main_game():
all_sprites.add(new_enemy)
enemies.add(new_enemy)
if player.shield <= 0:
# player.lives -= 1
player.lives -= 1
player.shield = 100
player.hide()
if player.lives == 0:
if player.lives <= 0:
game_over = True

# Check player-powerup collisions
hits = pygame.sprite.spritecollide(player, powerups, True)
for hit in hits:
if hit.type == 'shield':
player.shield += 20
if player.shield > 100:
player.shield = 100
if hit.type == 'power':
player.powerup()

if game_over:
pass
running = False
pygame.quit()
sys.exit()

# Draw / render
screen.fill(BLACK)
Expand All @@ -321,6 +333,10 @@ def main_game():
draw_shield_bar(screen, 5, 5, player.shield)
draw_lives(screen, SCREEN_WIDTH - 100, 5, player.lives, player_mini_img)

# Display power level when changed
if pygame.time.get_ticks() - player.power_display_timer < 2000: # Show for 2 seconds
draw_text(screen, f"POWER LEVEL {player.power_level}", 24, SCREEN_WIDTH / 2, 50)

# Flip the display
pygame.display.flip()

Expand Down
128 changes: 128 additions & 0 deletions test_space_adventure.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import pytest
import pygame
import os
from space_adventure import (
Player, Enemy, Bullet, Powerup,
SCREEN_WIDTH, SCREEN_HEIGHT,
load_image
)

# Initialize pygame for testing
pygame.init()
pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))

@pytest.fixture
def sprite_groups():
all_sprites = pygame.sprite.Group()
bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()
powerups = pygame.sprite.Group()
return {
'all_sprites': all_sprites,
'bullets': bullets,
'enemies': enemies,
'powerups': powerups
}

@pytest.fixture
def player(sprite_groups):
player = Player()
sprite_groups['all_sprites'].add(player)
return player

@pytest.fixture
def enemy(sprite_groups):
enemy = Enemy()
sprite_groups['all_sprites'].add(enemy)
sprite_groups['enemies'].add(enemy)
return enemy

@pytest.fixture
def bullet(player, sprite_groups):
bullet = Bullet(player.rect.centerx, player.rect.top)
sprite_groups['all_sprites'].add(bullet)
sprite_groups['bullets'].add(bullet)
return bullet

@pytest.fixture
def powerup(sprite_groups):
powerup = Powerup()
sprite_groups['all_sprites'].add(powerup)
sprite_groups['powerups'].add(powerup)
return powerup

def test_player_initialization(player):
assert player.rect.centerx == SCREEN_WIDTH // 2
assert player.rect.bottom == SCREEN_HEIGHT - 10
assert player.shield == 100
assert player.lives == 3
assert not player.hidden
assert player.power_level == 1

def test_player_movement(player, monkeypatch):
# Test right movement
keys = {pygame.K_RIGHT: True, pygame.K_LEFT: False}
monkeypatch.setattr(pygame.key, 'get_pressed', lambda: keys)
initial_x = player.rect.x
player.update()
assert player.rect.x > initial_x

# Test left movement
keys = {pygame.K_RIGHT: False, pygame.K_LEFT: True}
monkeypatch.setattr(pygame.key, 'get_pressed', lambda: keys)
initial_x = player.rect.x
player.update()
assert player.rect.x < initial_x

def test_player_screen_bounds(player):
# Test right boundary
player.rect.right = SCREEN_WIDTH + 100
player.update()
assert player.rect.right == SCREEN_WIDTH

# Test left boundary
player.rect.left = -100
player.update()
assert player.rect.left == 0

def test_enemy_initialization(enemy):
assert 0 <= enemy.rect.x <= SCREEN_WIDTH - enemy.rect.width
assert -150 <= enemy.rect.y <= -100
assert 1 <= enemy.speedy <= 8
assert -3 <= enemy.speedx <= 3

def test_enemy_movement(enemy):
initial_pos = enemy.rect.y
enemy.update()
assert enemy.rect.y > initial_pos

def test_bullet_movement(bullet):
initial_y = bullet.rect.y
bullet.update()
assert bullet.rect.y < initial_y
assert bullet.speedy == -10

def test_powerup_movement(powerup):
initial_y = powerup.rect.y
powerup.update()
assert powerup.rect.y > initial_y
assert powerup.speedy == 4
assert powerup.type in ['shield', 'power']

def test_player_power_up(player):
initial_power = player.power_level
player.powerup()
assert player.power_level == initial_power + 1

def test_player_shooting(player, sprite_groups):
# Test normal shot
player.power_level = 1
bullets = player.shoot(sprite_groups['all_sprites'], sprite_groups['bullets'])
assert len(bullets) == 1
assert len(sprite_groups['bullets']) == 1

# Test powered up shot
player.power_level = 2
bullets = player.shoot(sprite_groups['all_sprites'], sprite_groups['bullets'])
assert len(bullets) == 2
assert len(sprite_groups['bullets']) == 3 # 1 from previous + 2 new ones
Loading