source: nagslang/render.py @ 221:0c0d5919f70a

Last change on this file since 221:0c0d5919f70a was 221:0c0d5919f70a, checked in by Jeremy Thurgood <firxen@…>, 7 years ago

Fix embarrassing leftover underscore.

File size: 4.9 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    rotate = True  # Set to `False` to suppress image rotation.
47
48    def __init__(self, image):
49        self._image = image
50
51    def get_image(self):
52        return self._image
53
54    def rotate_image(self, image):
55        if not self.rotate:
56            return image
57        angle = self.game_object.get_render_angle() * 180 / math.pi
58        return pygame.transform.rotate(image, angle)
59
60    def render_image(self, surface, image):
61        image = self.rotate_image(image)
62        pos = self.game_object.get_render_position(surface)
63        surface.blit(image, image_pos(image, pos))
64
65    def render(self, surface):
66        self.render_image(surface, self.get_image())
67        super(ImageRenderer, self).render(surface)
68
69
70class ImageStateRenderer(ImageRenderer):
71    def __init__(self, state_images):
72        self._state_images = state_images
73
74    def get_image(self):
75        return self._state_images[self.game_object.puzzler.get_state()]
76
77
78class TimedAnimatedRenderer(ImageRenderer):
79    def __init__(self, images, frame_ticks=1):
80        self._images = images
81        self._frame_ticks = frame_ticks
82        self._frame_tick = 0
83        self._frame = 0
84
85    def advance_tick(self):
86        self._frame_tick += 1
87        if self._frame_tick > self._frame_ticks:
88            self._frame_tick = 0
89            self._frame += 1
90        if self._frame >= len(self._images):
91            self._frame = 0
92
93    def reset(self):
94        self._frame_tick = 0
95        self._frame = 0
96
97    def get_image(self):
98        return self._images[self._frame]
99
100    def animate(self):
101        self.advance_tick()
102
103
104class MovementAnimatedRenderer(TimedAnimatedRenderer):
105    def animate(self):
106        if self.game_object.is_moving:
107            self.advance_tick()
108        else:
109            self.reset()
110
111
112class RendererSelectionRenderer(Renderer):
113    def __init__(self, renderers):
114        self._renderers = renderers
115
116    def set_game_object(self, game_object):
117        self.game_object = game_object
118        for renderer in self._renderers.values():
119            renderer.set_game_object(game_object)
120
121    @property
122    def renderer(self):
123        return self._renderers[self.select_renderer()]
124
125    def render(self, surface):
126        return self.renderer.render(surface)
127
128    def animate(self):
129        return self.renderer.animate()
130
131    def select_renderer(self):
132        raise NotImplementedError()
133
134
135class FacingSelectionRenderer(RendererSelectionRenderer):
136    def __init__(self, renderers):
137        for renderer in renderers.values():
138            renderer.rotate = False
139        super(FacingSelectionRenderer, self).__init__(renderers)
140        self._face = 'left'
141
142    def _update_facing(self, angle):
143        if abs(angle) < math.pi / 2:
144            self._face = 'right'
145        elif abs(angle) > math.pi / 2:
146            self._face = 'left'
147
148    def select_renderer(self):
149        angle = self.game_object.get_render_angle()
150        self._update_facing(angle)
151        return self._face
152
153
154class ShapeRenderer(Renderer):
155    def render(self, surface):
156        self._render_shape(surface)
157        super(ShapeRenderer, self).render(surface)
158
159
160class ShapeStateRenderer(ShapeRenderer):
161    """Renders the shape in a different colour depending on the state.
162
163    Requires the game object it's attached to to have a puzzler.
164    """
165    def render(self, surface):
166        if self.game_object.puzzler.get_state():
167            color = pygame.color.THECOLORS['green']
168        else:
169            color = pygame.color.THECOLORS['red']
170
171        self.game_object.get_shape().color = color
172        super(ShapeStateRenderer, self).render(surface)
Note: See TracBrowser for help on using the repository browser.