Created
December 11, 2015 15:00
-
-
Save jm42/18a6c2567968d09b5f5c to your computer and use it in GitHub Desktop.
Travel to the Void -- a game in progress
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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