Skip to content

Instantly share code, notes, and snippets.

@jm42
Created December 11, 2015 15:00
Show Gist options
  • Save jm42/18a6c2567968d09b5f5c to your computer and use it in GitHub Desktop.
Save jm42/18a6c2567968d09b5f5c to your computer and use it in GitHub Desktop.
Travel to the Void -- a game in progress
import pygame
import math
from random import random, randint, uniform
WIDTH = 640.0
HEIGHT = 480.0
CENTER = (WIDTH / 2.0, HEIGHT / 2.0)
class SceneManager:
def __init__(self):
self.stack = []
def top(self): return self.stack[-1] if self.stack else None
def push(self, scene): self.stack.append(scene)
def pop(self):
last_scene = self.top()
if last_scene:
del self.stack[-1]
return last_scene
class Scene:
def __init__(self):
self.bg_color = (0, 0, 0)
self.fg_color = (255, 255, 255)
self.cur_color = (255, 255, 0)
self.colors = [
(255, 255, 0),
(255, 200, 200),
(200, 255, 255),
(150, 150, 150)]
self.thick = 9
self.width = math.pi / 12
self.pos = 0.0
self.camera = (0, 0)
self.camera_pos = (0, 0)
self._generate_backgrounds()
def _generate_backgrounds(self):
self.backgrounds = []
for bg in range(2):
size = (WIDTH * 3, HEIGHT * 3)
surface = pygame.Surface(size)
if bg: surface.set_colorkey((0, 0, 0))
surface.lock()
for star in range(150):
color = self.colors[int(random() * len(self.colors))]
pos = (int(random() * surface.get_width()),
int(random() * surface.get_height()))
if bg:
pygame.draw.circle(surface, color, pos, 2)
else:
surface.set_at(pos, color)
surface.unlock()
self.backgrounds.append(surface)
def tick(self):
return NotImplemented
def move(self, pos, rel):
self.move_camera(rel)
self.move_pos(pos)
self.thick = 7 if abs(rel[0]) > 1 or abs(rel[1]) > 1 else 9
self.thick = 5 if abs(rel[0]) > 3 or abs(rel[1]) > 3 else 9
def move_camera(self, rel):
self.camera = (max(0, min(WIDTH, self.camera[0] + rel[0])),
max(0, min(HEIGHT, self.camera[1] + rel[1])))
def move_pos(self, pos):
x = (CENTER[0] * -1) + pos[0]
y = (pos[1] * -1) + CENTER[1]
if x == 0 or y == 0:
return
self.pos = math.atan(y / x)
if x < 0 and y > 0 or x < 0 and y < 0:
self.pos -= math.pi
def pre(self, val):
if val:
self.camera_pos = (randint(-10, 10), randint(-10, 10))
else:
self.camera_pos = (0, 0)
def act(self, manager):
return NotImplemented
def draw(self, screen):
screen.fill(self.bg_color)
self.draw_background(screen)
self.draw_cursor(screen)
self.draw_scene(screen)
def draw_background(self, screen):
for bg, surface in enumerate(self.backgrounds):
screen.blit(surface, self.camera_pos, ((self.camera[0] * (3 - bg),
self.camera[1] * (3 - bg)), (WIDTH, HEIGHT)))
def draw_cursor(self, screen):
size = (HEIGHT - 24)
left = (WIDTH - size) / 2
pygame.draw.arc(screen, self.cur_color, (left, 12, size, size),
self.pos, self.pos + self.width, self.thick)
def draw_scene(self, screen):
return NotImplemented
class IntroScene(Scene):
def __init__(self):
Scene.__init__(self)
self.velocity = 1
self.current = 0
self.text_pos = CENTER
self.texts = [
["In a vast galaxy", 150],
["you can only travel to", 130],
["the VOID", 160]]
self.instructions = pygame.font.SysFont("monospace", 22) \
.render("move your mouse to control the circle "
"and click for action", 1, self.fg_color)
def act(self, manager):
Scene.act(self, manager)
manager.pop()
manager.push(MenuScene())
def draw_scene(self, screen):
if self.current >= len(self.texts):
self.draw_instructions(screen)
else:
self.draw_texts(screen)
def draw_instructions(self, screen):
screen.blit(self.instructions,
(WIDTH - self.instructions.get_width() - 12,
HEIGHT - self.instructions.get_height() - 12))
def draw_texts(self, screen):
label, size = self.texts[self.current]
font = pygame.font.SysFont("monospace", size)
pos = (self.text_pos[0] - (font.size(label)[0] / 2),
self.text_pos[1] - (font.get_linesize()))
screen.blit(font.render(label, 1, self.fg_color), pos)
self.texts[self.current][1] -= self.velocity
if size <= 13:
self.current += 1
class MenuScene(Scene):
def __init__(self):
Scene.__init__(self)
self.font = pygame.font.SysFont("monospace", 35)
self.font_selected = pygame.font.SysFont("monospace", 47)
self.selected = None
self.items = [
["Play", (107, 76, 156)],
#["0", (228, 165, 40)],
["Quit", (192, 10, 44)]]
self._calculate_pos(CENTER)
def _calculate_pos(self, pos):
norm_height = self.font.get_linesize() + 12
selc_height = self.font_selected.get_linesize() + 12
norm_top = pos[1] - (len(self.items) * norm_height / 2.0) - norm_height
selc_top = pos[1] - (len(self.items) * selc_height / 2.0) - selc_height
for item in self.items:
norm_left = pos[0] - (self.font.size(item[0])[0] / 2.0)
selc_left = pos[0] - (self.font_selected.size(item[0])[0] / 2.0)
norm_top += norm_height
selc_top += selc_height
item.append((norm_left, norm_top))
item.append((selc_left, selc_top))
def move(self, pos, rel):
Scene.move(self, pos, rel)
for item in self.items:
if pos[1] >= item[2][1]:
self.selected = item[0]
def act(self, manager):
Scene.act(self, manager)
if not self.selected:
return
manager.pop()
if self.selected == "Play":
manager.push(GameScene())
def draw_scene(self, screen):
self.draw_menu(screen)
def draw_menu(self, screen):
for item in self.items:
label, color, norm, selc = item
if self.selected == label:
pos = selc
font = self.font_selected
color_inverted = (255 - color[0], 255 - color[1], 255 - color[2])
else:
pos = norm
font = self.font
color = (255, 255, 255)
color_inverted = (0, 0, 0)
screen.blit(font.render(label, 0, color_inverted), (pos[0]+3, pos[1]+3))
screen.blit(font.render(label, 1, color), (pos[0], pos[1]))
class GameScene(Scene):
def __init__(self):
Scene.__init__(self)
self.level = 0
self.obstacles_count = 4
self.obstacles = []
for i in range(self.obstacles_count):
self._create_obstacle()
def _create_obstacle(self):
self.obstacles.append([(int(CENTER[0]), int(CENTER[1])),
randint(2, 8), uniform(0, 2 * math.pi), randint(2, 2 + self.level)])
def tick(self):
self._create_obstacle()
def act(self, manager):
Scene.act(self, manager)
manager.pop()
manager.push(MenuScene())
def draw_scene(self, screen):
for n, obs in enumerate(self.obstacles):
pygame.draw.circle(screen, self.fg_color, obs[0], obs[1])
self.obstacles[n][0] = (obs[0][0] + int(obs[3] * math.cos(obs[2])),
obs[0][1] + int(obs[3] * math.sin(obs[2])))
def main():
pygame.init()
pygame.font.init()
pygame.display.set_caption("Trvoid - Travel to Void")
pygame.display.set_mode((int(WIDTH), int(HEIGHT)))
pygame.mouse.set_visible(False)
pygame.time.set_timer(pygame.USEREVENT + 1, 1000)
screen = pygame.display.get_surface()
clock = pygame.time.Clock()
manager = SceneManager()
manager.push(IntroScene())
pre = False
while manager.top():
clock.tick(60)
events = pygame.event.get()
if any(event.type == pygame.QUIT for event in events):
break;
tik = False # Tik-tak does the clock
pos = None # Next current position
rel = None # Next relative position
act = False # To act or not to act
for event in events:
if event.type == pygame.USEREVENT + 1:
tik = True
elif event.type == pygame.MOUSEMOTION:
pos = event.dict["pos"]
rel = event.dict["rel"]
if event.dict["buttons"][0] == 1:
pre = True
else:
pre = False
elif event.type == pygame.MOUSEBUTTONDOWN and \
event.dict["button"] == 1:
pre = True
elif event.type == pygame.MOUSEBUTTONUP and \
event.dict["button"] == 1:
pre = False
act = True
s = manager.top()
s.pre(pre)
tik and s.tick()
pos and s.move(pos, rel)
act and s.act(manager)
s.draw(screen)
pygame.display.flip()
pygame.display.update()
pygame.font.quit()
pygame.quit()
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment