source: nagslang/render.py@ 362:d0aeb893967d

Last change on this file since 362:d0aeb893967d was 362:d0aeb893967d, checked in by Neil Muller <drnlmuller@…>, 8 years ago

Transparent moonlight

File size: 6.6 KB
Line 
1import math
2
3import pygame
4import pygame.locals as pgl
5import pymunk
6
7from nagslang.options import options
8from nagslang.utils import tile_surface
9from nagslang.widgets.text import LabelWidget
10
11
12class Renderer(object):
13 def set_game_object(self, game_object):
14 self.game_object = game_object
15
16 def _render_shape(self, surface):
17 shape = self.game_object.get_shape()
18 # Less general that pymunk.pygame_util.draw, but also a lot less noisy.
19 color = getattr(shape, 'color', pygame.color.THECOLORS['lightblue'])
20 # We only explicitly draw Circle and Poly shapes. Everything else we
21 # forward to pymunk.
22 if isinstance(shape, pymunk.Circle):
23 centre = pymunk.pygame_util.to_pygame(shape.body.position, surface)
24 radius = int(shape.radius)
25 pygame.draw.circle(surface, color, centre, radius, 2)
26 elif isinstance(shape, pymunk.Poly):
27 # polygon bounding box
28 points = [pymunk.pygame_util.to_pygame(p, surface)
29 for p in shape.get_vertices()]
30 pygame.draw.lines(surface, color, True, points, 2)
31 else:
32 pymunk.pygame_util.draw(surface, shape)
33
34 def render(self, surface):
35 if options.debug:
36 self._render_shape(surface)
37
38 def update(self, seconds):
39 # Used by time animatations to advance the clock
40 pass
41
42
43class NullRenderer(Renderer):
44 def render(self, surface):
45 pass
46
47
48def image_pos(image, pos):
49 return (pos[0] - image.get_width() / 2,
50 pos[1] - image.get_height() / 2)
51
52
53class ImageRenderer(Renderer):
54 def __init__(self, image):
55 self._image = image
56
57 def get_image(self):
58 return self._image
59
60 def rotate_image(self, image):
61 angle = self.game_object.get_render_angle() * 180 / math.pi
62 return pygame.transform.rotate(image, angle)
63
64 def render_image(self, surface, image):
65 image = self.rotate_image(image)
66 pos = self.game_object.get_render_position(surface)
67 surface.blit(image, image_pos(image, pos))
68
69 def render(self, surface):
70 self.render_image(surface, self.get_image())
71 super(ImageRenderer, self).render(surface)
72
73
74class ImageStateRenderer(ImageRenderer):
75 def __init__(self, state_images):
76 self._state_images = state_images
77
78 def get_image(self):
79 return self._state_images[self.game_object.puzzler.get_state()]
80
81
82class TimedAnimatedRenderer(ImageRenderer):
83 def __init__(self, images, frame_ticks=1):
84 self._images = images
85 self._frame_ticks = frame_ticks
86 self._frame_tick = 0
87 self._frame = 0
88
89 def advance_tick(self):
90 self._frame_tick += 1
91 if self._frame_tick > self._frame_ticks:
92 self._frame_tick = 0
93 self._frame += 1
94 if self._frame >= len(self._images):
95 self._frame = 0
96
97 def reset(self):
98 self._frame_tick = 0
99 self._frame = 0
100
101 def get_image(self):
102 return self._images[self._frame]
103
104 def update(self, seconds):
105 self.advance_tick()
106
107
108class MovementAnimatedRenderer(TimedAnimatedRenderer):
109 def update(self, seconds):
110 if self.game_object.is_moving:
111 self.advance_tick()
112 else:
113 self.reset()
114
115
116class RendererSelectionRenderer(Renderer):
117 def __init__(self, renderers):
118 self._renderers = renderers
119
120 def set_game_object(self, game_object):
121 self.game_object = game_object
122 for renderer in self._renderers.values():
123 renderer.set_game_object(game_object)
124
125 @property
126 def renderer(self):
127 return self._renderers[self.select_renderer()]
128
129 def render(self, surface):
130 return self.renderer.render(surface)
131
132 def update(self, seconds):
133 return self.renderer.update(seconds)
134
135 def select_renderer(self):
136 raise NotImplementedError()
137
138
139class FacingSelectionRenderer(RendererSelectionRenderer):
140 def select_renderer(self):
141 return self.game_object.get_facing_direction()
142
143
144class ShapeRenderer(Renderer):
145 def render(self, surface):
146 self._render_shape(surface)
147 super(ShapeRenderer, self).render(surface)
148
149
150class ShapeStateRenderer(ShapeRenderer):
151 """Renders the shape in a different colour depending on the state.
152
153 Requires the game object it's attached to to have a puzzler.
154 """
155 def render(self, surface):
156 if self.game_object.puzzler.get_state():
157 color = pygame.color.THECOLORS['green']
158 else:
159 color = pygame.color.THECOLORS['red']
160
161 self.game_object.get_shape().color = color
162 super(ShapeStateRenderer, self).render(surface)
163
164
165class Overlay(object):
166 def set_game_object(self, game_object):
167 self.game_object = game_object
168
169 def render(self, surface, display_offset):
170 pass
171
172 def is_visible(self):
173 return self.game_object.puzzler.get_state()
174
175
176class TextOverlay(Overlay):
177 def __init__(self, text):
178 self.text = text
179 self.widget = LabelWidget((20, 20), self.text)
180
181 def render(self, surface, display_offset):
182 x, y = 20, 20
183 if display_offset[0] < 0:
184 x += abs(display_offset[0])
185 if display_offset[1] < 0:
186 y += abs(display_offset[1])
187 self.widget.rect.topleft = (x, y)
188 self.widget.draw(surface)
189
190
191class TiledRenderer(Renderer):
192 """Tile the given image to fit the given outline
193
194 Outline is assumed to be in pymunk coordinates"""
195
196 def __init__(self, outline, tile_image, alpha=255):
197 self._tile_image = tile_image
198 self.outline = outline
199 self._tiled = None
200 self._offset = None
201 self._alpha = alpha
202
203 def _make_surface(self, surface):
204 if not self._tiled:
205 size = surface.get_size()
206 mask = pygame.surface.Surface(size, pgl.SRCALPHA)
207 mask.fill(pygame.color.Color(0, 0, 0, 0))
208 pointlist = [pymunk.pygame_util.to_pygame(p, surface)
209 for p in self.outline]
210 rect = pygame.draw.polygon(mask,
211 pygame.color.Color(
212 255, 255, 255, self._alpha),
213 pointlist, 0)
214 self._offset = (rect.x, rect.y)
215 self._tiled = tile_surface((rect.w, rect.h), self._tile_image)
216 self._tiled.blit(mask, (0, 0), rect,
217 special_flags=pgl.BLEND_RGBA_MULT)
218
219 def render(self, surface):
220 self._make_surface(surface)
221 surface.blit(self._tiled, self._offset)
222 super(TiledRenderer, self).render(surface)
Note: See TracBrowser for help on using the repository browser.