From 0469021ff341e12535918037b59d9f2c7125907b Mon Sep 17 00:00:00 2001 From: rdarius Date: Sun, 19 Jan 2025 23:50:23 +0200 Subject: [PATCH] ze game --- asteroid.py | 36 ++++++++++++++++++++++++++++++++ asteroidfield.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++ circleshape.py | 29 ++++++++++++++++++++++++++ constants.py | 10 ++++++++- main.py | 45 ++++++++++++++++++++++++++++++++++++++-- player.py | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ shot.py | 16 +++++++++++++++ 7 files changed, 237 insertions(+), 3 deletions(-) create mode 100644 asteroid.py create mode 100644 asteroidfield.py create mode 100644 circleshape.py create mode 100644 player.py create mode 100644 shot.py diff --git a/asteroid.py b/asteroid.py new file mode 100644 index 0000000..0057708 --- /dev/null +++ b/asteroid.py @@ -0,0 +1,36 @@ +import pygame +from circleshape import CircleShape +from constants import * +import random + +class Asteroid(CircleShape): + + def __init__(self, x, y, radius): + super().__init__(x, y, radius) + + def draw(self, screen): + pygame.draw.circle(screen, pygame.Color(255, 255, 255), self.position, self.radius, 2) + + def update(self, dt): + self.position += self.velocity * dt + + def split(self): + self.kill() + if self.radius <= ASTEROID_MIN_RADIUS: + return + + angle = random.uniform(20, 50) + + new1 = Asteroid(self.position.x, self.position.y, self.radius - ASTEROID_MIN_RADIUS) + new1.velocity = self.velocity + new1.velocity = new1.velocity.rotate(angle) + new1.velocity *= 1.2 + + new2 = Asteroid(self.position.x, self.position.y, self.radius - ASTEROID_MIN_RADIUS) + new2.velocity = self.velocity + new2.velocity = new2.velocity.rotate(-angle) + new2.velocity *= 1.2 + + + + \ No newline at end of file diff --git a/asteroidfield.py b/asteroidfield.py new file mode 100644 index 0000000..74d9d57 --- /dev/null +++ b/asteroidfield.py @@ -0,0 +1,51 @@ +import pygame +import random +from asteroid import Asteroid +from constants import * + + +class AsteroidField(pygame.sprite.Sprite): + edges = [ + [ + pygame.Vector2(1, 0), + lambda y: pygame.Vector2(-ASTEROID_MAX_RADIUS, y * SCREEN_HEIGHT), + ], + [ + pygame.Vector2(-1, 0), + lambda y: pygame.Vector2( + SCREEN_WIDTH + ASTEROID_MAX_RADIUS, y * SCREEN_HEIGHT + ), + ], + [ + pygame.Vector2(0, 1), + lambda x: pygame.Vector2(x * SCREEN_WIDTH, -ASTEROID_MAX_RADIUS), + ], + [ + pygame.Vector2(0, -1), + lambda x: pygame.Vector2( + x * SCREEN_WIDTH, SCREEN_HEIGHT + ASTEROID_MAX_RADIUS + ), + ], + ] + + def __init__(self): + pygame.sprite.Sprite.__init__(self, self.containers) + self.spawn_timer = 0.0 + + def spawn(self, radius, position, velocity): + asteroid = Asteroid(position.x, position.y, radius) + asteroid.velocity = velocity + + def update(self, dt): + self.spawn_timer += dt + if self.spawn_timer > ASTEROID_SPAWN_RATE: + self.spawn_timer = 0 + + # spawn a new asteroid at a random edge + edge = random.choice(self.edges) + speed = random.randint(40, 100) + velocity = edge[0] * speed + velocity = velocity.rotate(random.randint(-30, 30)) + position = edge[1](random.uniform(0, 1)) + kind = random.randint(1, ASTEROID_KINDS) + self.spawn(ASTEROID_MIN_RADIUS * kind, position, velocity) \ No newline at end of file diff --git a/circleshape.py b/circleshape.py new file mode 100644 index 0000000..6060cda --- /dev/null +++ b/circleshape.py @@ -0,0 +1,29 @@ +import pygame + +# Base class for game objects +class CircleShape(pygame.sprite.Sprite): + def __init__(self, x, y, radius): + # we will be using this later + if hasattr(self, "containers"): + super().__init__(self.containers) + else: + super().__init__() + + self.position = pygame.Vector2(x, y) + self.velocity = pygame.Vector2(0, 0) + self.radius = radius + + def draw(self, screen): + # sub-classes must override + pass + + def update(self, dt): + # sub-classes must override + pass + + def is_collission(self, obj): + distance = self.position.distance_to(obj.position) + if (distance <= self.radius + obj.radius): + return True + + return False \ No newline at end of file diff --git a/constants.py b/constants.py index f9e4d64..a4c71fc 100644 --- a/constants.py +++ b/constants.py @@ -4,4 +4,12 @@ SCREEN_HEIGHT = 720 ASTEROID_MIN_RADIUS = 20 ASTEROID_KINDS = 3 ASTEROID_SPAWN_RATE = 0.8 # seconds -ASTEROID_MAX_RADIUS = ASTEROID_MIN_RADIUS * ASTEROID_KINDS \ No newline at end of file +ASTEROID_MAX_RADIUS = ASTEROID_MIN_RADIUS * ASTEROID_KINDS + +PLAYER_RADIUS = 20 +PLAYER_TURN_SPEED = 300 +PLAYER_SPEED = 200 +PLAYER_SHOOT_SPEED = 500 +SHOT_RADIUS = 5 + +PLAYER_SHOOT_COOLDOWN=0.3 \ No newline at end of file diff --git a/main.py b/main.py index db86631..c6ca3c3 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,10 @@ import pygame +import sys from constants import * +from player import Player +from asteroid import Asteroid +from shot import Shot +from asteroidfield import AsteroidField def main(): @@ -10,16 +15,52 @@ def main(): pygame.init() screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + updatable = pygame.sprite.Group() + drawable = pygame.sprite.Group() + asteroids = pygame.sprite.Group() + shots = pygame.sprite.Group() + + clock = pygame.time.Clock() + dt = 0 + player = Player(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2) + drawable.add(player) + updatable.add(player) + + Player.containers = (updatable, drawable) + Asteroid.containers = (asteroids, updatable, drawable) + AsteroidField.containers = (updatable) + Shot.containers = (shots, updatable, drawable) + + asteroidField = AsteroidField() + while True: for event in pygame.event.get(): if event.type == pygame.QUIT: return + + dt = clock.tick(60)/1000 + + for entity in updatable: + entity.update(dt) + + for entity in asteroids: + if player.is_collission(entity): + print("Game Over!") + sys.exit(0) + + for bullet in shots: + if bullet.is_collission(entity): + entity.split() + bullet.kill() + continue screen.fill(pygame.Color(0, 0, 0), pygame.Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)) - - + + for entity in drawable: + entity.draw(screen) pygame.display.flip() + if __name__ == "__main__": main() diff --git a/player.py b/player.py new file mode 100644 index 0000000..b95df1b --- /dev/null +++ b/player.py @@ -0,0 +1,53 @@ +from circleshape import CircleShape +from constants import * +from shot import Shot +import pygame + +class Player(CircleShape): + def __init__(self, x, y): + super().__init__(x, y, PLAYER_RADIUS) + self.rotation = 0 + self.cooldown = 0 + + # in the player class + def triangle(self): + forward = pygame.Vector2(0, 1).rotate(self.rotation) + right = pygame.Vector2(0, 1).rotate(self.rotation + 90) * self.radius / 1.5 + a = self.position + forward * self.radius + b = self.position - forward * self.radius - right + c = self.position - forward * self.radius + right + return [a, b, c] + + def draw(self, screen): + super().draw(screen) + pygame.draw.polygon(screen, pygame.Color(255, 255, 255), self.triangle(), 2) + + def rotate(self, dt): + self.rotation += PLAYER_TURN_SPEED * dt + + def update(self, dt): + keys = pygame.key.get_pressed() + + self.cooldown -= dt + + if keys[pygame.K_a]: + self.rotate(-dt) + if keys[pygame.K_d]: + self.rotate(dt) + if keys[pygame.K_w]: + self.move(dt) + if keys[pygame.K_s]: + self.move(-dt) + if keys[pygame.K_SPACE]: + self.shoot() + + def move(self, dt): + forward = pygame.Vector2(0, 1).rotate(self.rotation) + self.position += forward * PLAYER_SPEED * dt + + def shoot(self): + if self.cooldown > 0: + return + self.cooldown = PLAYER_SHOOT_COOLDOWN + shot = Shot(self.position.x, self.position.y) + shot.velocity = pygame.Vector2(0, 1).rotate(self.rotation) * PLAYER_SHOOT_SPEED \ No newline at end of file diff --git a/shot.py b/shot.py new file mode 100644 index 0000000..60dfb61 --- /dev/null +++ b/shot.py @@ -0,0 +1,16 @@ +import pygame +from circleshape import CircleShape +from constants import * + +class Shot(CircleShape): + + def __init__(self, x, y): + super().__init__(x, y, SHOT_RADIUS) + + def draw(self, screen): + pygame.draw.circle(screen, pygame.Color(255, 255, 255), self.position, self.radius, 2) + + def update(self, dt): + self.position += self.velocity * dt + + \ No newline at end of file