def draw(self): """ Render the display. """ # Fill in the background self.screen.fill(self.bg_color) # Update and draw the group contents LayeredUpdates.draw(self, self.screen) # draw units for u in base_unit.BaseUnit.active_units: self.update_unit_rect(u) base_unit.BaseUnit.active_units.draw(self.screen) # If there's a selected unit, outline it if self.sel_unit: pygame.gfxdraw.rectangle( self.screen, self.sel_unit.rect, SELECT_COLOR) # Mark potential targets for tile_pos in self._attackable_tiles: screen_pos = self.map.screen_coords(tile_pos) self.draw_reticle(screen_pos) # Draw effects self._effects.draw(self.screen) # Draw the status bar self.draw_bar() # Draw the win message if self.mode == Modes.GameOver: # Determine the message win_text = "TEAM {} WINS!".format( TEAM_NAME[self.win_team].upper()) # Render the text win_msg = BIG_FONT.render( win_text, True, FONT_COLOR) # Move it into position msg_rect = pygame.Rect((0, 0), win_msg.get_size()) msg_rect.center = (MAP_WIDTH / 2, self.screen.get_height() / 2) # Draw it self.screen.blit(win_msg, msg_rect) # Update the screen pygame.display.flip()
class Scene(ABC): REGULAR_FONT = "fonts/Connection/Connection.otf" BOLD_FONT = "fonts/Connection/ConnectionBold.otf" def __init__(self, controller): self.__controller = controller self.__last_scene = controller.get_scene() self.game_objects = LayeredUpdates() self.screen_rect = pygame.display.get_surface().get_rect() try: open(self.REGULAR_FONT).close() except FileNotFoundError: fix_path() @abstractmethod def handle_events(self, events): pass @abstractmethod def update(self, ms): game_objects = self.game_objects game_objects.update(ms) collisions = groupcollide(game_objects, game_objects, False, False) for key, value in collisions.items(): value.pop(0) if value: key.collide(value) @abstractmethod def render(self, screen): return self.game_objects.draw(screen) def load(self): pass
def draw(self, screen): # Don't do anything if stopped if not self.started: return LayeredUpdates.draw(self, screen) for u in self.p0_units: screen.blit(self.bg, u.image.get_rect().move(u.prev_pos), area=u.image.get_rect().move(u.prev_pos)) for u in self.p1_units: screen.blit(self.bg, u.rect.move(u.prev_pos), area=u.rect.move(u.prev_pos)) for u in self.p0_units: u.draw(screen) for u in self.p1_units: u.draw(screen)
class Scene(ABC): REGULAR_FONT = "fonts/Connection/Connection.otf" BOLD_FONT = "fonts/Connection/ConnectionBold.otf" def __init__(self, controller): try: open(self.REGULAR_FONT).close() except FileNotFoundError: fix_path() self._font = ftfont.Font(self.REGULAR_FONT, 50) self._small_font = ftfont.Font(self.REGULAR_FONT, 30) self._bold_font = ftfont.Font(self.BOLD_FONT, 30) self.__controller = controller try: self.__last_scene = controller.get_scene() except AttributeError: self.__last_scene = None self.game_objects = LayeredUpdates() self.screen_rect = pygame.display.get_surface().get_rect() background = pygame.Surface(self.screen_rect.size) background.fill((240, 240, 240)) self.background = GameObject(self.game_objects, pygame.Rect(0, 0, 0, 0), background) self.game_objects.add(self.background) @abstractmethod def handle_events(self, events): pass @abstractmethod def update(self, ms): game_objects = self.game_objects game_objects.update(ms) collisions = groupcollide(game_objects, game_objects, False, False) for key, value in collisions.items(): value.pop(0) if value: try: key.collide(value) except AttributeError: pass @abstractmethod def render(self, screen): return self.game_objects.draw(screen) def load(self): pass def back(self): # return to last scene self.__controller.set_scene(self.__last_scene) def set_scene(self, SceneClass: 'Scene', *args): self.__controller.set_scene(SceneClass(self.__controller, *args))
def draw(self, active_units): """ Render the display. Modified code from assignment four to be more applicable to checkers. """ # Fill in the background self.screen.fill(self.bg_color) # Update and draw the group contents LayeredUpdates.draw(self, self.screen) # draw units for u in active_units: u.rect.x, u.rect.y = self.update_unit_rect(u) active_units.draw(self.screen) for i in self.buttons: self.draw_bar_button(i) # Draw the win message if self.mode == Modes.GameOver: # Determine the message win_text = "TEAM {} WINS!".format(TEAM_NAME[self.win_team].upper()) #Clear Highlights self.map.clear_highlights() # Render the text win_msg = BIG_FONT.render(win_text, True, FONT_COLOR) # Move it into position msg_rect = pygame.Rect((0, 0), win_msg.get_size()) msg_rect.center = (MAP_WIDTH / 2, self.screen.get_height() / 2) # Draw it self.screen.blit(win_msg, msg_rect) # Update the screen pygame.display.flip()
class PlatformerScene(Scene): def __init__(self, game): super().__init__(game) self.player = None self.active = True self.geometry = list() self.space = pymunk.Space() self.space.gravity = (0, 1000) self.sprites = LayeredUpdates() self.event_handler = event_handling.EventQueueHandler() self.background = resources.gfx("background.png", convert=True) self.load() pygame.mixer.music.load(resources.music_path("zirkus.ogg")) pygame.mixer.music.play(-1) def add_static(self, vertices, rect): body = pymunk.Body(body_type=pymunk.Body.STATIC) body.position = rect.x, rect.y shape = pymunk.Poly(body, vertices) shape.friction = 1.0 shape.elasticity = 1.0 self.space.add(body, shape) def load(self): def box_vertices(x, y, w, h): lt = x, y rt = x + w, y rb = x + w, y + h lb = x, y + h return lt, rt, rb, lb filename = path_join("data", "maps", "untitled.tmx") tmxdata = pytmx.util_pygame.load_pygame(filename) for obj in tmxdata.objects: if obj.type == map_fixed: rect = Rect(obj.x, obj.y, obj.width, obj.height) vertices = box_vertices(0, 0, obj.width, obj.height) self.add_static(vertices, rect) elif obj.type == map_yarn_spawn: ball = sprite.Ball(Rect((obj.x, obj.y), (32, 32))) model = BasicModel() model.sprites = [ball] model.pymunk_objects = ball.pymunk_shapes self.add_model(model) self.player = model elif obj.type == map_player_spawn: self.player = unicyclecat.build(self.space, self.sprites) self.player.position = obj.x, obj.y self.fsm = SimpleFSM(control, "idle") def add_model(self, model): self.sprites.add(*model.sprites) self.space.add(model.pymunk_objects) def remove_model(self, model): self.sprites.remove(*model.sprites) self.space.remove(model.pymunk_objects) def render(self): surface = self._game.screen surface.blit(self.background, (0, 0)) self.sprites.draw(surface) return [surface.get_rect()] def tick(self, dt): step_amount = (1 / 30.) / 30 for i in range(30): self.space.step(step_amount) self.sprites.update(dt) def event(self, pg_event): events = self.event_handler.process_event(pg_event) position = self.player.position for event in events: try: cmd, arg = self.fsm((event.button, event.held)) except ValueError as e: continue if cmd == "move": resources.sfx("cat_wheel.ogg", False, True) resources.sfx("cat_wheel.ogg", True) self.player.accelerate(arg) if cmd == "idle": self.player.brake() elif cmd == "jump": resources.sfx("cat_jump.ogg", True) self.player.main_body.apply_impulse_at_world_point((0, -600), position)
class Cutscene(Minigame): GAME_NAME = "Cutscene" _default_layer = 1 def __init__(self, scene_name="cutscene001", scene_file_name="test-cutscene.yaml"): self.running = False self.script_runner = ScriptRunner() self._scene_name = scene_name self._scene_file_name = scene_file_name self._border = None self._sprites = LayeredUpdates() self._animations = Group() self._dialog_open = False self._dialog_rect = None self._caption = None self._text = None def initialize(self, context): with open(get_data_asset(self._scene_file_name)) as fp: config = yaml.load(fp) self.script_runner.start(self, config[self._scene_name]) @staticmethod def new_sprite(image, rect): sprite = Sprite() sprite.image = image sprite.rect = rect return sprite def animate(self, *args, **kwargs): ani = animation.Animation(*args, **kwargs) self._animations.add(ani) return ani def add_sprite(self, image, rect, layer=None): self._sprites.add(self.new_sprite(image, rect), layer=ternone(layer, self._default_layer)) def set_background(self, filename): surf = smoothscale(load_image(filename), SCREEN_SIZE).convert() rect = (0, 0), SCREEN_SIZE self.add_sprite(surf, rect, 0) def set_portrait(self, filename): size = 340, 680 # HACK to remove old portrait for sprite in self._sprites: if sprite.image.get_size() == size: self._sprites.remove(sprite) if filename is not None: surf = smoothscale(load_image(filename), size).convert_alpha() rect = (900, 60), size self.add_sprite(surf, rect, 1) def set_caption(self, value): if value is None: self._caption = None return get = self.script_runner.vars.get fcolor = Color(get('caption-fg', 'black')) font = load_font('pixChicago.ttf', 16) if 'caption-bg' in self.script_runner.vars and get( 'caption-bg') is not None: bcolor = Color(get('caption-bg')) image = font.render(value, 0, fcolor, bcolor) margins = image.get_rect().inflate(45, 0) background = pygame.Surface(margins.size) background.fill(bcolor) background.blit(image, (24, 0)) self._caption = background else: self._caption = font.render(value, 0, fcolor) def set_text(self, value): get = self.script_runner.vars.get fcolor = Color(get('text-fg', 'black')) bcolor = none_or_not(self.script_runner.vars, 'text-bg', Color) font = load_font('pixChicago.ttf', 16) w, h = self.final_rect().size w -= 48 final_rect = Rect((0, 0), (w, h)) self._text = pygame.Surface(final_rect.size, pygame.SRCALPHA) draw_text(self._text, value, final_rect, font, fcolor, bcolor) def final_rect(self): sw, sh = SCREEN_SIZE return Rect(sw * .05, sh * .6, sw * .62, sh * .35) def queue_dialog_text(self, value): self.set_text(value) def open_dialog(self): self._dialog_open = True final_rect = self.final_rect() self._dialog_rect = Rect(0, 0, 64, 64, center=final_rect.center) ani = self.animate(self._dialog_rect, height=final_rect.height, width=final_rect.width, duration=100) ani.schedule( lambda: setattr(self._dialog_rect, "center", final_rect.center), 'on update') def close_dialog(self): self._dialog_open = False def run(self, context): flip = pygame.display.flip update = self.update draw = self.draw handle_events = self.handle_event screen = pygame.display.get_surface() clock = time.time frame_time = (1 / 60.) * 1000 last_draw = 0 times = deque(maxlen=10) self.running = True last_frame = clock() while self.running: dt = (clock() - last_frame) * 1000 last_frame = clock() times.append(dt) dt = sum(times) / 10 last_draw += dt handle_events() update(dt) if last_draw >= frame_time: draw(screen) flip() last_draw = 0 pygame.mixer.music.fadeout(800) def draw(self, screen): self._sprites.draw(screen) if self._dialog_open: self.draw_dialog(screen) def draw_dialog(self, surface): with surface_clipping_context(surface, self._dialog_rect): self._border.draw(surface, self._dialog_rect) internal = self._dialog_rect.inflate(-48, -6) with surface_clipping_context(surface, internal): if self._caption: rect = self._caption.get_rect() rect.top = internal.top rect.centerx = internal.centerx surface.blit(self._caption, rect) if self._text: rect = internal.copy() rect.top = internal.top + 75 rect.left = internal.left surface.blit(self._text, rect) def update(self, dt): self._animations.update(dt) def button_press(self): """ Handles the ACTION button :return: """ self.script_runner.dialog_event('press') def handle_event(self): for event in pygame.event.get(): if event.type == KEYDOWN: if event.key == K_ESCAPE: self.running = False if event.key == K_SPACE: self.button_press() if event.type == QUIT: # this will allow pressing the windows (X) to close the game sys.exit(0)
def graph_loop(mass_lower_limit=0.0, mass_upper_limit=0.0, radius_lower_limit=0.0, radius_upper_limit=0.0, is_gas_drwaf=False): m_lo_l = mass_lower_limit m_hi_l = mass_upper_limit r_lo_l = radius_lower_limit r_hi_l = radius_upper_limit fondo = display.set_mode((witdh, height), SCALED) rect = Rect(60, 2, 529, 476) lineas = LayeredUpdates() linea_h = Linea(rect, rect.x, rect.centery, rect.w, 1, lineas) linea_v = Linea(rect, rect.centerx, rect.y, 1, rect.h, lineas) punto = Punto(rect, rect.centerx, rect.centery, lineas) data = {} if any([ mass_lower_limit < 0, mass_upper_limit < 0, radius_lower_limit < 0, radius_upper_limit < 0 ]): raise ValueError() lim_mass_a = int(find_and_interpolate(m_lo_l, mass_keys, exes)) if m_lo_l else 0 lim_mass_b = int(find_and_interpolate(m_hi_l, mass_keys, exes)) if m_hi_l else 0 lim_radius_a = int(find_and_interpolate(r_lo_l, radius_keys, yes)) if r_lo_l else 0 lim_radius_b = int(find_and_interpolate(r_hi_l, radius_keys, yes)) if r_hi_l else 0 move_x, move_y = True, True lockx, locky = False, False mass_value = 0 radius_value = 0 mass_color = negro radius_color = negro mouse.set_pos(rect.center) event.clear() done = False composition_text_comp = None while not done: for e in event.get(): if e.type == QUIT: py_quit() if __name__ == '__main__': sys.exit() elif e.type == MOUSEBUTTONDOWN: if e.button == 1: if (not lockx) or (not locky): if (not lockx) and (not move_x): lockx = True elif (not locky) and (not move_y): locky = True elif not punto.disabled: data['mass'] = round(mass_value, 3) data['radius'] = round(radius_value, 3) data['gravity'] = round( mass_value / (radius_value**2), 3) data['density'] = round( mass_value / (radius_value**3), 3) done = True else: data = {} done = True elif e.button == 3: if lockx: lockx = False move_x = not lockx if locky: locky = False move_y = not locky elif e.type == MOUSEMOTION: px, py = e.pos if move_y: linea_h.move_y(py) punto.move_y(py) if move_x: linea_v.move_x(px) punto.move_x(px) point_x, point_y = punto.rect.center if rect.collidepoint(point_x, point_y) and (move_x or move_y): if mascara.get_at((point_x, point_y)): punto.select() for name in _lineas: if [point_x, point_y] in _lineas[name]: composition_text_comp = name break else: punto.deselect() elif e.type == KEYDOWN: if e.key == K_ESCAPE: py_quit() sys.exit() if e.key == K_LSHIFT: move_x = False elif e.key == K_LCTRL: move_y = False elif e.key == K_SPACE: data['mass'] = round(mass_value, 3) data['radius'] = round(radius_value, 3) data['gravity'] = round(mass_value / (radius_value**2), 3) data['density'] = round(mass_value / (radius_value**3), 3) done = True elif e.type == KEYUP: if e.key == K_LSHIFT: if not lockx: move_x = True elif e.key == K_LCTRL: if not locky: move_y = True px, py = punto.rect.center alto, bajo = 0, 0 if rect.collidepoint((px, py)): for _y in reversed(range(0, py)): if mascara.get_at((px, _y)): alto = _y break for _y in range(py, 476): if mascara.get_at((px, _y)): bajo = _y break a, b = 0, 0 # creo que esto se puede escribir con oneliners. for name in _lineas: if [px, alto] in _lineas[name]: a = name break for name in _lineas: if [px, bajo] in _lineas[name]: b = name break if a and b: c = composiciones silicates = interpolate(py, alto, bajo, c[a]['silicates'], c[b]['silicates']) hydrogen = interpolate(py, alto, bajo, c[a]['hydrogen'], c[b]['hydrogen']) helium = interpolate(py, alto, bajo, c[a]['helium'], c[b]['helium']) iron = interpolate(py, alto, bajo, c[a]['iron'], c[b]['iron']) water_ice = interpolate(py, alto, bajo, c[a]['water ice'], c[b]['water ice']) values = [ i for i in [silicates, hydrogen, helium, iron, water_ice] if i != 0 ] # sólo mostramos los valores mayores a 0% keys, compo = [], [] if silicates: compo.append(str(round(silicates, 2)) + '% silicates') keys.append('silicates') if hydrogen: compo.append(str(round(hydrogen, 2)) + '% hydrogen') keys.append('hydrogen') if helium: compo.append(str(round(helium, 2)) + '% helium') keys.append('helium') if iron: compo.append(str(round(iron, 2)) + '% iron') keys.append('iron') if water_ice: compo.append(str(round(water_ice, 2)) + '% water ice') keys.append('water ice') composition_text_comp = ', '.join(compo) data['composition'] = dict(zip(keys, values)) if hydrogen or helium: data['clase'] = 'Gas Dwarf' data['albedo'] = 30 else: data['clase'] = 'Terrestial Planet' data['albedo'] = 25 else: data = {} mass_value = find_and_interpolate(linea_v.rect.x, exes, mass_keys) radius_value = find_and_interpolate_flipped(linea_h.rect.y, yes, radius_keys) block = Surface(rect.size, SRCALPHA) block_mask = mask.from_surface(block) if any([lim_mass_b, lim_mass_a, lim_radius_a, lim_radius_b]): block_rect = block.get_rect(topleft=rect.topleft) alpha = 150 if lim_mass_a: block.fill([0] * 3 + [alpha], (0, rect.y - 2, lim_mass_a - rect.x, rect.h)) if lim_mass_b: block.fill([0] * 3 + [alpha], (lim_mass_b - rect.x, rect.y - 2, rect.w, rect.h)) if lim_radius_a: block.fill([0] * 3 + [alpha], (0, lim_radius_a, rect.w, rect.h - lim_radius_a)) if lim_radius_b: block.fill([0] * 3 + [alpha], (0, rect.y - 2, rect.w, lim_radius_b)) if is_gas_drwaf: block.blit(gas_drawf, (0, 0)) block_mask = mask.from_surface(block) point_x, point_y = punto.rect.center if block_rect.collidepoint((point_x, point_y)): if block_mask.get_at((point_x - rect.x, point_y - rect.y)): punto.disable() radius_color = rojo mass_color = rojo else: punto.enable() mass_color = negro radius_color = negro mass_text = 'Mass:' + str(round(mass_value, 3)) radius_text = 'Radius:' + str(round(radius_value, 3)) gravity_text = 'Density:' + str( round(mass_value / (radius_value**3), 3)) density_text = 'Gravity:' + str( round(mass_value / (radius_value**2), 3)) if not done: fondo.fill(blanco) fondo.blit(graph, (0, 0)) if block_mask.count() != 0: fondo.blit(block, rect) if punto.disabled: fondo.blit(texto3, rectT3) else: fondo.blit(fuente1.render(mass_text, True, mass_color), (5, rect.bottom + 43)) fondo.blit(fuente1.render(radius_text, True, radius_color), (140, rect.bottom + 43)) fondo.blit(fuente1.render(density_text, True, negro), (130 * 2 - 5, rect.bottom + 43)) fondo.blit(fuente1.render(gravity_text, True, negro), (140 * 3, rect.bottom + 43)) if composition_text_comp is not None: composition_text = 'Composition:' + composition_text_comp fondo.blit( fuente1.render(composition_text, True, negro, blanco), (5, rect.bottom + 64)) fondo.blit(texto1, rectT1) fondo.blit(texto2, rectT2) punto.update() lineas.update() lineas.draw(fondo) display.update() display.quit() return data
class DDR(Microgame): def __init__(self): Microgame.__init__(self) self.rect=Rect(0,0, locals.WIDTH, locals.HEIGHT) self.arrow1=arrow(self,'left',50,50,0,0) self.arrow2=arrow(self,'down',150,50,0,0) self.arrow3=arrow(self,'up',250, 50,0,0) self.arrow4=arrow(self,'right',350,50,0,0) self.background=Background() self.sprites=LayeredUpdates([self.background,self.arrow1,self.arrow2,self.arrow3,self.arrow4]) self.timesincearrow=0 self.dancer=pyganim.PygAnimation([('games/DDR/DDRGIFS/TWERK/twerk1.png',0.1), ('games/DDR/DDRGIFS/TWERK/twerk2.png',0.1), ('games/DDR/DDRGIFS/TWERK/twerk3.png',0.1), ('games/DDR/DDRGIFS/TWERK/twerk4.png',0.1), ('games/DDR/DDRGIFS/TWERK/twerk5.png',0.1), ('games/DDR/DDRGIFS/TWERK/twerk6.png',0.1)]) self.anim=pyganim.PygAnimation([('games/DDR/DDRGIFS/MUSIC_ANIMATION/music1.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music2.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music3.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music4.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music5.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music6.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music7.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music8.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music9.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music10.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music11.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music12.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music13.png',0.1), ('games/DDR/DDRGIFS/MUSIC_ANIMATION/music14.png',0.1)]) self.disco=pyganim.PygAnimation([('games/DDR/DDRGIFS/DISCOBALL/disco3.png',0.1), ('games/DDR/DDRGIFS/DISCOBALL/disco4.png',0.1)]) self.dancer.play() self.anim.play() self.disco.play() def time_elapsed(self): self.timesincearrow=pygame.time.get_ticks() def start(self): self.time_elapsed() music.load('games/DDR/geekin.ogg') music.play(2,0.0) def stop(self): music.stop() def update(self): self.sprites.update() time=pygame.time.get_ticks() if time-self.timesincearrow>350: num=randint(0,3) if num==0: self.sprites.add(moving_arrow(self,'left',50,768,0,-10)) elif num==1: self.sprites.add(moving_arrow(self,'down',150,768,0,-10)) elif num==2: self.sprites.add(moving_arrow(self,'up',250,768,0,-10)) elif num==3: self.sprites.add(moving_arrow(self,'right',350,768,0,-10)) self.time_elapsed() for event in pygame.event.get(): if event.type==KEYDOWN or event.type==KEYUP: if event.key==K_q: self.lose() def render(self,surface): surface.fill(Color(0,0,0)) self.sprites.draw(surface) self.dancer.blit(surface,(800,100)) self.anim.blit(surface,(550,500)) self.disco.blit(surface,(600,50))
class Jackin(Minigame): GAME_NAME = "Jackin" _default_layer = 1 charset = "1234567890QWERTYUIOPASDFGHJKLZXCVBNM,.?>&/=" def __init__(self): super(Jackin, self).__init__() self.running = False self._sprites = LayeredUpdates() self._animations = Group() self.platten_speed = 40 self.pressed = set() self.cpl = 40 self.buffer = None self.cache = None self.char_height = 0 self.char_width = 0 self.platten = None self.paper = None self.mode = None self.fade_buffer = None self.screen_size = None self.cursor = Vector2(200, -70) self.document = list() self.document.append(list()) self.current_line = 0 font_name = 'Apple ][.ttf' font_size = 8 ratio = 10 color = pygame.Color('goldenrod') self.text = [ ('display', '> '), ('wait', 1500), ('type', 'CD/HACK'), ('display', '\nHACK> '), ('type', '\nRUN HACK.BAS'), ('wait', 1000), ('type', '\nAT&F&D2&C1S0=0X4'), ('wait', 1500), ('display', '\nOK'), ('wait', 1000), ('type', '\nATDT0040745129711\n'), ('sound', 'modem'), ('wait', 18000), ('display', '\nCONNECT 14400') ] self.sounds = { 'run': load_sound('run.wav'), 'boot': load_sound('boot.wav'), 'beep': load_sound('beep.wav'), 'modem': load_sound('188828__0ktober__modem-dial.wav'), 'spacebar': [load_sound(i) for i in [ 'spacebar01.wav', 'spacebar02.wav']], 'key': [load_sound(i) for i in [ 'keypress01.wav', 'keypress02.wav', 'keypress04.wav', 'keypress05.wav', 'keypress06.wav', ]] } self.generate_font(font_name, font_size, ratio, color) self.set_tab(0) def next_command(self): try: cmd, text = self.text.pop(0) except IndexError: self.fade_out() return if cmd == 'display': self.display(text) elif cmd == 'type': self.buffer = list(text) self.next_press() elif cmd == 'sound': self.sounds[text].play() self.next_command() elif cmd == 'wait': task = Task(self.next_command, text) self._animations.add(task) def next_press(self): try: self.press(self.buffer.pop(0)) except IndexError: self.next_command() else: if random.randint(0, 20): task = Task(self.next_press, interval=random.randint(200, 400)) else: task = Task(self.next_press, interval=random.randint(800, 1200)) self._animations.add(task) def fade_out(self): if self.fade_buffer is None: self.fade_buffer = pygame.Surface(self.screen_size) self.fade_buffer.fill(0) ani = self.animate(self.fade_buffer, set_alpha=255, initial=0, duration=3000) ani.schedule(partial(setattr, self, 'running', False), 'on finish') def display(self, text): for char in text: self.strike(char, True) task = Task(self.next_command, interval=random.randint(600, 800)) self._animations.add(task) def generate_font(self, font_name, font_size, ratio, color): self.cache = dict() padding = 8 padding2 = padding * 2 font = pygame.font.Font(get_font_asset(font_name), font_size) glyph = font.render('W', 1, (0, 0, 0)) natural_size = glyph.get_size() scratch = natural_size[0] + padding2, natural_size[1] + padding2 full_size = scratch[0] * ratio, scratch[1] * ratio # generate a scanline image to create scanline effect scanline = pygame.Surface(full_size, pygame.SRCALPHA) scolor = (64, 64, 64) for y in range(0, full_size[1], 4): pygame.draw.line(scanline, scolor, (0, y), (full_size[0], y)) pygame.draw.line(scanline, scolor, (0, y + 1), (full_size[0], y + 1)) for char in self.charset: original = font.render(char, 1, color) lined = pygame.Surface(natural_size, pygame.SRCALPHA) lined.blit(original, (0, 0)) lined.blit(scanline, (0, 0)) glyph = pygame.Surface(scratch, pygame.SRCALPHA) glyph.blit(original, (padding, padding)) large_glyph = smoothscale(glyph, full_size) # norml_glyph.blit(scanline, (0, 0)) bloom = smoothscale(glyph, (10, int(scratch[1] * .80))) bloom = smoothscale(bloom, full_size) image = pygame.Surface(full_size, pygame.SRCALPHA) image.blit(bloom, (0, 0)) image.blit(large_glyph, (0, 0)) image.blit(scanline, (0, 0), None, pygame.BLEND_SUB) self.cache[char] = image self.char_width = int(full_size[0] * .3) self.char_height = int(full_size[1] * .35) page_width = self.char_width * self.cpl self.platten = pygame.Rect(0, self.cursor.y, page_width, 100) self.paper = pygame.Rect(0, self.cursor.y, page_width, 1000) def initialize(self, context): pass @staticmethod def new_sprite(image, rect): sprite = Sprite() sprite.image = image sprite.rect = rect return sprite def animate(self, *args, **kwargs): ani = Animation(*args, **kwargs) self._animations.add(ani) return ani def add_sprite(self, image, rect, layer=None): self._sprites.add(self.new_sprite(image, rect), layer=ternone(layer, self._default_layer)) def run(self, context): flip = pygame.display.flip update = self.update draw = self.draw handle_events = self.handle_event screen = pygame.display.get_surface() clock = time.time frame_time = (1 / 60.) * 1000 last_draw = 0 times = deque(maxlen=10) self.sounds['boot'].play() self.sounds['run'].play(-1, fade_ms=200) task = Task(self.next_command, 2500) self._animations.add(task) self.screen_size = screen.get_size() self.running = True last_frame = clock() while self.running: dt = (clock() - last_frame) * 1000 last_frame = clock() times.append(dt) dt = sum(times) / 10 last_draw += dt handle_events() update(dt) if last_draw >= frame_time: draw(screen) if self.fade_buffer: screen.blit(self.fade_buffer, (0, 0)) flip() last_draw = 0 def draw(self, surface): self._sprites.draw(surface) surface.fill((0, 0, 0)) self.paper.left = self.platten.left for line_index, line in enumerate(self.document): for position, glyph in line: gx, gy = position x = gx y = gy + (line_index * self.char_height) surface.blit(glyph, self.paper.move(x, y)) def update(self, dt): self._animations.update(dt) def handle_event(self): for event in pygame.event.get(): if event.type == KEYDOWN: if event.key == K_SPACE: self.fade_out() if event.type == QUIT: # this will allow pressing the windows (X) to close the game sys.exit(0) def strike(self, char, now=False): self.paper.left = self.platten.left if char == ' ': self.advance_one(now) return elif char == '\n': self.cr() return try: glyph = self.cache[char] position = [int(self.cursor.x - self.paper.left), 10] self.document[self.current_line].append((position, glyph)) self.advance_one(now) return glyph except KeyError: pass def advance_one(self, now=False): if now: self.platten.left -= self.char_width else: remove_animations_of(self.platten, self._animations) ani = Animation(left=-self.char_width, relative=True, duration=self.platten_speed) ani.start(self.platten) self._animations.add(ani) def press(self, char, sound=80): if char in self.charset: if sound: random.choice(self.sounds['key']).play() task = Task(partial(self.strike, char), sound) elif char == ' ': if sound: random.choice(self.sounds['spacebar']).play() task = Task(self.advance_one, sound) elif char == '\n': if sound: random.choice(self.sounds['key']).play() task = Task(self.cr, sound) else: raise ValueError(char) # don't show character right away b/c sound lag self._animations.add(task) def release(self, key): """ :param key: :return: """ if key in self.pressed: self.pressed.remove(key) self.advance_one() def bs(self): """ Backspace :return: """ self.mode = 1 remove_animations_of(self.platten, self._animations) ani = Animation(left=self.char_width, relative=True, duration=self.platten_speed) ani.start(self.platten) self._animations.add(ani) def cr(self): """ Carriage return :return: """ self.current_line += 1 self.document.append(list()) self.set_tab(0) def set_tab(self, tab=0): self.platten.left = tab remove_animations_of(self.platten, self._animations) ani = Animation(left=0, duration=self.platten_speed) ani.start(self.platten) self._animations.add(ani)
class GraphView(Minigame): GAME_NAME = "GraphView" def __init__(self, graph_yaml=None, graph_tmx=None): self.visitor = None self.scroll_group = None self.graph_yaml = graph_yaml self.graph_tmx = graph_tmx self.visitor_cursor = None self.vertex_group = VertexLookupGroup() self.hud_group = None self.hud_button = None self.pointer = None self.sprites = LayeredUpdates() self._animations = Group() def animate(self, *args, **kwargs): ani = Animation(*args, **kwargs) self._animations.add(ani) return ani def initialize(self, context): screen = pygame.display.get_surface() adventure_graph = build_graph_from_yaml_data( load_yaml_data(get_data_asset(self.graph_yaml))) self.visitor = Visitor.visit_graph(adventure_graph, context) tmx_data = load_pygame(resources.get_map_asset(self.graph_tmx)) map_data = pyscroll.TiledMapData(tmx_data) map_layer_size = screen.get_width(), int(screen.get_height() * .80) map_layer_rect = Rect((0, 0), map_layer_size) map_layer = pyscroll.BufferedRenderer(map_data, map_layer_size) self.scroll_group = PyscrollGroup(map_layer=map_layer) self.pointer = PointerSprite(self.vertex_group, self.scroll_group) # self.pointer.selected_vertex_id = "START" self.sprites.add(self.pointer, layer=100) sw, sh = screen.get_size() hud_rect = Rect(20, sh * .76, sw * .80, sh * .2) border_image = load_image('border-default.png').convert_alpha() self.hud_group = HUDGroup(hud_rect, border_image) info = VertexInfoSprite(self.visitor) info.rect = Rect(12, 12, hud_rect.width - 250, hud_rect.height - 24) self.hud_group.add(info) self.hud_group.open() self.hud_button = HUDButton(self.hud_group, 850, 70) self.hud_group.add(self.hud_button) edges = list() for vertex in self.visitor.graph.vertex_index.values(): vertex_sprite = VertexSprite(vertex) self.vertex_group.add(vertex_sprite) self.scroll_group.add(vertex_sprite) for edge in vertex.edges: edges.append(edge) edge_sprites = dict() for edge in edges: key = [edge.from_vertex.vertex_id, edge.to_vertex.vertex_id] key.sort() key = tuple(key) if key not in edge_sprites: edge_sprite = EdgeSprite(edge, self.scroll_group) from_vertex_sprite = self.vertex_group[ edge.from_vertex.vertex_id] to_vertex_sprite = self.vertex_group[edge.to_vertex.vertex_id] from_vertex_sprite.edge_sprites.append(edge_sprite) to_vertex_sprite.edge_sprites.append(edge_sprite) edge_sprites[key] = edge_sprite self.visitor_cursor = VisitorCursor(self.visitor, self.pointer, self.vertex_group, self.scroll_group) if context.get('show_clippie', False): c = Clippie(self.sprites, self._animations, context) c.rect.topleft = 1100, 550 self.sprites.add(c) self.visitor_cursor.clippie = c clock = pygame.time.Clock() pygame.display.flip() pygame.mouse.set_visible(False) while True: delta = clock.tick(60) events = pygame.event.get() self.hud_group.update(delta, events) for event in events: if event.type == pygame.QUIT: sys.exit(0) elif event.type == pygame.KEYDOWN or self.hud_button.handle_click: vertex_id = self.visitor_cursor.current_vertex_sprite.vertex_id if self.hud_button.handle_click or pygame.K_SPACE == event.key and vertex_id == self.pointer.selected_vertex_id: self.hud_button.handle_click = False if self.visitor.current_vertex.can_activate( self.visitor.context): activation_dict = self.visitor.activate_current_vertex( ) if activation_dict[ "command"] == "launch-mini-game": r = RunMinigameActivation( activation_dict["command"], activation_dict["activation-keyword-args"]) logger.debug( "Stating game: {} with arguments {}". format(r.mini_game_name, r.mini_game_keyword_args)) unhandled_actions = self.minigame_manager.run_minigame( r.mini_game_name, self.visitor.context, r.post_run_actions, **r.mini_game_keyword_args if r.mini_game_keyword_args is not None else {}) if self.has_exit_action(unhandled_actions): return else: vertex = self.visitor.current_vertex failing = vertex.activation_pre_requisites.get_failing_pre_requisites( self.visitor.context) self.visitor.context[ 'gamestate.dialog_text'] = failing[0].hint self.visitor_cursor.animations.add( Task(self.visitor_cursor.clear_hint, 5000)) self.scroll_group.update(delta, events) # self.hud_group.update(delta, events) self.sprites.update(delta, events) self._animations.update(delta) self._update_edge_colors() x_offset = ( (self.visitor_cursor.rect.x - self.scroll_group.view.x) - self.pointer.rect.x) / 2 self.scroll_group.center( (self.visitor_cursor.rect.x - x_offset, 0)) self.scroll_group.draw(screen, map_layer_rect) screen.fill((200, 200, 200), (0, sh * .75, 1280, 200)) self.hud_group.draw(screen) self.sprites.draw(screen) screen.blit(self.pointer.image, self.pointer.rect) pygame.display.flip() def has_exit_action(self, unhandle_actions): for u in unhandle_actions: if u.ACTION_NAME == ExitGameAction.ACTION_NAME: return True return False def run(self, context): pass def _update_edge_colors(self): for key, vertex_sprite in self.vertex_group.lookup.items(): for e in vertex_sprite.edge_sprites: if e.edge.can_traverse(self.visitor.context): e.color = pygame.Color("GREEN")
class PlatformerScene(Scene): """ Platformer Scene class. """ def __init__(self, game): super().__init__(game) self.player = None self.active = True self.fsm = None self.space = pymunk.Space() self.space.gravity = (0, 1000) self.sprites = LayeredUpdates() self.event_handler = event_handling.EventQueueHandler() self.event_handler.print_controls() self.background = resources.gfx("background.png", convert=True) self.load() pygame.mixer.music.load(resources.music_path("zirkus.ogg")) pygame.mixer.music.play(-1) def add_static(self, vertices, rect): """ Add static object to scene. :param vertices: :param rect: """ body = pymunk.Body(body_type=pymunk.Body.STATIC) body.position = rect.x, rect.y shape = pymunk.Poly(body, vertices) shape.friction = 1.0 shape.elasticity = 1.0 self.space.add(body, shape) def load(self): """ Load a scene in TMX format. """ def box_vertices(box_x, box_y, width, height): top_left = box_x, box_y top_right = box_x + width, box_y bottom_right = box_x + width, box_y + height bottom_left = box_x, box_y + height return top_left, top_right, bottom_right, bottom_left filename = path_join("data", "maps", "untitled.tmx") tmxdata = pytmx.util_pygame.load_pygame(filename) for obj in tmxdata.objects: if obj.type == MAP_FIXED: rect = Rect(obj.x, obj.y, obj.width, obj.height) vertices = box_vertices(0, 0, obj.width, obj.height) self.add_static(vertices, rect) elif obj.type == MAP_YARN_SPAWN: ball = sprite.Ball(Rect((obj.x, obj.y), (32, 32))) model = BasicModel() model.sprites = [ball] model.pymunk_objects = ball.pymunk_shapes self.add_model(model) self.player = model elif obj.type == MAP_PLAYER_SPAWN: self.player = unicyclecat.build(self.space, self.sprites) self.player.position = obj.x, obj.y self.fsm = SimpleFSM(CONTROL, "idle") def add_model(self, model): """ Add a model. :param model: Model to add. """ self.sprites.add(*model.sprites) self.space.add(model.pymunk_objects) def remove_model(self, model): """ Remove a model. :param model: Model to remove. """ self.sprites.remove(*model.sprites) self.space.remove(model.pymunk_objects) def render(self): """ Render scene to the screen surface. """ surface = self._game.screen surface.blit(self.background, (0, 0)) self.sprites.draw(surface) return [surface.get_rect()] def tick(self, time_delta): """ Tick the physics and game update loops. """ step_amount = (1 / 30.0) / 30 for _ in range(30): self.space.step(step_amount) self.sprites.update(time_delta=time_delta) def event(self, event): """ Process an event. :param event: The event to process """ events = self.event_handler.process_event(event) position = self.player.position for evt in events: try: cmd, arg = self.fsm((evt.button, evt.held)) except ValueError: continue if cmd == "move": resources.sfx("cat_wheel.ogg", False, True) resources.sfx("cat_wheel.ogg", True) self.player.accelerate(arg) if cmd == "idle": self.player.brake() elif cmd == "jump": resources.sfx("cat_jump.ogg", True) self.player.main_body.apply_impulse_at_world_point((0, -600), position)