source: nagslang/protagonist.py@ 207:42e8993c31fd

Last change on this file since 207:42e8993c31fd was 207:42e8993c31fd, checked in by Stefano Rivera <stefano@…>, 7 years ago

Break out Renderers

File size: 9.0 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._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: render.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: render.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: render.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: render.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.physicser = self._physicsers[self.form]
130 self._body.mass = 100
131 self._body.velocity_limit = 1000
132 self.impulse_factor = 4000
133 self._body.damping = 0.9
134 if self.render_form == self.HUMAN_FORM:
135 self.render_form = self.WOLF_FORM
136 elif self.render_form == self.HUMAN_FORM_BACK:
137 self.render_form = self.WOLF_FORM_BACK
138 else:
139 self.render_form = self.WOLF_FORM
140 self.renderer = self._renderers[self.render_form]
141
142 def go_human(self):
143 self._physicsers[self.form].remove_from_space()
144 self.form = self.HUMAN_FORM
145 self._physicsers[self.form].add_to_space()
146 self.physicser = self._physicsers[self.form]
147 self._body.mass = 10
148 self._body.velocity_limit = 1000
149 self.impulse_factor = 500
150 self._body.damping = 0.8
151 if self.render_form == self.WOLF_FORM:
152 self.render_form = self.HUMAN_FORM
153 elif self.render_form == self.WOLF_FORM_BACK:
154 self.render_form = self.HUMAN_FORM_BACK
155 else:
156 self.render_form = self.HUMAN_FORM
157 self.renderer = self._renderers[self.render_form]
158
159 def _switch_to_back(self):
160 if self.render_form == self.HUMAN_FORM:
161 self.render_form = self.HUMAN_FORM_BACK
162 elif self.render_form == self.WOLF_FORM:
163 self.render_form = self.WOLF_FORM_BACK
164 self.renderer = self._renderers[self.render_form]
165
166 def _switch_to_front(self):
167 if self.render_form == self.HUMAN_FORM_BACK:
168 self.render_form = self.HUMAN_FORM
169 elif self.render_form == self.WOLF_FORM_BACK:
170 self.render_form = self.WOLF_FORM
171 self.renderer = self._renderers[self.render_form]
172
173 def set_direction(self, dx, dy):
174 if (dx, dy) == (0, 0):
175 self.renderer.stop()
176 return
177 old_angle = self.angle
178 self.angle = pymunk.Vec2d((dx, dy)).angle
179 # If we've gone from quadrants 2 & 3 to 1 & 4 (or vice versa)
180 # switch between front & back views
181 if self.angle != math.pi:
182 # == math.pi is going straight left, which can't
183 # trigger a front/back swap and simplifies these checks
184 if self.angle > 0 and old_angle != self.angle:
185 self._switch_to_back()
186 elif self.angle < 0 and old_angle != self.angle:
187 self._switch_to_front()
188 self._body.apply_impulse(
189 (dx * self.impulse_factor, dy * self.impulse_factor))
190 self.renderer.start()
191
192 def set_position(self, position):
193 self._body.position = position
194
195 def copy_state(self, old_protagonist):
196 self._physicsers[self.form].remove_from_space()
197 self._body.position = old_protagonist._body.position
198 self.form = old_protagonist.form
199 self.angle = old_protagonist.angle
200 self.render_form = old_protagonist.render_form
201 self.inventory = old_protagonist.inventory
202 self.renderer = self._renderers[self.render_form]
203 self._physicsers[self.form].add_to_space()
204 self.physicser = self._physicsers[self.form]
205
206 def toggle_form(self):
207 if self.form == self.WOLF_FORM:
208 self.go_human()
209 else:
210 self.go_werewolf()
211
212 def act_on(self, target):
213 """Perform an action on the target.
214 """
215 # TODO: Decide how best to do this.
216 pass
217
218 def attack(self):
219 """Attempt to hurt something.
220 """
221 pass
222
223 def in_wolf_form(self):
224 return self.form == self.WOLF_FORM
225
226 def in_human_form(self):
227 return self.form == self.HUMAN_FORM
228
229 def has_item(self, item):
230 return item in self.inventory
231
232 def environmental_movement(self, dx, dy):
233 if (dx, dy) == (0, 0):
234 return
235 self._body.apply_impulse((dx, dy))
Note: See TracBrowser for help on using the repository browser.