Mercurial > nagslang
view nagslang/game_object.py @ 106:bce9cd8a4a8c
FloorLight, linked to a FloorSwitch.
author | Jeremy Thurgood <firxen@gmail.com> |
---|---|
date | Mon, 02 Sep 2013 13:48:24 +0200 |
parents | 1be3eebb87c4 |
children | b90d01e4d9d4 |
line wrap: on
line source
import math import pygame import pymunk import pymunk.pygame_util from nagslang.constants import SWITCH_PUSHERS, COLLISION_TYPE_SWITCH from nagslang.options import options class PuzzleGlue(object): """Glue that holds bits of a puzzle together. """ def __init__(self): self._components = {} def add_component(self, name, puzzler): self._components[name] = puzzler puzzler.set_glue(self) def get_state_of(self, name): return self._components[name].get_state() class Puzzler(object): """Behaviour specific to a puzzle component. """ def set_glue(self, glue): self.glue = glue def get_state(self): raise NotImplementedError() class FloorSwitchPuzzler(Puzzler): def __init__(self, space, shape): self._space = space self._shape = shape def get_state(self): for shape in self._space.shape_query(self._shape): if shape.collision_type in SWITCH_PUSHERS: return True return False class StateProxyPuzzler(Puzzler): def __init__(self, state_source): self._state_source = state_source def get_state(self): return self.glue.get_state_of(self._state_source) class Physicser(object): def __init__(self, space): self.space = space def add_to_space(self): raise NotImplementedError() def remove_from_space(self): raise NotImplementedError() def get_render_position(self, surface): raise NotImplementedError() def get_angle(self): raise NotImplementedError() def apply_impulse(self, j, r=(0, 0)): raise NotImplementedError() class SingleShapePhysicser(Physicser): def __init__(self, space, shape): super(SingleShapePhysicser, self).__init__(space) self._shape = shape def add_to_space(self): self.space.add(self._shape) if not self._shape.body.is_static: self.space.add(self._shape.body) def remove_from_space(self): self.space.remove(self._shape) if not self._shape.body.is_static: self.space.remove(self._shape.body) def get_render_position(self, surface): pos = self._shape.body.position return pymunk.pygame_util.to_pygame(pos, surface) def get_angle(self): return self._shape.body.angle def apply_impulse(self, j, r=(0, 0)): return self._shape.body.apply_impulse(j, r) class Renderer(object): def __init__(self, shape): self._shape = shape def _render_shape(self, surface, pos, angle): # Less general that pymunk.pygame_util.draw, but also a lot less noisy. color = getattr( self._shape, 'color', pygame.color.THECOLORS['lightblue']) # We only explicitly draw Circle and Poly shapes. Everything else we # forward to pymunk. if isinstance(self._shape, pymunk.Circle): centre = pymunk.pygame_util.to_pygame( self._shape.body.position, surface) radius = int(self._shape.radius) pygame.draw.circle(surface, color, centre, radius, 2) elif isinstance(self._shape, pymunk.Poly): # polygon bounding box points = [pymunk.pygame_util.to_pygame(p, surface) for p in self._shape.get_vertices()] pygame.draw.lines(surface, color, True, points, 2) else: pymunk.pygame_util.draw(surface, self._shape) def render(self, surface, pos, angle): if options.debug: self._render_shape(surface, pos, angle) def image_pos(image, pos): return (pos[0] - image.get_width() / 2, pos[1] - image.get_height() / 2) class ImageRenderer(Renderer): def __init__(self, shape, image): super(ImageRenderer, self).__init__(shape) self._image = image def render(self, surface, pos, angle): surface.blit(self._image, image_pos(self._image, pos)) super(ImageRenderer, self).render(surface, pos, angle) class FacingImageRenderer(Renderer): def __init__(self, shape, left_image, right_image): super(FacingImageRenderer, self).__init__(shape) self._images = { 'left': left_image, 'right': right_image, } def get_image(self, angle): if abs(angle) < math.pi / 2: return self._images['right'] return self._images['left'] def render(self, surface, pos, angle): image = self.get_image(angle) surface.blit(image, image_pos(image, pos)) super(FacingImageRenderer, self).render(surface, pos, angle) class ShapeRenderer(Renderer): def render(self, surface, pos, angle): self._render_shape(surface, pos, angle) super(ShapeRenderer, self).render(surface, pos, angle) class GameObject(object): """A representation of a thing in the game world. This has a rendery thing, physicsy things and maybe some other things. """ def __init__(self, physicser, renderer, puzzler=None): self.physicser = physicser self.physicser.add_to_space() self.renderer = renderer self.puzzler = puzzler def get_render_position(self, surface): return self.physicser.get_render_position(surface) def get_render_angle(self): return self.physicser.get_angle() def render(self, surface): return self.renderer.render( surface, self.get_render_position(surface), self.get_render_angle()) class FloorSwitch(GameObject): def __init__(self, space, position): body = pymunk.Body() body.position = position self.shape = pymunk.Circle(body, 30) self.shape.collision_type = COLLISION_TYPE_SWITCH self.shape.sensor = True super(FloorSwitch, self).__init__( SingleShapePhysicser(space, self.shape), ShapeRenderer(self.shape), FloorSwitchPuzzler(space, self.shape), ) def render(self, surface): if self.puzzler.get_state(): self.shape.color = pygame.color.THECOLORS['green'] else: self.shape.color = pygame.color.THECOLORS['red'] super(FloorSwitch, self).render(surface) class FloorLight(GameObject): def __init__(self, space, position, state_source): body = pymunk.Body() body.position = position self.shape = pymunk.Circle(body, 10) self.shape.collision_type = COLLISION_TYPE_SWITCH self.shape.sensor = True super(FloorLight, self).__init__( SingleShapePhysicser(space, self.shape), ShapeRenderer(self.shape), StateProxyPuzzler(state_source), ) def render(self, surface): if self.puzzler.get_state(): self.shape.color = pygame.color.THECOLORS['green'] else: self.shape.color = pygame.color.THECOLORS['red'] super(FloorLight, self).render(surface)