source: nagslang/protagonist.py@ 208:3d54fe7a2998

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

Fun with mass and friction.

File size: 9.1 KB
RevLine 
[65]1import pymunk
2import pymunk.pygame_util
3
[156]4import math
5
[207]6from nagslang import render
[107]7from nagslang.constants import COLLISION_TYPE_PLAYER, ZORDER_MID
[207]8from nagslang.game_object import GameObject, SingleShapePhysicser, make_body
[76]9from nagslang.mutators import FLIP_H
[65]10from nagslang.resources import resources
[28]11
12
[65]13class Protagonist(GameObject):
[28]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'
[156]20 HUMAN_FORM_BACK = 'human_back'
[28]21 WOLF_FORM = 'wolf'
[156]22 WOLF_FORM_BACK = 'wolf_back'
[28]23
[93]24 def __init__(self, space, position):
25 self._setup_physics(space, position)
[65]26 self._setup_renderers()
[28]27 self.inventory = {}
28 self.form = self.HUMAN_FORM
[156]29 self.render_form = self.HUMAN_FORM
[28]30
[65]31 super(Protagonist, self).__init__(
[93]32 self._physicsers[self.form], self._renderers[self.form])
[107]33 self.zorder = ZORDER_MID
[65]34
35 self.go_human()
36
[93]37 def _setup_physics(self, space, position):
[133]38 self._body = make_body(10, pymunk.inf, position, 0.8)
[65]39
[93]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 }
[208]45 self._shapes[self.HUMAN_FORM].friction = 1.0
46 self._shapes[self.WOLF_FORM].friction = 0.05
[93]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
[65]53
[66]54 def _get_image(self, name, *transforms):
55 return resources.get_image('creatures', name, transforms=transforms)
56
[65]57 def _setup_renderers(self):
58 self._renderers = {
[207]59 self.HUMAN_FORM: render.AnimatedFacingImageRenderer(
[143]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))),
[207]72 self.HUMAN_FORM_BACK: render.AnimatedFacingImageRenderer(
[156]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))),
[207]85 self.WOLF_FORM: render.AnimatedFacingImageRenderer(
[143]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))),
[207]98 self.WOLF_FORM_BACK: render.AnimatedFacingImageRenderer(
[156]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))),
[65]111 }
[123]112 for renderer in self._renderers.values():
113 renderer.set_game_object(self)
[65]114
[28]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
[93]123 def get_render_angle(self):
124 return self.angle
125
[65]126 def go_werewolf(self):
[93]127 self._physicsers[self.form].remove_from_space()
[65]128 self.form = self.WOLF_FORM
[93]129 self._physicsers[self.form].add_to_space()
[200]130 self.physicser = self._physicsers[self.form]
[66]131 self._body.mass = 100
132 self._body.velocity_limit = 1000
[65]133 self.impulse_factor = 4000
[133]134 self._body.damping = 0.9
[156]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]
[65]142
143 def go_human(self):
[93]144 self._physicsers[self.form].remove_from_space()
[65]145 self.form = self.HUMAN_FORM
[93]146 self._physicsers[self.form].add_to_space()
[200]147 self.physicser = self._physicsers[self.form]
[66]148 self._body.mass = 10
149 self._body.velocity_limit = 1000
[65]150 self.impulse_factor = 500
[133]151 self._body.damping = 0.8
[156]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]
[65]173
174 def set_direction(self, dx, dy):
175 if (dx, dy) == (0, 0):
[143]176 self.renderer.stop()
[65]177 return
[156]178 old_angle = self.angle
[93]179 self.angle = pymunk.Vec2d((dx, dy)).angle
[156]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()
[66]189 self._body.apply_impulse(
[65]190 (dx * self.impulse_factor, dy * self.impulse_factor))
[143]191 self.renderer.start()
[65]192
[179]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()
[200]205 self.physicser = self._physicsers[self.form]
[179]206
[65]207 def toggle_form(self):
208 if self.form == self.WOLF_FORM:
209 self.go_human()
210 else:
211 self.go_werewolf()
212
[28]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
[73]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.