1 | import pymunk
|
---|
2 | import pymunk.pygame_util
|
---|
3 |
|
---|
4 | from nagslang import render
|
---|
5 | from nagslang.constants import COLLISION_TYPE_ENEMY, ZORDER_MID
|
---|
6 | from nagslang.game_object import GameObject, SingleShapePhysicser, make_body
|
---|
7 | from nagslang.mutators import FLIP_H
|
---|
8 | from nagslang.resources import resources
|
---|
9 |
|
---|
10 |
|
---|
11 | class Enemy(GameObject):
|
---|
12 | """A base class for mobile enemies"""
|
---|
13 |
|
---|
14 | def __init__(self, space, position):
|
---|
15 | self._setup_physics(space, position)
|
---|
16 | self._setup_renderer()
|
---|
17 |
|
---|
18 | super(Enemy, self).__init__(
|
---|
19 | self._physicser, self.renderer)
|
---|
20 | self.zorder = ZORDER_MID
|
---|
21 |
|
---|
22 | def _get_image(self, name, *transforms):
|
---|
23 | return resources.get_image('creatures', name, transforms=transforms)
|
---|
24 |
|
---|
25 | def _setup_physics(self, space, position):
|
---|
26 | raise NotImplementedError
|
---|
27 |
|
---|
28 | def _setup_renderer(self):
|
---|
29 | raise NotImplementedError
|
---|
30 |
|
---|
31 | def attack(self):
|
---|
32 | raise NotImplementedError
|
---|
33 |
|
---|
34 |
|
---|
35 | class PatrollingAlien(Enemy):
|
---|
36 | is_moving = True # Always walking.
|
---|
37 |
|
---|
38 | def __init__(self, space, position, end_position):
|
---|
39 | # An enemy that patrols between the two points
|
---|
40 | super(PatrollingAlien, self).__init__(space, position)
|
---|
41 | self._start_pos = position
|
---|
42 | self._end_pos = end_position
|
---|
43 | self._direction = 'away'
|
---|
44 |
|
---|
45 | def _setup_physics(self, space, position):
|
---|
46 | self._body = make_body(10, pymunk.inf, position, 0.8)
|
---|
47 |
|
---|
48 | self._shape = pymunk.Circle(self._body, 30)
|
---|
49 |
|
---|
50 | self._shape.elasticity = 1.0
|
---|
51 | self._shape.friction = 0.05
|
---|
52 | self._shape.collision_type = COLLISION_TYPE_ENEMY
|
---|
53 | self._physicser = SingleShapePhysicser(space, self._shape)
|
---|
54 | self.impulse_factor = 50
|
---|
55 | self.angle = 0
|
---|
56 |
|
---|
57 | def _setup_renderer(self):
|
---|
58 | self.renderer = render.FacingSelectionRenderer({
|
---|
59 | 'left': render.TimedAnimatedRenderer(
|
---|
60 | [self._get_image('alien_A_1.png'),
|
---|
61 | self._get_image('alien_A_2.png')], 3),
|
---|
62 | 'right': render.TimedAnimatedRenderer(
|
---|
63 | [self._get_image('alien_A_1.png', FLIP_H),
|
---|
64 | self._get_image('alien_A_2.png', FLIP_H)], 3),
|
---|
65 | })
|
---|
66 |
|
---|
67 | def get_render_angle(self):
|
---|
68 | return self.angle
|
---|
69 |
|
---|
70 | def _switch_direction(self):
|
---|
71 | if self._direction == 'away':
|
---|
72 | self._direction = 'towards'
|
---|
73 | else:
|
---|
74 | self._direction = 'away'
|
---|
75 |
|
---|
76 | def set_direction(self, dx, dy):
|
---|
77 | self.angle = pymunk.Vec2d((dx, dy)).angle
|
---|
78 | self._body.apply_impulse(
|
---|
79 | (dx * self.impulse_factor, dy * self.impulse_factor))
|
---|
80 |
|
---|
81 | def animate(self):
|
---|
82 | # Calculate the step every frame
|
---|
83 | if self._direction == 'away':
|
---|
84 | target = self._end_pos
|
---|
85 | else:
|
---|
86 | target = self._start_pos
|
---|
87 | x_step = 0
|
---|
88 | y_step = 0
|
---|
89 | if (target[0] < self._body.position[0]):
|
---|
90 | x_step = max(-1, target[0] - self._body.position[0])
|
---|
91 | elif (target[0] > self._body.position[0]):
|
---|
92 | x_step = min(1, target[0] - self._body.position[0])
|
---|
93 | if abs(x_step) < 0.5:
|
---|
94 | x_step = 0
|
---|
95 | if (target[1] < self._body.position[1]):
|
---|
96 | y_step = max(-1, target[1] - self._body.position[1])
|
---|
97 | elif (target[1] > self._body.position[1]):
|
---|
98 | y_step = min(1, target[1] - self._body.position[1])
|
---|
99 | if abs(y_step) < 0.5:
|
---|
100 | y_step = 0
|
---|
101 | if abs(x_step) < 1 and abs(y_step) < 1:
|
---|
102 | self._switch_direction()
|
---|
103 | self.set_direction(x_step, y_step)
|
---|
104 | super(PatrollingAlien, self).animate()
|
---|