Skip to content

Commit 5d94c67

Browse files
committed
finished project
1 parent c0733ec commit 5d94c67

7 files changed

+240
-6
lines changed

asteroid.py

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import pygame
2+
import random
3+
from circleshape import *
4+
from constants import *
5+
6+
7+
class Asteroid(CircleShape):
8+
def __init__(self, x, y, radius):
9+
super().__init__(x, y, radius)
10+
11+
def draw(self, screen):
12+
pygame.draw.circle(screen, "WHITE", self.position, self.radius, 2)
13+
14+
def update(self, dt):
15+
self.position += self.velocity * dt
16+
17+
def split(self):
18+
self.kill()
19+
if self.radius <= ASTEROID_MIN_RADIUS:
20+
return
21+
22+
random_angle = random.uniform(20, 50)
23+
24+
a = self.velocity.rotate(random_angle)
25+
b = self.velocity.rotate(-random_angle)
26+
27+
new_radius = self.radius - ASTEROID_MIN_RADIUS
28+
asteroid = Asteroid(self.position.x, self.position.y, new_radius)
29+
asteroid.velocity = a * 1.2
30+
asteroid = Asteroid(self.position.x, self.position.y, new_radius)
31+
asteroid.velocity = b * 1.2
32+
33+
34+
35+

asteroidfield.py

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import pygame
2+
import random
3+
from asteroid import *
4+
from constants import *
5+
6+
7+
class AsteroidField(pygame.sprite.Sprite):
8+
edges = [
9+
[
10+
pygame.Vector2(1, 0),
11+
lambda y: pygame.Vector2(-ASTEROID_MAX_RADIUS, y * SCREEN_HEIGHT),
12+
],
13+
[
14+
pygame.Vector2(-1, 0),
15+
lambda y: pygame.Vector2(
16+
SCREEN_WIDTH + ASTEROID_MAX_RADIUS, y * SCREEN_HEIGHT
17+
),
18+
],
19+
[
20+
pygame.Vector2(0, 1),
21+
lambda x: pygame.Vector2(x * SCREEN_WIDTH, -ASTEROID_MAX_RADIUS),
22+
],
23+
[
24+
pygame.Vector2(0, -1),
25+
lambda x: pygame.Vector2(
26+
x * SCREEN_WIDTH, SCREEN_HEIGHT + ASTEROID_MAX_RADIUS
27+
),
28+
],
29+
]
30+
31+
def __init__(self):
32+
pygame.sprite.Sprite.__init__(self, self.containers)
33+
self.spawn_timer = 0.0
34+
35+
def spawn(self, radius, position, velocity):
36+
asteroid = Asteroid(position.x, position.y, radius)
37+
asteroid.velocity = velocity
38+
39+
def update(self, dt):
40+
self.spawn_timer += dt
41+
if self.spawn_timer > ASTEROID_SPAWN_RATE:
42+
self.spawn_timer = 0
43+
44+
# spawn a new asteroid at a random edge
45+
edge = random.choice(self.edges)
46+
speed = random.randint(40, 100)
47+
velocity = edge[0] * speed
48+
velocity = velocity.rotate(random.randint(-30, 30))
49+
position = edge[1](random.uniform(0, 1))
50+
kind = random.randint(1, ASTEROID_KINDS)
51+
self.spawn(ASTEROID_MIN_RADIUS * kind, position, velocity)

circleshape.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import pygame
2+
3+
# Base class for game objects
4+
class CircleShape(pygame.sprite.Sprite):
5+
def __init__(self, x, y, radius):
6+
# we will be using this later
7+
if hasattr(self, "containers"):
8+
super().__init__(self.containers)
9+
else:
10+
super().__init__()
11+
12+
self.position = pygame.Vector2(x, y)
13+
self.velocity = pygame.Vector2(0, 0)
14+
self.radius = radius
15+
16+
def draw(self, screen):
17+
# sub-classes must override
18+
pass
19+
20+
def update(self, dt):
21+
# sub-classes must override
22+
pass
23+
24+
def collosion(self, other):
25+
return self.position.distance_to(other.position) <= self.radius + other.radius

constants.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,10 @@
44
ASTEROID_MIN_RADIUS = 20
55
ASTEROID_KINDS = 3
66
ASTEROID_SPAWN_RATE = 0.8 # seconds
7-
ASTEROID_MAX_RADIUS = ASTEROID_MIN_RADIUS * ASTEROID_KINDS
7+
ASTEROID_MAX_RADIUS = ASTEROID_MIN_RADIUS * ASTEROID_KINDS
8+
PLAYER_RADIUS = 20
9+
PLAYER_TURN_SPEED = 300
10+
PLAYER_SPEED = 200
11+
PLAYER_SHOOT_SPEED = 500
12+
SHOT_RADIUS = 5
13+
PLAYER_SHOOT_COOLDOWN = 0.3

