source: nagslang/render.py@ 222:cc5f2a5ac501

Last change on this file since 222:cc5f2a5ac501 was 222:cc5f2a5ac501, checked in by Stefano Rivera <stefano@…>, 8 years ago

Overlays belong in render

File size: 5.6 KB
RevLine 
[207]1import math
2
3import pygame
4import pymunk
5
6from nagslang.options import options
[222]7from nagslang.widgets.text import LabelWidget
[207]8
9
10class Renderer(object):
11 def set_game_object(self, game_object):
12 self.game_object = game_object
13
14 def _render_shape(self, surface):
15 shape = self.game_object.get_shape()
16 # Less general that pymunk.pygame_util.draw, but also a lot less noisy.
17 color = getattr(shape, 'color', pygame.color.THECOLORS['lightblue'])
18 # We only explicitly draw Circle and Poly shapes. Everything else we
19 # forward to pymunk.
20 if isinstance(shape, pymunk.Circle):
21 centre = pymunk.pygame_util.to_pygame(shape.body.position, surface)
22 radius = int(shape.radius)
23 pygame.draw.circle(surface, color, centre, radius, 2)
24 elif isinstance(shape, pymunk.Poly):
25 # polygon bounding box
26 points = [pymunk.pygame_util.to_pygame(p, surface)
27 for p in shape.get_vertices()]
28 pygame.draw.lines(surface, color, True, points, 2)
29 else:
30 pymunk.pygame_util.draw(surface, shape)
31
32 def render(self, surface):
33 if options.debug:
34 self._render_shape(surface)
35
36 def animate(self):
37 # Used by time animatations to advance the clock
38 pass
39
40
41def image_pos(image, pos):
42 return (pos[0] - image.get_width() / 2,
43 pos[1] - image.get_height() / 2)
44
45
46class ImageRenderer(Renderer):
[219]47 rotate = True # Set to `False` to suppress image rotation.
48
[207]49 def __init__(self, image):
50 self._image = image
51
52 def get_image(self):
53 return self._image
54
55 def rotate_image(self, image):
[221]56 if not self.rotate:
[219]57 return image
[207]58 angle = self.game_object.get_render_angle() * 180 / math.pi
59 return pygame.transform.rotate(image, angle)
60
61 def render_image(self, surface, image):
62 image = self.rotate_image(image)
63 pos = self.game_object.get_render_position(surface)
64 surface.blit(image, image_pos(image, pos))
65
66 def render(self, surface):
67 self.render_image(surface, self.get_image())
68 super(ImageRenderer, self).render(surface)
69
70
71class ImageStateRenderer(ImageRenderer):
72 def __init__(self, state_images):
73 self._state_images = state_images
74
75 def get_image(self):
76 return self._state_images[self.game_object.puzzler.get_state()]
77
78
[217]79class TimedAnimatedRenderer(ImageRenderer):
80 def __init__(self, images, frame_ticks=1):
81 self._images = images
82 self._frame_ticks = frame_ticks
83 self._frame_tick = 0
84 self._frame = 0
85
86 def advance_tick(self):
87 self._frame_tick += 1
88 if self._frame_tick > self._frame_ticks:
89 self._frame_tick = 0
90 self._frame += 1
91 if self._frame >= len(self._images):
92 self._frame = 0
93
94 def reset(self):
95 self._frame_tick = 0
96 self._frame = 0
97
98 def get_image(self):
99 return self._images[self._frame]
100
101 def animate(self):
102 self.advance_tick()
103
104
105class MovementAnimatedRenderer(TimedAnimatedRenderer):
106 def animate(self):
[218]107 if self.game_object.is_moving:
[217]108 self.advance_tick()
109 else:
110 self.reset()
111
112
113class RendererSelectionRenderer(Renderer):
114 def __init__(self, renderers):
115 self._renderers = renderers
116
117 def set_game_object(self, game_object):
118 self.game_object = game_object
119 for renderer in self._renderers.values():
120 renderer.set_game_object(game_object)
121
122 @property
123 def renderer(self):
124 return self._renderers[self.select_renderer()]
125
126 def render(self, surface):
127 return self.renderer.render(surface)
128
129 def animate(self):
130 return self.renderer.animate()
131
132 def select_renderer(self):
133 raise NotImplementedError()
134
135
136class FacingSelectionRenderer(RendererSelectionRenderer):
137 def __init__(self, renderers):
138 for renderer in renderers.values():
[219]139 renderer.rotate = False
[217]140 super(FacingSelectionRenderer, self).__init__(renderers)
[207]141 self._face = 'left'
142
143 def _update_facing(self, angle):
144 if abs(angle) < math.pi / 2:
145 self._face = 'right'
146 elif abs(angle) > math.pi / 2:
147 self._face = 'left'
148
[217]149 def select_renderer(self):
[207]150 angle = self.game_object.get_render_angle()
151 self._update_facing(angle)
[217]152 return self._face
[207]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)
[222]174
175
176class Overlay(object):
177 def set_game_object(self, game_object):
178 self.game_object = game_object
179
180 def render(self, surface, display_offset):
181 pass
182
183 def is_visible(self):
184 return self.game_object.puzzler.get_state()
185
186
187class TextOverlay(Overlay):
188 def __init__(self, text):
189 self.text = text
190 self.widget = LabelWidget((20, 20), self.text)
191
192 def render(self, surface, display_offset):
193 x, y = 20, 20
194 if display_offset[0] < 0:
195 x += abs(display_offset[0])
196 if display_offset[1] < 0:
197 y += abs(display_offset[1])
198 self.widget.rect.topleft = (x, y)
199 self.widget.draw(surface)
Note: See TracBrowser for help on using the repository browser.