source: nagslang/protagonist.py @ 230:a3db94687ce2

Last change on this file since 230:a3db94687ce2 was 230:a3db94687ce2, checked in by Jeremy Thurgood <firxen@…>, 7 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.