1 | import math
|
---|
2 |
|
---|
3 | import pygame
|
---|
4 | import pymunk
|
---|
5 |
|
---|
6 | from nagslang.constants import SWITCH_PUSHERS, COLLISION_TYPE_SWITCH
|
---|
7 |
|
---|
8 |
|
---|
9 | class Puzzler(object):
|
---|
10 | def get_state(self, space):
|
---|
11 | raise NotImplementedError()
|
---|
12 |
|
---|
13 | def notify(self):
|
---|
14 | pass
|
---|
15 |
|
---|
16 |
|
---|
17 | class FloorSwitchPuzzler(Puzzler):
|
---|
18 | def __init__(self, shape):
|
---|
19 | self.shape = shape
|
---|
20 |
|
---|
21 | def get_state(self, space):
|
---|
22 | for shape in space.shape_query(self.shape):
|
---|
23 | if shape.collision_type in SWITCH_PUSHERS:
|
---|
24 | return True
|
---|
25 | return False
|
---|
26 |
|
---|
27 |
|
---|
28 | class Physicser(object):
|
---|
29 | def add_to_space(self, space):
|
---|
30 | raise NotImplementedError()
|
---|
31 |
|
---|
32 | def remove_from_space(self, space):
|
---|
33 | raise NotImplementedError()
|
---|
34 |
|
---|
35 | def render_position(self, surface):
|
---|
36 | raise NotImplementedError()
|
---|
37 |
|
---|
38 | def render_angle(self):
|
---|
39 | raise NotImplementedError()
|
---|
40 |
|
---|
41 |
|
---|
42 | class NullPhysicser(Physicser):
|
---|
43 | def add_to_space(self, space):
|
---|
44 | pass
|
---|
45 |
|
---|
46 | def remove_from_space(self, space):
|
---|
47 | pass
|
---|
48 |
|
---|
49 | def render_position(self):
|
---|
50 | return (0, 0)
|
---|
51 |
|
---|
52 | def render_angle(self):
|
---|
53 | return 0
|
---|
54 |
|
---|
55 |
|
---|
56 | class SingleShapePhysicser(Physicser):
|
---|
57 | def __init__(self, shape):
|
---|
58 | self._shape = shape
|
---|
59 |
|
---|
60 | def add_to_space(self, space):
|
---|
61 | space.add(self._shape, self._shape.body)
|
---|
62 |
|
---|
63 | def remove_from_space(self, space):
|
---|
64 | space.remove(self._shape, self._shape.body)
|
---|
65 |
|
---|
66 | def render_position(self, surface):
|
---|
67 | pos = self._shape.body.position
|
---|
68 | import pymunk.pygame_util
|
---|
69 | return pymunk.pygame_util.to_pygame(pos, surface)
|
---|
70 |
|
---|
71 | def render_angle(self):
|
---|
72 | return self._shape.body.angle
|
---|
73 |
|
---|
74 |
|
---|
75 | class Renderer(object):
|
---|
76 | def render(self, surface, pos, angle):
|
---|
77 | raise NotImplementedError()
|
---|
78 |
|
---|
79 |
|
---|
80 | def image_pos(image, pos):
|
---|
81 | return (pos[0] - image.get_width() / 2,
|
---|
82 | pos[1] - image.get_height() / 2)
|
---|
83 |
|
---|
84 |
|
---|
85 | class ImageRenderer(Renderer):
|
---|
86 | def __init__(self, image):
|
---|
87 | self._image = image
|
---|
88 |
|
---|
89 | def render(self, surface, pos, angle):
|
---|
90 | surface.blit(self._image, image_pos(self._image, pos))
|
---|
91 |
|
---|
92 |
|
---|
93 | class FacingImageRenderer(Renderer):
|
---|
94 | def __init__(self, left_image, right_image):
|
---|
95 | self._images = {
|
---|
96 | 'left': left_image,
|
---|
97 | 'right': right_image,
|
---|
98 | }
|
---|
99 |
|
---|
100 | def get_image(self, angle):
|
---|
101 | if abs(angle) < math.pi / 2:
|
---|
102 | return self._images['right']
|
---|
103 | return self._images['left']
|
---|
104 |
|
---|
105 | def render(self, surface, pos, angle):
|
---|
106 | image = self.get_image(angle)
|
---|
107 | surface.blit(image, image_pos(image, pos))
|
---|
108 |
|
---|
109 |
|
---|
110 | class ShapeRenderer(Renderer):
|
---|
111 | def __init__(self, shape):
|
---|
112 | self._shape = shape
|
---|
113 |
|
---|
114 | def render(self, surface, pos, angle):
|
---|
115 | import pymunk.pygame_util
|
---|
116 | pymunk.pygame_util.draw(surface, self._shape)
|
---|
117 |
|
---|
118 |
|
---|
119 | class GameObject(object):
|
---|
120 | """A representation of a thing in the game world.
|
---|
121 |
|
---|
122 | This has a rendery thing, physicsy things and maybe some other things.
|
---|
123 | """
|
---|
124 |
|
---|
125 | def __init__(self, renderer, physicser=None, puzzler=None):
|
---|
126 | self.renderer = renderer
|
---|
127 | if physicser is None:
|
---|
128 | physicser = NullPhysicser()
|
---|
129 | self.physicser = physicser
|
---|
130 | self.puzzler = puzzler
|
---|
131 |
|
---|
132 | def add_to_space(self, space):
|
---|
133 | self.physicser.add_to_space(space)
|
---|
134 |
|
---|
135 | def render(self, surface):
|
---|
136 | return self.renderer.render(
|
---|
137 | surface, self.physicser.render_position(surface),
|
---|
138 | self.physicser.render_angle())
|
---|
139 |
|
---|
140 |
|
---|
141 | class FloorSwitch(GameObject):
|
---|
142 | def __init__(self, position):
|
---|
143 | body = pymunk.Body()
|
---|
144 | body.position = position
|
---|
145 | self.shape = pymunk.Circle(body, 30)
|
---|
146 | self.shape.collision_type = COLLISION_TYPE_SWITCH
|
---|
147 | self.shape.sensor = True
|
---|
148 | super(FloorSwitch, self).__init__(
|
---|
149 | ShapeRenderer(self.shape),
|
---|
150 | SingleShapePhysicser(self.shape),
|
---|
151 | FloorSwitchPuzzler(self.shape),
|
---|
152 | )
|
---|
153 |
|
---|
154 | def add_to_space(self, space):
|
---|
155 | # XXX: Hacky hack.
|
---|
156 | self._space = space
|
---|
157 |
|
---|
158 | def render(self, surface):
|
---|
159 | if self.puzzler.get_state(self._space):
|
---|
160 | self.shape.color = pygame.color.THECOLORS['green']
|
---|
161 | else:
|
---|
162 | self.shape.color = pygame.color.THECOLORS['red']
|
---|
163 | super(FloorSwitch, self).render(surface)
|
---|