source: nagslang/protagonist.py@ 209:ad1d3de210cd

Last change on this file since 209:ad1d3de210cd was 208:3d54fe7a2998, checked in by Jeremy Thurgood <firxen@…>, 8 years ago

Fun with mass and friction.

File size: 9.1 KB
Line 
1import pymunk
2import pymunk.pygame_util
3
4import math
5
6from nagslang import render
7from nagslang.constants import COLLISION_TYPE_PLAYER, ZORDER_MID
8from nagslang.game_object import GameObject, SingleShapePhysicser, make_body
9from nagslang.mutators import FLIP_H
10from nagslang.resources import resources
11
12
13class Protagonist(GameObject):
14 """Representation of our fearless protagonist.
15
16 TODO: Factor out a bunch of this stuff when we need it for other objects.
17 """
18
19 HUMAN_FORM = 'human'
20 HUMAN_FORM_BACK = 'human_back'
21 WOLF_FORM = 'wolf'
22 WOLF_FORM_BACK = 'wolf_back'
23
24 def __init__(self, space, position):
25 self._setup_physics(space, position)
26 self._setup_renderers()
27 self.inventory = {}
28 self.form = self.HUMAN_FORM
29 self.render_form = self.HUMAN_FORM
30
31 super(Protagonist, self).__init__(
32 self._physicsers[self.form], self._renderers[self.form])
33 self.zorder = ZORDER_MID
34
35 self.go_human()
36
37 def _setup_physics(self, space, position):
38 self._body = make_body(10, pymunk.inf, position, 0.8)
39
40 self._shapes = {
41 self.HUMAN_FORM: pymunk.Poly(
42 self._body, [(-15, -30), (15, -30), (15, 30), (-15, 30)]),
43 self.WOLF_FORM: pymunk.Circle(self._body, 30),
44 }
45 self._shapes[self.HUMAN_FORM].friction = 1.0
46 self._shapes[self.WOLF_FORM].friction = 0.05
47 self._physicsers = {}
48 for form, shape in self._shapes.iteritems():
49 shape.elasticity = 1.0
50 shape.collision_type = COLLISION_TYPE_PLAYER
51 self._physicsers[form] = SingleShapePhysicser(space, shape)
52 self.angle = 0
53
54 def _get_image(self, name, *transforms):
55 return resources.get_image('creatures', name, transforms=transforms)
56
57 def _setup_renderers(self):
58 self._renderers = {
59 self.HUMAN_FORM: render.AnimatedFacingImageRenderer(
60 (self._get_image('human_1.png'),
61 self._get_image('human_1.png'),
62 self._get_image('human_1.png'),
63 self._get_image('human_2.png'),
64 self._get_image('human_2.png'),
65 self._get_image('human_2.png')),
66 (self._get_image('human_1.png', FLIP_H),
67 self._get_image('human_1.png', FLIP_H),
68 self._get_image('human_1.png', FLIP_H),
69 self._get_image('human_2.png', FLIP_H),
70 self._get_image('human_2.png', FLIP_H),
71 self._get_image('human_2.png', FLIP_H))),
72 self.HUMAN_FORM_BACK: render.AnimatedFacingImageRenderer(
73 (self._get_image('human_back_1.png'),
74 self._get_image('human_back_1.png'),
75 self._get_image('human_back_1.png'),
76 self._get_image('human_back_2.png'),
77 self._get_image('human_back_2.png'),
78 self._get_image('human_back_2.png')),
79 (self._get_image('human_back_1.png', FLIP_H),
80 self._get_image('human_back_1.png', FLIP_H),
81 self._get_image('human_back_1.png', FLIP_H),
82 self._get_image('human_back_2.png', FLIP_H),
83 self._get_image('human_back_2.png', FLIP_H),
84 self._get_image('human_back_2.png', FLIP_H))),
85 self.WOLF_FORM: render.AnimatedFacingImageRenderer(
86 (self._get_image('werewolf_1.png'),
87 self._get_image('werewolf_1.png'),
88 self._get_image('werewolf_1.png'),
89 self._get_image('werewolf_2.png'),
90 self._get_image('werewolf_2.png'),
91 self._get_image('werewolf_2.png')),
92 (self._get_image('werewolf_1.png', FLIP_H),
93 self._get_image('werewolf_1.png', FLIP_H),
94 self._get_image('werewolf_1.png', FLIP_H),
95 self._get_image('werewolf_2.png', FLIP_H),
96 self._get_image('werewolf_2.png', FLIP_H),
97 self._get_image('werewolf_2.png', FLIP_H))),
98 self.WOLF_FORM_BACK: render.AnimatedFacingImageRenderer(
99 (self._get_image('werewolf_back_1.png'),
100 self._get_image('werewolf_back_1.png'),
101 self._get_image('werewolf_back_1.png'),
102 self._get_image('werewolf_back_2.png'),
103 self._get_image('werewolf_back_2.png'),
104 self._get_image('werewolf_back_2.png')),
105 (self._get_image('werewolf_back_1.png', FLIP_H),
106 self._get_image('werewolf_back_1.png', FLIP_H),
107 self._get_image('werewolf_back_1.png', FLIP_H),
108 self._get_image('werewolf_back_2.png', FLIP_H),
109 self._get_image('werewolf_back_2.png', FLIP_H),
110 self._get_image('werewolf_back_2.png', FLIP_H))),
111 }
112 for renderer in self._renderers.values():
113 renderer.set_game_object(self)
114
115 @classmethod
116 def from_saved_state(cls, saved_state):
117 """Create an instance from the provided serialised state.
118 """
119 obj = cls()
120 # TODO: Update from saved state.
121 return obj
122
123 def get_render_angle(self):
124 return self.angle
125
126 def go_werewolf(self):
127 self._physicsers[self.form].remove_from_space()
128 self.form = self.WOLF_FORM
129 self._physicsers[self.form].add_to_space()
130 self.physicser = self._physicsers[self.form]
131 self._body.mass = 100
132 self._body.velocity_limit = 1000
133 self.impulse_factor = 4000
134 self._body.damping = 0.9
135 if self.render_form == self.HUMAN_FORM:
136 self.render_form = self.WOLF_FORM
137 elif self.render_form == self.HUMAN_FORM_BACK:
138 self.render_form = self.WOLF_FORM_BACK
139 else:
140 self.render_form = self.WOLF_FORM
141 self.renderer = self._renderers[self.render_form]
142
143 def go_human(self):
144 self._physicsers[self.form].remove_from_space()
145 self.form = self.HUMAN_FORM
146 self._physicsers[self.form].add_to_space()
147 self.physicser = self._physicsers[self.form]
148 self._body.mass = 10
149 self._body.velocity_limit = 1000
150 self.impulse_factor = 500
151 self._body.damping = 0.8
152 if self.render_form == self.WOLF_FORM:
153 self.render_form = self.HUMAN_FORM
154 elif self.render_form == self.WOLF_FORM_BACK:
155 self.render_form = self.HUMAN_FORM_BACK
156 else:
157 self.render_form = self.HUMAN_FORM
158 self.renderer = self._renderers[self.render_form]
159
160 def _switch_to_back(self):
161 if self.render_form == self.HUMAN_FORM:
162 self.render_form = self.HUMAN_FORM_BACK
163 elif self.render_form == self.WOLF_FORM:
164 self.render_form = self.WOLF_FORM_BACK
165 self.renderer = self._renderers[self.render_form]
166
167 def _switch_to_front(self):
168 if self.render_form == self.HUMAN_FORM_BACK:
169 self.render_form = self.HUMAN_FORM
170 elif self.render_form == self.WOLF_FORM_BACK:
171 self.render_form = self.WOLF_FORM
172 self.renderer = self._renderers[self.render_form]
173
174 def set_direction(self, dx, dy):
175 if (dx, dy) == (0, 0):
176 self.renderer.stop()
177 return
178 old_angle = self.angle
179 self.angle = pymunk.Vec2d((dx, dy)).angle
180 # If we've gone from quadrants 2 & 3 to 1 & 4 (or vice versa)
181 # switch between front & back views
182 if self.angle != math.pi:
183 # == math.pi is going straight left, which can't
184 # trigger a front/back swap and simplifies these checks
185 if self.angle > 0 and old_angle != self.angle:
186 self._switch_to_back()
187 elif self.angle < 0 and old_angle != self.angle:
188 self._switch_to_front()
189 self._body.apply_impulse(
190 (dx * self.impulse_factor, dy * self.impulse_factor))
191 self.renderer.start()
192
193 def set_position(self, position):
194 self._body.position = position
195
196 def copy_state(self, old_protagonist):
197 self._physicsers[self.form].remove_from_space()
198 self._body.position = old_protagonist._body.position
199 self.form = old_protagonist.form
200 self.angle = old_protagonist.angle
201 self.render_form = old_protagonist.render_form
202 self.inventory = old_protagonist.inventory
203 self.renderer = self._renderers[self.render_form]
204 self._physicsers[self.form].add_to_space()
205 self.physicser = self._physicsers[self.form]
206
207 def toggle_form(self):
208 if self.form == self.WOLF_FORM:
209 self.go_human()
210 else:
211 self.go_werewolf()
212
213 def act_on(self, target):
214 """Perform an action on the target.
215 """
216 # TODO: Decide how best to do this.
217 pass
218
219 def attack(self):
220 """Attempt to hurt something.
221 """
222 pass
223
224 def in_wolf_form(self):
225 return self.form == self.WOLF_FORM
226
227 def in_human_form(self):
228 return self.form == self.HUMAN_FORM
229
230 def has_item(self, item):
231 return item in self.inventory
232
233 def environmental_movement(self, dx, dy):
234 if (dx, dy) == (0, 0):
235 return
236 self._body.apply_impulse((dx, dy))
Note: See TracBrowser for help on using the repository browser.