parent
33a2342985
commit
3308a7d2c4
3 changed files with 223 additions and 0 deletions
@ -0,0 +1,147 @@ |
||||
#!/usr/bin/env python3 |
||||
from sys import argv |
||||
import pygame as pg |
||||
# locals |
||||
from ship import Ship |
||||
from gem import Gem |
||||
from block import Block |
||||
from starfield import Starfield |
||||
from read_level import read_level |
||||
|
||||
# Colors |
||||
BLACK = (0,)*3 |
||||
WHITE = (255,)*3 |
||||
|
||||
# Graphical Environment |
||||
WIN_SIZE = (640, 480) |
||||
MAX_FPS = 60 |
||||
|
||||
# Game constants |
||||
|
||||
# Sprite positions |
||||
|
||||
if len(argv) >= 2: |
||||
(start, gem_pos, block_pos) = read_level(argv[1]) |
||||
else: |
||||
start = (0,0) |
||||
gem_pos = [(100,100)] |
||||
block_pos = [] |
||||
|
||||
|
||||
# Setup |
||||
pg.init() |
||||
clock = pg.time.Clock() |
||||
|
||||
font = pg.font.SysFont('Courier',24) |
||||
|
||||
pg.display.set_caption(f"Space Collector") |
||||
screen = pg.display.set_mode(WIN_SIZE) |
||||
scr_rect = screen.get_rect() |
||||
|
||||
map_rect = pg.Rect( |
||||
(start[0]-scr_rect.width/2, |
||||
start[1]-scr_rect.height/2), |
||||
scr_rect.size |
||||
) |
||||
|
||||
the_starfield = Starfield(screen); |
||||
|
||||
the_ship = Ship(start,scr_rect) |
||||
the_ship.rect.x = scr_rect.centerx - the_ship.rect.width / 2 |
||||
the_ship.rect.y = scr_rect.centery - the_ship.rect.height / 2 |
||||
|
||||
disp_sprites = pg.sprite.Group() |
||||
gems = pg.sprite.Group(map(Gem,gem_pos)) |
||||
blocks = pg.sprite.Group(map(Block, block_pos)) |
||||
moving = pg.sprite.Group(gems,blocks) |
||||
|
||||
# Game loop |
||||
carry_on = True |
||||
win = False |
||||
|
||||
while carry_on: |
||||
|
||||
# Quitting states |
||||
for event in pg.event.get(): |
||||
if event.type == pg.QUIT: |
||||
carry_on = False |
||||
elif event.type==pg.KEYDOWN: |
||||
if event.key==pg.K_ESCAPE: |
||||
carry_on = False |
||||
|
||||
### Game Logic ### |
||||
|
||||
mouse_events = pg.mouse.get_pressed() |
||||
if mouse_events[0]: |
||||
the_ship.deceleration = 0 |
||||
the_ship.velocity += 1 |
||||
if mouse_events[2]: |
||||
the_ship.deceleration = 1 |
||||
|
||||
mousev = pg.math.Vector2(pg.mouse.get_pos()) |
||||
mousev -= scr_rect.center |
||||
|
||||
# ship movement |
||||
if mousev.length() > the_ship.SIZE/2: |
||||
the_ship.direction += mousev.normalize()/(the_ship.velocity+1) |
||||
the_ship.direction.normalize_ip() |
||||
|
||||
the_ship.velocity = max(the_ship.velocity - the_ship.deceleration, 0) |
||||
if the_ship.velocity == 0: |
||||
the_ship.deceleration = 0 |
||||
|
||||
# Move ship |
||||
the_ship.change = (the_ship.velocity*the_ship.direction) |
||||
the_ship.map_pos.x += round(the_ship.change.x) |
||||
the_ship.map_pos.y += round(the_ship.change.y) |
||||
|
||||
# Move camera to follow ship |
||||
map_rect.x = the_ship.map_pos.x - map_rect.w/2 |
||||
map_rect.y = the_ship.map_pos.y - map_rect.h/2 |
||||
|
||||
|
||||
for s in moving: |
||||
# Display on screen sprites |
||||
if not map_rect.colliderect(s.map_rect): |
||||
s.remove(disp_sprites) |
||||
continue |
||||
|
||||
s.add(disp_sprites) |
||||
if not win: |
||||
s.collide_ship(the_ship) |
||||
|
||||
if len(gems) == 0: |
||||
win = True |
||||
|
||||
### Display Logic ### |
||||
screen.fill(BLACK) |
||||
|
||||
the_starfield.draw(screen, map_rect) |
||||
|
||||
disp_sprites.update(map_rect=map_rect) |
||||
disp_sprites.draw(screen) |
||||
|
||||
the_ship.update(rot_vector= the_ship.direction) |
||||
screen.blit(the_ship.image, the_ship.rect) |
||||
|
||||
if not win: |
||||
elapsed_time = pg.time.get_ticks()/1000 |
||||
elapsed_minutes = int(elapsed_time // 60) |
||||
elapsed_seconds = int(elapsed_time // 1) % 60 |
||||
|
||||
time_string = f"{elapsed_minutes:d}:{elapsed_seconds:02d}" |
||||
time_label = font.render(time_string, 1, WHITE) |
||||
time_pos = (screen.get_width()-10-time_label.get_width(),10) |
||||
screen.blit(time_label, time_pos) |
||||
|
||||
if win: |
||||
gem_str = f"Level Complete!" |
||||
else: |
||||
gem_str = f"Gems to collect:{len(gems):3d} " |
||||
gem_label = font.render(gem_str,True, WHITE) |
||||
screen.blit(gem_label, (10, 10)) |
||||
|
||||
pg.display.flip() |
||||
clock.tick(MAX_FPS) |
||||
|
||||
pg.quit() |
@ -0,0 +1,35 @@ |
||||
from xml.etree import ElementTree |
||||
from itertools import chain |
||||
|
||||
def read_level(file_path): |
||||
schema = '{http://www.w3.org/2000/svg}' |
||||
root = ElementTree.parse(file_path).getroot() |
||||
active = next(filter( |
||||
lambda g: g.get('id') == "ACTIVE", |
||||
root.iter(f"{schema}g"))) |
||||
block_pos = [ ( |
||||
float(rect.get('x')), |
||||
float(rect.get('y')), |
||||
float(rect.get('width')), |
||||
float(rect.get('height')), |
||||
) |
||||
for rect in active.iter(f"{schema}rect") |
||||
] |
||||
gem_pos = [] |
||||
ellipses = chain( |
||||
active.iter(f"{schema}circle"), |
||||
active.iter(f"{schema}ellipse") |
||||
) |
||||
for ellipse in ellipses: |
||||
if ellipse.get('id') == "START": |
||||
start = ( |
||||
float(ellipse.get(f'cx')), |
||||
float(ellipse.get(f'cy')), |
||||
) |
||||
else: |
||||
gem_pos.append(( |
||||
float(ellipse.get('cx')), |
||||
float(ellipse.get('cy')), |
||||
)) |
||||
|
||||
return (start, gem_pos, block_pos) |
@ -0,0 +1,41 @@ |
||||
import pygame as pg |
||||
import random |
||||
|
||||
WHITE = (255,)*3 |
||||
|
||||
def snap(x, scale): |
||||
return int(x//scale)*scale |
||||
|
||||
|
||||
class Starfield: |
||||
|
||||
def __init__(self, |
||||
screen, |
||||
inv_density=10, |
||||
grid_step=31, |
||||
paralax = 2, |
||||
star_color=WHITE, |
||||
star_size = 1): |
||||
self.rng = random.Random() |
||||
self.screen = screen |
||||
self.inv_density = inv_density |
||||
self.paralax = paralax |
||||
self.grid_step = grid_step |
||||
self.star_color = star_color |
||||
self.star_size = star_size |
||||
|
||||
def draw(self, screen, map_pos): |
||||
sky_pos = pg.math.Vector2((map_pos.x, map_pos.y))/self.paralax |
||||
xstart = snap(sky_pos.x, self.grid_step) |
||||
ystart = snap(sky_pos.y, self.grid_step) |
||||
xstop = xstart + screen.get_rect().width |
||||
ystop = ystart + screen.get_rect().width |
||||
for x in range(xstart, xstop, self.grid_step): |
||||
for y in range(ystart, ystop, self.grid_step): |
||||
self.rng.seed(hash((x,y))) |
||||
if self.rng.randint(0, self.inv_density) == 0: |
||||
xoff = self.rng.randint(0, self.grid_step) |
||||
yoff = self.rng.randint(0, self.grid_step) |
||||
cx = x + xoff - sky_pos.x |
||||
cy = y + yoff - sky_pos.y |
||||
pg.draw.circle(screen, self.star_color, (cx,cy), self.star_size) |
Loading…
Reference in new issue