source: nagslang/enemies.py @ 229:329b3044ddef

Last change on this file since 229:329b3044ddef was 229:329b3044ddef, checked in by Jeremy Thurgood <firxen@…>, 7 years ago

Much better facing renderers.

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