source: nagslang/enemies.py@ 258:083053422a84

Last change on this file since 258:083053422a84 was 258:083053422a84, checked in by David Sharpe, 8 years ago

Added collision damage with enemies.

File size: 4.2 KB
Line 
1import math
2
3import pymunk
4import pymunk.pygame_util
5
6from nagslang import render
7from nagslang.constants import COLLISION_TYPE_ENEMY, ZORDER_MID
8from nagslang.game_object import GameObject, SingleShapePhysicser, make_body
9from nagslang.mutators import FLIP_H
10from nagslang.resources import resources
11
12
13def get_editable_enemies():
14 classes = []
15 for cls_name, cls in globals().iteritems():
16 if isinstance(cls, type) and issubclass(cls, Enemy):
17 if hasattr(cls, 'requires'):
18 classes.append((cls_name, cls))
19 return classes
20
21
22class Enemy(GameObject):
23 """A base class for mobile enemies"""
24
25 def __init__(self, space, position):
26 self._setup_physics(space, position)
27 self._setup_renderer()
28
29 super(Enemy, self).__init__(
30 self._physicser, self.renderer)
31 self.zorder = ZORDER_MID
32
33 def _get_image(self, name, *transforms):
34 return resources.get_image('creatures', name, transforms=transforms)
35
36 def _setup_physics(self, space, position):
37 raise NotImplementedError
38
39 def _setup_renderer(self):
40 raise NotImplementedError
41
42 def attack(self):
43 raise NotImplementedError
44
45 @classmethod
46 def requires(cls):
47 return [("name", "string"), ("position", "coordinates")]
48
49
50class PatrollingAlien(Enemy):
51 is_moving = True # Always walking.
52
53 def __init__(self, space, position, end_position):
54 # An enemy that patrols between the two points
55 super(PatrollingAlien, self).__init__(space, position)
56 self._start_pos = position
57 self._end_pos = end_position
58 self._direction = 'away'
59
60 def _setup_physics(self, space, position):
61 self._body = make_body(10, pymunk.inf, position, 0.8)
62
63 self._shape = pymunk.Circle(self._body, 30)
64
65 self._shape.elasticity = 1.0
66 self._shape.friction = 0.05
67 self._shape.collision_type = COLLISION_TYPE_ENEMY
68 self._physicser = SingleShapePhysicser(space, self._shape)
69 self.impulse_factor = 50
70 self.angle = 0
71
72 def _setup_renderer(self):
73 self.renderer = render.FacingSelectionRenderer({
74 'left': render.TimedAnimatedRenderer(
75 [self._get_image('alien_A_1.png'),
76 self._get_image('alien_A_2.png')], 3),
77 'right': render.TimedAnimatedRenderer(
78 [self._get_image('alien_A_1.png', FLIP_H),
79 self._get_image('alien_A_2.png', FLIP_H)], 3),
80 })
81
82 def get_render_angle(self):
83 # No image rotation when rendering, please.
84 return 0
85
86 def get_facing_direction(self):
87 # Enemies can face left or right.
88 if - math.pi / 2 < self.angle <= math.pi / 2:
89 return 'right'
90 else:
91 return 'left'
92
93 def _switch_direction(self):
94 if self._direction == 'away':
95 self._direction = 'towards'
96 else:
97 self._direction = 'away'
98
99 def set_direction(self, dx, dy):
100 self.angle = pymunk.Vec2d((dx, dy)).angle
101 self._body.apply_impulse(
102 (dx * self.impulse_factor, dy * self.impulse_factor))
103
104 def animate(self):
105 # Calculate the step every frame
106 if self._direction == 'away':
107 target = self._end_pos
108 else:
109 target = self._start_pos
110 x_step = 0
111 y_step = 0
112 if (target[0] < self._body.position[0]):
113 x_step = max(-1, target[0] - self._body.position[0])
114 elif (target[0] > self._body.position[0]):
115 x_step = min(1, target[0] - self._body.position[0])
116 if abs(x_step) < 0.5:
117 x_step = 0
118 if (target[1] < self._body.position[1]):
119 y_step = max(-1, target[1] - self._body.position[1])
120 elif (target[1] > self._body.position[1]):
121 y_step = min(1, target[1] - self._body.position[1])
122 if abs(y_step) < 0.5:
123 y_step = 0
124 if abs(x_step) < 1 and abs(y_step) < 1:
125 self._switch_direction()
126 self.set_direction(x_step, y_step)
127 super(PatrollingAlien, self).animate()
128
129 def collide_with_protagonist(self):
130 return 5
131
132 @classmethod
133 def requires(cls):
134 return [("name", "string"), ("position", "coordinates"),
135 ("end_position", "coordinates")]
Note: See TracBrowser for help on using the repository browser.