main.py

+52-5
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,69 @@
11
# this allows us to use code from
22
# the open-source pygame library
33
# throughout this file
4-
from constants import SCREEN_WIDTH, SCREEN_HEIGHT
4+
import sys
55
import pygame
6+
from constants import *
7+
from player import Player
8+
from asteroid import *
9+
from asteroidfield import *
10+
from shot import *
11+
12+
613

714
def main():
8-
print("Starting asteroids!")
9-
print(f"Screen width: {SCREEN_WIDTH}")
10-
print(f"Screen height: {SCREEN_HEIGHT}")
1115
pygame.init()
1216
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
17+
clock = pygame.time.Clock()
18+
19+
updatable = pygame.sprite.Group()
20+
drawable = pygame.sprite.Group()
21+
asteroids = pygame.sprite.Group()
22+
shots = pygame.sprite.Group()
23+
24+
25+
26+
27+
Asteroid.containers = (asteroids, updatable, drawable)
28+
Shot.containers = (shots, updatable, drawable)
29+
AsteroidField.containers = updatable
30+
asteroid_field = AsteroidField()
31+
32+
Player.containers = (updatable, drawable)
33+
34+
player = Player(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2)
35+
dt = 0
36+
1337
while True:
1438
for event in pygame.event.get():
1539
if event.type == pygame.QUIT:
1640
return
17-
pygame.Surface.fill(screen, (0, 0, 0))
41+
42+
for update in updatable:
43+
update.update(dt)
44+
45+
for obj in asteroids:
46+
if obj.collosion(player):
47+
print("Game over!")
48+
sys.exit()
49+
50+
for shot in shots:
51+
if obj.collosion(shot):
52+
shot.kill()
53+
obj.split()
54+
55+
56+
screen.fill("black")
57+
58+
for obj in drawable:
59+
obj.draw(screen)
60+
1861
pygame.display.flip()
1962

63+
# limit the framerate to 60 FPS
64+
dt = clock.tick(60) / 1000
65+
66+
2067
if __name__ == "__main__":
2168
main()
2269

player.py

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import pygame
2+
from constants import *
3+
from circleshape import *
4+
from shot import *
5+
6+
class Player(CircleShape):
7+
def __init__(self, x, y):
8+
super().__init__(x, y, PLAYER_RADIUS)
9+
self.rotation = 0
10+
self.shoot_timer = 0
11+
12+
def draw(self, screen):
13+
pygame.draw.polygon(screen, "WHITE", self.triangle(), 2)
14+
15+
def rotate(self, dt):
16+
self.rotation += PLAYER_TURN_SPEED * dt
17+
return self.rotation
18+
19+
def update(self, dt):
20+
self.shoot_timer -= dt
21+
keys = pygame.key.get_pressed()
22+
23+
if keys[pygame.K_a]:
24+
self.rotate(-dt)
25+
if keys[pygame.K_d]:
26+
self.rotate(dt)
27+
if keys[pygame.K_w]:
28+
self.move(dt)
29+
if keys[pygame.K_s]:
30+
self.move(-dt)
31+
if keys[pygame.K_SPACE]:
32+
self.shoot()
33+
34+
def move(self, dt):
35+
forward = pygame.Vector2(0, 1).rotate(self.rotation)
36+
self.position += forward * PLAYER_SPEED * dt
37+
38+
def shoot(self):
39+
if self.shoot_timer > 0:
40+
return
41+
shot = Shot(self.position.x, self.position.y)
42+
shot.velocity = pygame.Vector2(0, 1).rotate(self.rotation) * PLAYER_SHOOT_SPEED
43+
self.shoot_timer = PLAYER_SHOOT_COOLDOWN
44+
45+
46+
47+
48+
# in the player class
49+
def triangle(self):
50+
forward = pygame.Vector2(0, 1).rotate(self.rotation)
51+
right = pygame.Vector2(0, 1).rotate(self.rotation + 90) * self.radius / 1.5
52+
a = self.position + forward * self.radius
53+
b = self.position - forward * self.radius - right
54+
c = self.position - forward * self.radius + right
55+
return [a, b, c]

shot.py

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import pygame
2+
from circleshape import *
3+
from constants import *
4+
5+
6+
class Shot(CircleShape):
7+
def __init__(self, x, y):
8+
super().__init__(x, y, SHOT_RADIUS)
9+
10+
def draw(self, screen):
11+
pygame.draw.circle(screen, "WHITE", self.position, self.radius, 2)
12+
13+
14+
def update(self, dt):
15+
self.position += self.velocity * dt

0 commit comments

Comments
 (0)