source: nagslang/protagonist.py@ 160:0c9b0449485e

Last change on this file since 160:0c9b0449485e was 156:94a2456696af, checked in by Neil Muller <drnlmuller@…>, 8 years ago

front and back views

File size: 8.3 KB
Line 
1import pymunk
2import pymunk.pygame_util
3
4import math
5
6from nagslang.constants import COLLISION_TYPE_PLAYER, ZORDER_MID
7from nagslang.game_object import (
8 GameObject, SingleShapePhysicser, AnimatedFacingImageRenderer, 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._physicsers = {}
46 for form, shape in self._shapes.iteritems():
47 shape.elasticity = 1.0
48 shape.friction = 10.0
49 shape.collision_type = COLLISION_TYPE_PLAYER
50 self._physicsers[form] = SingleShapePhysicser(space, shape)
51 self.angle = 0
52
53 def _get_image(self, name, *transforms):
54 return resources.get_image('creatures', name, transforms=transforms)
55
56 def _setup_renderers(self):
57 self._renderers = {
58 self.HUMAN_FORM: AnimatedFacingImageRenderer(
59 (self._get_image('human_1.png'),
60 self._get_image('human_1.png'),
61 self._get_image('human_1.png'),
62 self._get_image('human_2.png'),
63 self._get_image('human_2.png'),
64 self._get_image('human_2.png')),
65 (self._get_image('human_1.png', FLIP_H),
66 self._get_image('human_1.png', FLIP_H),
67 self._get_image('human_1.png', FLIP_H),
68 self._get_image('human_2.png', FLIP_H),
69 self._get_image('human_2.png', FLIP_H),
70 self._get_image('human_2.png', FLIP_H))),
71 self.HUMAN_FORM_BACK: AnimatedFacingImageRenderer(
72 (self._get_image('human_back_1.png'),
73 self._get_image('human_back_1.png'),
74 self._get_image('human_back_1.png'),
75 self._get_image('human_back_2.png'),
76 self._get_image('human_back_2.png'),
77 self._get_image('human_back_2.png')),
78 (self._get_image('human_back_1.png', FLIP_H),
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_2.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.WOLF_FORM: AnimatedFacingImageRenderer(
85 (self._get_image('werewolf_1.png'),
86 self._get_image('werewolf_1.png'),
87 self._get_image('werewolf_1.png'),
88 self._get_image('werewolf_2.png'),
89 self._get_image('werewolf_2.png'),
90 self._get_image('werewolf_2.png')),
91 (self._get_image('werewolf_1.png', FLIP_H),
92 self._get_image('werewolf_1.png', FLIP_H),
93 self._get_image('werewolf_1.png', FLIP_H),
94 self._get_image('werewolf_2.png', FLIP_H),
95 self._get_image('werewolf_2.png', FLIP_H),
96 self._get_image('werewolf_2.png', FLIP_H))),
97 self.WOLF_FORM_BACK: AnimatedFacingImageRenderer(
98 (self._get_image('werewolf_back_1.png'),
99 self._get_image('werewolf_back_1.png'),
100 self._get_image('werewolf_back_1.png'),
101 self._get_image('werewolf_back_2.png'),
102 self._get_image('werewolf_back_2.png'),
103 self._get_image('werewolf_back_2.png')),
104 (self._get_image('werewolf_back_1.png', FLIP_H),
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_2.png', FLIP_H),
108 self._get_image('werewolf_back_2.png', FLIP_H),
109 self._get_image('werewolf_back_2.png', FLIP_H))),
110 }
111 for renderer in self._renderers.values():
112 renderer.set_game_object(self)
113
114 @classmethod
115 def from_saved_state(cls, saved_state):
116 """Create an instance from the provided serialised state.
117 """
118 obj = cls()
119 # TODO: Update from saved state.
120 return obj
121
122 def get_render_angle(self):
123 return self.angle
124
125 def go_werewolf(self):
126 self._physicsers[self.form].remove_from_space()
127 self.form = self.WOLF_FORM
128 self._physicsers[self.form].add_to_space()
129 self._body.mass = 100
130 self._body.velocity_limit = 1000
131 self.impulse_factor = 4000
132 self._body.damping = 0.9
133 if self.render_form == self.HUMAN_FORM:
134 self.render_form = self.WOLF_FORM
135 elif self.render_form == self.HUMAN_FORM_BACK:
136 self.render_form = self.WOLF_FORM_BACK
137 else:
138 self.render_form = self.WOLF_FORM
139 self.renderer = self._renderers[self.render_form]
140
141 def go_human(self):
142 self._physicsers[self.form].remove_from_space()
143 self.form = self.HUMAN_FORM
144 self._physicsers[self.form].add_to_space()
145 self._body.mass = 10
146 self._body.velocity_limit = 1000
147 self.impulse_factor = 500
148 self._body.damping = 0.8
149 if self.render_form == self.WOLF_FORM:
150 self.render_form = self.HUMAN_FORM
151 elif self.render_form == self.WOLF_FORM_BACK:
152 self.render_form = self.HUMAN_FORM_BACK
153 else:
154 self.render_form = self.HUMAN_FORM
155 self.renderer = self._renderers[self.render_form]
156
157 def _switch_to_back(self):
158 if self.render_form == self.HUMAN_FORM:
159 self.render_form = self.HUMAN_FORM_BACK
160 elif self.render_form == self.WOLF_FORM:
161 self.render_form = self.WOLF_FORM_BACK
162 self.renderer = self._renderers[self.render_form]
163
164 def _switch_to_front(self):
165 if self.render_form == self.HUMAN_FORM_BACK:
166 self.render_form = self.HUMAN_FORM
167 elif self.render_form == self.WOLF_FORM_BACK:
168 self.render_form = self.WOLF_FORM
169 self.renderer = self._renderers[self.render_form]
170
171 def set_direction(self, dx, dy):
172 if (dx, dy) == (0, 0):
173 self.renderer.stop()
174 return
175 old_angle = self.angle
176 self.angle = pymunk.Vec2d((dx, dy)).angle
177 # If we've gone from quadrants 2 & 3 to 1 & 4 (or vice versa)
178 # switch between front & back views
179 if self.angle != math.pi:
180 # == math.pi is going straight left, which can't
181 # trigger a front/back swap and simplifies these checks
182 if self.angle > 0 and old_angle != self.angle:
183 self._switch_to_back()
184 elif self.angle < 0 and old_angle != self.angle:
185 self._switch_to_front()
186 self._body.apply_impulse(
187 (dx * self.impulse_factor, dy * self.impulse_factor))
188 self.renderer.start()
189
190 def toggle_form(self):
191 if self.form == self.WOLF_FORM:
192 self.go_human()
193 else:
194 self.go_werewolf()
195
196 def act_on(self, target):
197 """Perform an action on the target.
198 """
199 # TODO: Decide how best to do this.
200 pass
201
202 def attack(self):
203 """Attempt to hurt something.
204 """
205 pass
206
207 def in_wolf_form(self):
208 return self.form == self.WOLF_FORM
209
210 def in_human_form(self):
211 return self.form == self.HUMAN_FORM
212
213 def has_item(self, item):
214 return item in self.inventory
215
216 def environmental_movement(self, dx, dy):
217 if (dx, dy) == (0, 0):
218 return
219 self._body.apply_impulse((dx, dy))
Note: See TracBrowser for help on using the repository browser.