Mercurial > nagslang
changeset 207:42e8993c31fd
Break out Renderers
author | Stefano Rivera <stefano@rivera.za.net> |
---|---|
date | Tue, 03 Sep 2013 23:33:44 +0200 |
parents | 42c565c5ce76 |
children | 3d54fe7a2998 |
files | nagslang/enemies.py nagslang/game_object.py nagslang/protagonist.py nagslang/render.py |
diffstat | 4 files changed, 178 insertions(+), 175 deletions(-) [+] |
line wrap: on
line diff
--- a/nagslang/enemies.py Tue Sep 03 23:32:46 2013 +0200 +++ b/nagslang/enemies.py Tue Sep 03 23:33:44 2013 +0200 @@ -1,9 +1,9 @@ import pymunk import pymunk.pygame_util +from nagslang import render from nagslang.constants import COLLISION_TYPE_ENEMY, ZORDER_MID -from nagslang.game_object import ( - GameObject, SingleShapePhysicser, AnimatedFacingImageRenderer, make_body) +from nagslang.game_object import GameObject, SingleShapePhysicser, make_body from nagslang.mutators import FLIP_H from nagslang.resources import resources @@ -54,7 +54,7 @@ self.angle = 0 def _setup_renderer(self): - self.renderer = AnimatedFacingImageRenderer( + self.renderer = render.AnimatedFacingImageRenderer( (self._get_image('alien_A_1.png'), self._get_image('alien_A_1.png'), self._get_image('alien_A_1.png'),
--- a/nagslang/game_object.py Tue Sep 03 23:32:46 2013 +0200 +++ b/nagslang/game_object.py Tue Sep 03 23:33:44 2013 +0200 @@ -1,14 +1,11 @@ -import math - -import pygame import pymunk import pymunk.pygame_util from nagslang import puzzle +from nagslang import render from nagslang.constants import ( SWITCH_PUSHERS, COLLISION_TYPE_SWITCH, COLLISION_TYPE_BOX, ZORDER_LOW, ZORDER_FLOOR, COLLISION_TYPE_DOOR) -from nagslang.options import options from nagslang.resources import resources from nagslang.events import DoorEvent from nagslang.widgets.text import LabelWidget @@ -79,163 +76,6 @@ return self._shape.body.apply_impulse(j, r) -class Renderer(object): - def set_game_object(self, game_object): - self.game_object = game_object - - def _render_shape(self, surface): - shape = self.game_object.get_shape() - # Less general that pymunk.pygame_util.draw, but also a lot less noisy. - color = getattr(shape, 'color', pygame.color.THECOLORS['lightblue']) - # We only explicitly draw Circle and Poly shapes. Everything else we - # forward to pymunk. - if isinstance(shape, pymunk.Circle): - centre = pymunk.pygame_util.to_pygame(shape.body.position, surface) - radius = int(shape.radius) - pygame.draw.circle(surface, color, centre, radius, 2) - elif isinstance(shape, pymunk.Poly): - # polygon bounding box - points = [pymunk.pygame_util.to_pygame(p, surface) - for p in shape.get_vertices()] - pygame.draw.lines(surface, color, True, points, 2) - else: - pymunk.pygame_util.draw(surface, shape) - - def render(self, surface): - if options.debug: - self._render_shape(surface) - - def animate(self): - # Used by time animatations to advance the clock - pass - - -def image_pos(image, pos): - return (pos[0] - image.get_width() / 2, - pos[1] - image.get_height() / 2) - - -class ImageRenderer(Renderer): - def __init__(self, image): - self._image = image - - def get_image(self): - return self._image - - def rotate_image(self, image): - angle = self.game_object.get_render_angle() * 180 / math.pi - return pygame.transform.rotate(image, angle) - - def render_image(self, surface, image): - image = self.rotate_image(image) - pos = self.game_object.get_render_position(surface) - surface.blit(image, image_pos(image, pos)) - - def render(self, surface): - self.render_image(surface, self.get_image()) - super(ImageRenderer, self).render(surface) - - -class ImageStateRenderer(ImageRenderer): - def __init__(self, state_images): - self._state_images = state_images - - def get_image(self): - return self._state_images[self.game_object.puzzler.get_state()] - - -class FacingImageRenderer(ImageRenderer): - def __init__(self, left_image, right_image): - self._images = { - 'left': left_image, - 'right': right_image, - } - self._face = 'left' - - def _update_facing(self, angle): - if abs(angle) < math.pi / 2: - self._face = 'right' - elif abs(angle) > math.pi / 2: - self._face = 'left' - - def rotate_image(self, image): - # Facing images don't get rotated. - return image - - def get_facing_image(self): - return self._images[self._face] - - def get_image(self): - angle = self.game_object.get_render_angle() - self._update_facing(angle) - return self.get_facing_image() - - -class AnimatedFacingImageRenderer(FacingImageRenderer): - def __init__(self, left_images, right_images): - self._images = { - 'left': left_images, - 'right': right_images, - } - self._frame = 0 - self._moving = False - self._face = 'left' - - def get_facing_image(self): - if self._frame >= len(self._images[self._face]): - self._frame = 0 - return self._images[self._face][self._frame] - - def animate(self): - if self._moving: - self._frame += 1 - else: - self._frame = 0 - - def start(self): - self._moving = True - - def stop(self): - self._moving = False - - -class TimedAnimatedRenderer(ImageRenderer): - - def __init__(self, images): - self._images = images - self._frame = 0 - self._image = None - - def get_image(self): - if self._frame > len(self._imaages): - self._frame = 0 - return self._images[self._frame] - - def animate(self): - self._frame += 1 - - -class ShapeRenderer(Renderer): - def render(self, surface): - self._render_shape(surface) - super(ShapeRenderer, self).render(surface) - - -class ShapeStateRenderer(ShapeRenderer): - """Renders the shape in a different colour depending on the state. - - Requires the game object it's attached to to have a puzzler. - """ - def render(self, surface): - if self.game_object.puzzler.get_state(): - color = pygame.color.THECOLORS['green'] - else: - color = pygame.color.THECOLORS['red'] - - self.game_object.get_shape().color = color - super(ShapeStateRenderer, self).render(surface) - - def damping_velocity_func(body, gravity, damping, dt): """Apply custom damping to this body's velocity. """ @@ -330,7 +170,7 @@ self.shape.sensor = True super(FloorSwitch, self).__init__( SingleShapePhysicser(space, self.shape), - ImageStateRenderer({ + render.ImageStateRenderer({ True: resources.get_image('objects', 'sensor_on.png'), False: resources.get_image('objects', 'sensor_off.png'), }), @@ -347,7 +187,7 @@ self.shape.sensor = True super(Note, self).__init__( SingleShapePhysicser(space, self.shape), - ImageRenderer(resources.get_image('objects', 'note.png')), + render.ImageRenderer(resources.get_image('objects', 'note.png')), puzzle.CollidePuzzler(), TextOverlay(message), ) @@ -363,7 +203,7 @@ self.shape.sensor = True super(FloorLight, self).__init__( SingleShapePhysicser(space, self.shape), - ImageStateRenderer({ + render.ImageStateRenderer({ True: resources.get_image('objects', 'light_on.png'), False: resources.get_image('objects', 'light_off.png'), }), @@ -379,7 +219,7 @@ self.shape.collision_type = COLLISION_TYPE_BOX super(Box, self).__init__( SingleShapePhysicser(space, self.shape), - ImageRenderer(resources.get_image('objects', 'crate.png')), + render.ImageRenderer(resources.get_image('objects', 'crate.png')), ) @@ -400,7 +240,7 @@ puzzler = puzzle.StateProxyPuzzler(key_state) super(Door, self).__init__( SingleShapePhysicser(space, self.shape), - ImageRenderer(resources.get_image('objects', 'door.png')), + render.ImageRenderer(resources.get_image('objects', 'door.png')), puzzler, )
--- a/nagslang/protagonist.py Tue Sep 03 23:32:46 2013 +0200 +++ b/nagslang/protagonist.py Tue Sep 03 23:33:44 2013 +0200 @@ -3,9 +3,9 @@ import math +from nagslang import render from nagslang.constants import COLLISION_TYPE_PLAYER, ZORDER_MID -from nagslang.game_object import ( - GameObject, SingleShapePhysicser, AnimatedFacingImageRenderer, make_body) +from nagslang.game_object import GameObject, SingleShapePhysicser, make_body from nagslang.mutators import FLIP_H from nagslang.resources import resources @@ -55,7 +55,7 @@ def _setup_renderers(self): self._renderers = { - self.HUMAN_FORM: AnimatedFacingImageRenderer( + self.HUMAN_FORM: render.AnimatedFacingImageRenderer( (self._get_image('human_1.png'), self._get_image('human_1.png'), self._get_image('human_1.png'), @@ -68,7 +68,7 @@ self._get_image('human_2.png', FLIP_H), self._get_image('human_2.png', FLIP_H), self._get_image('human_2.png', FLIP_H))), - self.HUMAN_FORM_BACK: AnimatedFacingImageRenderer( + self.HUMAN_FORM_BACK: render.AnimatedFacingImageRenderer( (self._get_image('human_back_1.png'), self._get_image('human_back_1.png'), self._get_image('human_back_1.png'), @@ -81,7 +81,7 @@ self._get_image('human_back_2.png', FLIP_H), self._get_image('human_back_2.png', FLIP_H), self._get_image('human_back_2.png', FLIP_H))), - self.WOLF_FORM: AnimatedFacingImageRenderer( + self.WOLF_FORM: render.AnimatedFacingImageRenderer( (self._get_image('werewolf_1.png'), self._get_image('werewolf_1.png'), self._get_image('werewolf_1.png'), @@ -94,7 +94,7 @@ self._get_image('werewolf_2.png', FLIP_H), self._get_image('werewolf_2.png', FLIP_H), self._get_image('werewolf_2.png', FLIP_H))), - self.WOLF_FORM_BACK: AnimatedFacingImageRenderer( + self.WOLF_FORM_BACK: render.AnimatedFacingImageRenderer( (self._get_image('werewolf_back_1.png'), self._get_image('werewolf_back_1.png'), self._get_image('werewolf_back_1.png'),
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nagslang/render.py Tue Sep 03 23:33:44 2013 +0200 @@ -0,0 +1,163 @@ +import math + +import pygame +import pymunk + +from nagslang.options import options + + +class Renderer(object): + def set_game_object(self, game_object): + self.game_object = game_object + + def _render_shape(self, surface): + shape = self.game_object.get_shape() + # Less general that pymunk.pygame_util.draw, but also a lot less noisy. + color = getattr(shape, 'color', pygame.color.THECOLORS['lightblue']) + # We only explicitly draw Circle and Poly shapes. Everything else we + # forward to pymunk. + if isinstance(shape, pymunk.Circle): + centre = pymunk.pygame_util.to_pygame(shape.body.position, surface) + radius = int(shape.radius) + pygame.draw.circle(surface, color, centre, radius, 2) + elif isinstance(shape, pymunk.Poly): + # polygon bounding box + points = [pymunk.pygame_util.to_pygame(p, surface) + for p in shape.get_vertices()] + pygame.draw.lines(surface, color, True, points, 2) + else: + pymunk.pygame_util.draw(surface, shape) + + def render(self, surface): + if options.debug: + self._render_shape(surface) + + def animate(self): + # Used by time animatations to advance the clock + pass + + +def image_pos(image, pos): + return (pos[0] - image.get_width() / 2, + pos[1] - image.get_height() / 2) + + +class ImageRenderer(Renderer): + def __init__(self, image): + self._image = image + + def get_image(self): + return self._image + + def rotate_image(self, image): + angle = self.game_object.get_render_angle() * 180 / math.pi + return pygame.transform.rotate(image, angle) + + def render_image(self, surface, image): + image = self.rotate_image(image) + pos = self.game_object.get_render_position(surface) + surface.blit(image, image_pos(image, pos)) + + def render(self, surface): + self.render_image(surface, self.get_image()) + super(ImageRenderer, self).render(surface) + + +class ImageStateRenderer(ImageRenderer): + def __init__(self, state_images): + self._state_images = state_images + + def get_image(self): + return self._state_images[self.game_object.puzzler.get_state()] + + +class FacingImageRenderer(ImageRenderer): + def __init__(self, left_image, right_image): + self._images = { + 'left': left_image, + 'right': right_image, + } + self._face = 'left' + + def _update_facing(self, angle): + if abs(angle) < math.pi / 2: + self._face = 'right' + elif abs(angle) > math.pi / 2: + self._face = 'left' + + def rotate_image(self, image): + # Facing images don't get rotated. + return image + + def get_facing_image(self): + return self._images[self._face] + + def get_image(self): + angle = self.game_object.get_render_angle() + self._update_facing(angle) + return self.get_facing_image() + + +class AnimatedFacingImageRenderer(FacingImageRenderer): + def __init__(self, left_images, right_images): + self._images = { + 'left': left_images, + 'right': right_images, + } + self._frame = 0 + self._moving = False + self._face = 'left' + + def get_facing_image(self): + if self._frame >= len(self._images[self._face]): + self._frame = 0 + return self._images[self._face][self._frame] + + def animate(self): + if self._moving: + self._frame += 1 + else: + self._frame = 0 + + def start(self): + self._moving = True + + def stop(self): + self._moving = False + + +class TimedAnimatedRenderer(ImageRenderer): + + def __init__(self, images): + self._images = images + self._frame = 0 + self._image = None + + def get_image(self): + if self._frame > len(self._imaages): + self._frame = 0 + return self._images[self._frame] + + def animate(self): + self._frame += 1 + + +class ShapeRenderer(Renderer): + def render(self, surface): + self._render_shape(surface) + super(ShapeRenderer, self).render(surface) + + +class ShapeStateRenderer(ShapeRenderer): + """Renders the shape in a different colour depending on the state. + + Requires the game object it's attached to to have a puzzler. + """ + def render(self, surface): + if self.game_object.puzzler.get_state(): + color = pygame.color.THECOLORS['green'] + else: + color = pygame.color.THECOLORS['red'] + + self.game_object.get_shape().color = color + super(ShapeStateRenderer, self).render(surface)