source: nagslang/protagonist.py@ 235:831e4f6b3d18

Last change on this file since 235:831e4f6b3d18 was 230:a3db94687ce2, checked in by Jeremy Thurgood <firxen@…>, 8 years ago

Remove unused stuff.

File size: 8.3 KB
Line 
1import pymunk
2import pymunk.pygame_util
3from pymunk.vec2d import Vec2d
4
5from nagslang import render
6from nagslang.constants import COLLISION_TYPE_PLAYER, ZORDER_MID
7from nagslang.game_object import GameObject, Physicser, make_body
8from nagslang.mutators import FLIP_H
9from nagslang.resources import resources
10
11
12class ProtagonistPhysicser(Physicser):
13 def __init__(self, space, form_shapes):
14 self._space = space
15 self._form_shapes = form_shapes
16
17 def switch_form(self, old_form, new_form):
18 self._space.remove(self._form_shapes[old_form])
19 shape = self._form_shapes[new_form]
20 self._space.add(shape)
21 for attr, value in shape.protagonist_body_props.iteritems():
22 setattr(shape.body, attr, value)
23
24 def get_shape(self):
25 return self._form_shapes[self.game_object.form]
26
27
28class ProtagonistFormSelectionRenderer(render.RendererSelectionRenderer):
29 def select_renderer(self):
30 return self.game_object.form
31
32
33class Protagonist(GameObject):
34 """Representation of our fearless protagonist.
35
36 TODO: Factor out a bunch of this stuff when we need it for other objects.
37 """
38
39 HUMAN_FORM = 'human'
40 WOLF_FORM = 'wolf'
41
42 def __init__(self, space, position):
43 physicser = self._make_physics(space, position)
44 renderer = self._make_renderer()
45 self.inventory = {}
46 self.form = self.HUMAN_FORM
47 self.angle = 0
48 self.is_moving = False
49
50 super(Protagonist, self).__init__(physicser, renderer)
51 self.zorder = ZORDER_MID
52
53 self.go_human()
54
55 def _make_physics(self, space, position):
56 body = make_body(10, pymunk.inf, position, 0.8)
57 body.velocity_limit = 1000
58
59 human = pymunk.Poly(body, [(-15, -30), (15, -30), (15, 30), (-15, 30)])
60 human.elasticity = 1.0
61 human.collision_type = COLLISION_TYPE_PLAYER
62 human.protagonist_body_props = {
63 'mass': 10,
64 'damping': 0.8,
65 }
66
67 wolf = pymunk.Circle(body, 30)
68 wolf.elasticity = 1.0
69 wolf.collision_type = COLLISION_TYPE_PLAYER
70 wolf.protagonist_body_props = {
71 'mass': 100,
72 'damping': 0.9,
73 }
74
75 return ProtagonistPhysicser(space, {
76 self.HUMAN_FORM: human,
77 self.WOLF_FORM: wolf,
78 })
79
80 def _get_image(self, name, *transforms):
81 return resources.get_image('creatures', name, transforms=transforms)
82
83 def _make_renderer(self):
84 return ProtagonistFormSelectionRenderer({
85 self.HUMAN_FORM: render.FacingSelectionRenderer(
86 {
87 'N': render.MovementAnimatedRenderer(
88 [self._get_image('human_N_1.png'),
89 self._get_image('human_N_2.png')], 3),
90 'S': render.MovementAnimatedRenderer(
91 [self._get_image('human_S_1.png'),
92 self._get_image('human_S_2.png')], 3),
93 'W': render.MovementAnimatedRenderer(
94 [self._get_image('human_W_1.png'),
95 self._get_image('human_W_2.png')], 3),
96 'E': render.MovementAnimatedRenderer(
97 [self._get_image('human_W_1.png', FLIP_H),
98 self._get_image('human_W_2.png', FLIP_H)], 3),
99 'NW': render.MovementAnimatedRenderer(
100 [self._get_image('human_NW_1.png'),
101 self._get_image('human_NW_2.png')], 3),
102 'NE': render.MovementAnimatedRenderer(
103 [self._get_image('human_NW_1.png', FLIP_H),
104 self._get_image('human_NW_2.png', FLIP_H)], 3),
105 'SW': render.MovementAnimatedRenderer(
106 [self._get_image('human_SW_1.png'),
107 self._get_image('human_SW_2.png')], 3),
108 'SE': render.MovementAnimatedRenderer(
109 [self._get_image('human_SW_1.png', FLIP_H),
110 self._get_image('human_SW_2.png', FLIP_H)], 3),
111 }),
112 self.WOLF_FORM: render.FacingSelectionRenderer(
113 {
114 'N': render.MovementAnimatedRenderer(
115 [self._get_image('werewolf_N_1.png'),
116 self._get_image('werewolf_N_2.png')], 3),
117 'S': render.MovementAnimatedRenderer(
118 [self._get_image('werewolf_S_1.png'),
119 self._get_image('werewolf_S_2.png')], 3),
120 'W': render.MovementAnimatedRenderer(
121 [self._get_image('werewolf_W_1.png'),
122 self._get_image('werewolf_W_2.png')], 3),
123 'E': render.MovementAnimatedRenderer(
124 [self._get_image('werewolf_W_1.png', FLIP_H),
125 self._get_image('werewolf_W_2.png', FLIP_H)], 3),
126 'NW': render.MovementAnimatedRenderer(
127 [self._get_image('werewolf_NW_1.png'),
128 self._get_image('werewolf_NW_2.png')], 3),
129 'NE': render.MovementAnimatedRenderer(
130 [self._get_image('werewolf_NW_1.png', FLIP_H),
131 self._get_image('werewolf_NW_2.png', FLIP_H)], 3),
132 'SW': render.MovementAnimatedRenderer(
133 [self._get_image('werewolf_SW_1.png'),
134 self._get_image('werewolf_SW_2.png')], 3),
135 'SE': render.MovementAnimatedRenderer(
136 [self._get_image('werewolf_SW_1.png', FLIP_H),
137 self._get_image('werewolf_SW_2.png', FLIP_H)], 3),
138 }),
139 })
140
141 @classmethod
142 def from_saved_state(cls, saved_state):
143 """Create an instance from the provided serialised state.
144 """
145 obj = cls()
146 # TODO: Update from saved state.
147 return obj
148
149 def get_render_angle(self):
150 # No image rotation when rendering, please.
151 return 0
152
153 def get_facing_direction(self):
154 # It's easier to work with a vector than an angle here.
155 vec = Vec2d.unit()
156 vec.angle = self.angle
157 # We probably don't have exactly -1, 0, or 1 here.
158 x = int(round(vec.x))
159 y = int(round(vec.y))
160
161 return {
162 (0, 1): 'N',
163 (0, -1): 'S',
164 (-1, 0): 'W',
165 (1, 0): 'E',
166 (1, 1): 'NE',
167 (1, -1): 'SE',
168 (-1, 1): 'NW',
169 (-1, -1): 'SW',
170 }[(x, y)]
171
172 def go_werewolf(self):
173 self.physicser.switch_form(self.form, self.WOLF_FORM)
174 self.form = self.WOLF_FORM
175 self.impulse_factor = 4000
176
177 def go_human(self):
178 self.physicser.switch_form(self.form, self.HUMAN_FORM)
179 self.form = self.HUMAN_FORM
180 self.impulse_factor = 500
181
182 def set_direction(self, dx, dy):
183 if (dx, dy) == (0, 0):
184 self.is_moving = False
185 return
186 self.is_moving = True
187 self.angle = pymunk.Vec2d((dx, dy)).angle
188 self.physicser.apply_impulse(
189 (dx * self.impulse_factor, dy * self.impulse_factor))
190
191 def set_position(self, position):
192 self.physicser.position = position
193
194 def copy_state(self, old_protagonist):
195 self.physicser.position = old_protagonist.physicser.position
196 self.physicser.switch_form(self.form, old_protagonist.form)
197 self.impulse_factor = old_protagonist.impulse_factor
198 self.form = old_protagonist.form
199 self.angle = old_protagonist.angle
200 self.inventory = old_protagonist.inventory
201
202 def toggle_form(self):
203 if self.form == self.WOLF_FORM:
204 self.go_human()
205 else:
206 self.go_werewolf()
207
208 def act_on(self, target):
209 """Perform an action on the target.
210 """
211 # TODO: Decide how best to do this.
212 pass
213
214 def attack(self):
215 """Attempt to hurt something.
216 """
217 pass
218
219 def in_wolf_form(self):
220 return self.form == self.WOLF_FORM
221
222 def in_human_form(self):
223 return self.form == self.HUMAN_FORM
224
225 def has_item(self, item):
226 return item in self.inventory
227
228 def environmental_movement(self, dx, dy):
229 if (dx, dy) == (0, 0):
230 return
231 self.physicser.apply_impulse((dx, dy))
Note: See TracBrowser for help on using the repository browser.