source: nagslang/render.py @ 218:9e2ef2f15035

Last change on this file since 218:9e2ef2f15035 was 218:9e2ef2f15035, checked in by Jeremy Thurgood <firxen@…>, 7 years ago

Better rendering and movement detection.

File size: 5.0 KB
Line 
1import math
2
3import pygame
4import pymunk
5
6from nagslang.options import options
7
8
9class Renderer(object):
10    def set_game_object(self, game_object):
11        self.game_object = game_object
12
13    def _render_shape(self, surface):
14        shape = self.game_object.get_shape()
15        # Less general that pymunk.pygame_util.draw, but also a lot less noisy.
16        color = getattr(shape, 'color', pygame.color.THECOLORS['lightblue'])
17        # We only explicitly draw Circle and Poly shapes. Everything else we
18        # forward to pymunk.
19        if isinstance(shape, pymunk.Circle):
20            centre = pymunk.pygame_util.to_pygame(shape.body.position, surface)
21            radius = int(shape.radius)
22            pygame.draw.circle(surface, color, centre, radius, 2)
23        elif isinstance(shape, pymunk.Poly):
24            # polygon bounding box
25            points = [pymunk.pygame_util.to_pygame(p, surface)
26                      for p in shape.get_vertices()]
27            pygame.draw.lines(surface, color, True, points, 2)
28        else:
29            pymunk.pygame_util.draw(surface, shape)
30
31    def render(self, surface):
32        if options.debug:
33            self._render_shape(surface)
34
35    def animate(self):
36        # Used by time animatations to advance the clock
37        pass
38
39
40def image_pos(image, pos):
41    return (pos[0] - image.get_width() / 2,
42            pos[1] - image.get_height() / 2)
43
44
45class ImageRenderer(Renderer):
46    def __init__(self, image):
47        self._image = image
48
49    def get_image(self):
50        return self._image
51
52    def rotate_image(self, image):
53        angle = self.game_object.get_render_angle() * 180 / math.pi
54        return pygame.transform.rotate(image, angle)
55
56    def render_image(self, surface, image):
57        image = self.rotate_image(image)
58        pos = self.game_object.get_render_position(surface)
59        surface.blit(image, image_pos(image, pos))
60
61    def render(self, surface):
62        self.render_image(surface, self.get_image())
63        super(ImageRenderer, self).render(surface)
64
65
66class ImageStateRenderer(ImageRenderer):
67    def __init__(self, state_images):
68        self._state_images = state_images
69
70    def get_image(self):
71        return self._state_images[self.game_object.puzzler.get_state()]
72
73
74class TimedAnimatedRenderer(ImageRenderer):
75    def __init__(self, images, frame_ticks=1):
76        self._images = images
77        self._frame_ticks = frame_ticks
78        self._frame_tick = 0
79        self._frame = 0
80
81    def advance_tick(self):
82        self._frame_tick += 1
83        if self._frame_tick > self._frame_ticks:
84            self._frame_tick = 0
85            self._frame += 1
86        if self._frame >= len(self._images):
87            self._frame = 0
88
89    def reset(self):
90        self._frame_tick = 0
91        self._frame = 0
92
93    def get_image(self):
94        return self._images[self._frame]
95
96    def animate(self):
97        self.advance_tick()
98
99
100class MovementAnimatedRenderer(TimedAnimatedRenderer):
101    def animate(self):
102        if self.game_object.is_moving:
103            self.advance_tick()
104        else:
105            self.reset()
106
107
108class RendererSelectionRenderer(Renderer):
109    def __init__(self, renderers):
110        self._renderers = renderers
111
112    def set_game_object(self, game_object):
113        self.game_object = game_object
114        for renderer in self._renderers.values():
115            renderer.set_game_object(game_object)
116
117    @property
118    def renderer(self):
119        return self._renderers[self.select_renderer()]
120
121    def render(self, surface):
122        return self.renderer.render(surface)
123
124    def animate(self):
125        return self.renderer.animate()
126
127    def select_renderer(self):
128        raise NotImplementedError()
129
130
131class FacingSelectionRenderer(RendererSelectionRenderer):
132    def __init__(self, renderers):
133        for renderer in renderers.values():
134            # TODO: Unhack this somehow.
135            renderer.rotate_image = self.rotate_image
136        super(FacingSelectionRenderer, self).__init__(renderers)
137        self._face = 'left'
138
139    def _update_facing(self, angle):
140        if abs(angle) < math.pi / 2:
141            self._face = 'right'
142        elif abs(angle) > math.pi / 2:
143            self._face = 'left'
144
145    def rotate_image(self, image):
146        # Facing images don't get rotated.
147        return image
148
149    def select_renderer(self):
150        angle = self.game_object.get_render_angle()
151        self._update_facing(angle)
152        return self._face
153
154
155class ShapeRenderer(Renderer):
156    def render(self, surface):
157        self._render_shape(surface)
158        super(ShapeRenderer, self).render(surface)
159
160
161class ShapeStateRenderer(ShapeRenderer):
162    """Renders the shape in a different colour depending on the state.
163
164    Requires the game object it's attached to to have a puzzler.
165    """
166    def render(self, surface):
167        if self.game_object.puzzler.get_state():
168            color = pygame.color.THECOLORS['green']
169        else:
170            color = pygame.color.THECOLORS['red']
171
172        self.game_object.get_shape().color = color
173        super(ShapeStateRenderer, self).render(surface)
Note: See TracBrowser for help on using the repository browser.