Changeset 334:a3f1b2f0e3fb for nagslang


Ignore:
Timestamp:
Sep 6, 2013, 9:39:48 AM (7 years ago)
Author:
Jeremy Thurgood <firxen@…>
Branch:
default
Message:

Physics-related cleanup.

Location:
nagslang
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • nagslang/enemies.py

    r333 r334  
    1111from nagslang.mutators import FLIP_H
    1212from nagslang.resources import resources
     13from nagslang.utils import vec_with_length
    1314
    1415
     
    2223
    2324
     25def get_alien_image(enemy_type, suffix, *transforms):
     26    image_name = 'alien_%s_%s.png' % (enemy_type, suffix)
     27    return resources.get_image('creatures', image_name, transforms=transforms)
     28
     29
    2430class Enemy(GameObject):
    2531    """A base class for mobile enemies"""
    26     enemy_type = None  # Image to use for dead Enemy
     32    zorder = ZORDER_MID
     33    enemy_type = None  # Which set of images to use
    2734    enemy_damage = None
     35    health = None
     36    impulse_factor = None
    2837
    2938    def __init__(self, space, world, position):
    30         self._setup_physics(space, position)
    31         self._setup_renderer()
    32         self.health = 42
    33 
    3439        super(Enemy, self).__init__(
    35             self._physicser, self.renderer)
    36         self.zorder = ZORDER_MID
     40            self.make_physics(space, position), self.make_renderer())
    3741        self.world = world
    38 
    39     def _get_image(self, name, *transforms):
    40         return resources.get_image('creatures', name, transforms=transforms)
    41 
    42     def _setup_physics(self, space, position):
     42        self.angle = 0
     43
     44    def make_physics(self, space, position):
    4345        raise NotImplementedError
    4446
    45     def _setup_renderer(self):
    46         raise NotImplementedError
     47    def make_renderer(self):
     48        return render.FacingSelectionRenderer({
     49            'left': render.TimedAnimatedRenderer(
     50                [get_alien_image(self.enemy_type, '1'),
     51                 get_alien_image(self.enemy_type, '2')], 3),
     52            'right': render.TimedAnimatedRenderer(
     53                [get_alien_image(self.enemy_type, '1', FLIP_H),
     54                 get_alien_image(self.enemy_type, '2', FLIP_H)], 3),
     55        })
    4756
    4857    def attack(self):
     
    6271            self.remove = True
    6372            EnemyDeathEvent.post(self.physicser.position, self.enemy_type)
     73
     74    def set_direction(self, dx, dy):
     75        vec = vec_with_length((dx, dy), self.impulse_factor)
     76        self.angle = vec.angle
     77        self.physicser.apply_impulse(vec)
    6478
    6579    def collide_with_protagonist(self, protagonist):
     
    92106    is_moving = True  # Always walking.
    93107    enemy_type = 'A'
     108    health = 42
     109    impulse_factor = 50
    94110
    95111    def __init__(self, space, world, position, end_position):
     
    100116        self._direction = 'away'
    101117
    102     def _setup_physics(self, space, position):
    103         self._body = make_body(10, pymunk.inf, position, 0.8)
    104 
    105         self._shape = pymunk.Circle(self._body, 30)
    106 
    107         self._shape.elasticity = 1.0
    108         self._shape.friction = 0.05
    109         self._shape.collision_type = COLLISION_TYPE_ENEMY
    110         self._physicser = SingleShapePhysicser(space, self._shape)
    111         self.impulse_factor = 50
    112         self.angle = 0
    113 
    114     def _setup_renderer(self):
    115         self.renderer = render.FacingSelectionRenderer({
    116             'left': render.TimedAnimatedRenderer(
    117                 [self._get_image('alien_A_1.png'),
    118                  self._get_image('alien_A_2.png')], 3),
    119             'right': render.TimedAnimatedRenderer(
    120                 [self._get_image('alien_A_1.png', FLIP_H),
    121                  self._get_image('alien_A_2.png', FLIP_H)], 3),
    122         })
     118    def make_physics(self, space, position):
     119        body = make_body(10, pymunk.inf, position, 0.8)
     120        shape = pymunk.Circle(body, 30)
     121        shape.elasticity = 1.0
     122        shape.friction = 0.05
     123        shape.collision_type = COLLISION_TYPE_ENEMY
     124        return SingleShapePhysicser(space, shape)
    123125
    124126    def get_render_angle(self):
     
    139141            self._direction = 'away'
    140142
    141     def set_direction(self, dx, dy):
    142         self.angle = pymunk.Vec2d((dx, dy)).angle
    143         self._body.apply_impulse(
    144             (dx * self.impulse_factor, dy * self.impulse_factor))
    145 
    146143    def update(self, dt):
    147144        # Calculate the step every frame
     
    152149        x_step = 0
    153150        y_step = 0
    154         if (target[0] < self._body.position[0]):
    155             x_step = max(-1, target[0] - self._body.position[0])
    156         elif (target[0] > self._body.position[0]):
    157             x_step = min(1, target[0] - self._body.position[0])
     151        if (target[0] < self.physicser.position[0]):
     152            x_step = max(-1, target[0] - self.physicser.position[0])
     153        elif (target[0] > self.physicser.position[0]):
     154            x_step = min(1, target[0] - self.physicser.position[0])
    158155        if abs(x_step) < 0.5:
    159156            x_step = 0
    160         if (target[1] < self._body.position[1]):
    161             y_step = max(-1, target[1] - self._body.position[1])
    162         elif (target[1] > self._body.position[1]):
    163             y_step = min(1, target[1] - self._body.position[1])
     157        if (target[1] < self.physicser.position[1]):
     158            y_step = max(-1, target[1] - self.physicser.position[1])
     159        elif (target[1] > self.physicser.position[1]):
     160            y_step = min(1, target[1] - self.physicser.position[1])
    164161        if abs(y_step) < 0.5:
    165162            y_step = 0
     
    179176    is_moving = False
    180177    enemy_type = 'B'
     178    health = 42
     179    impulse_factor = 300
    181180
    182181    def __init__(self, space, world, position, attack_range=100):
     
    184183        self._range = attack_range
    185184
    186     def _setup_physics(self, space, position):
    187         self._body = make_body(100, pymunk.inf, position, 0.8)
    188 
    189         self._shape = pymunk.Circle(self._body, 30)
    190 
    191         self._shape.elasticity = 1.0
    192         self._shape.friction = 0.05
    193         self._shape.collision_type = COLLISION_TYPE_ENEMY
    194         self._physicser = SingleShapePhysicser(space, self._shape)
    195         self.impulse_factor = 300
    196         self.angle = 0
    197 
    198     def _setup_renderer(self):
    199         self.renderer = render.FacingSelectionRenderer({
    200             'left': render.TimedAnimatedRenderer(
    201                 [self._get_image('alien_B_1.png'),
    202                  self._get_image('alien_B_2.png')], 3),
    203             'right': render.TimedAnimatedRenderer(
    204                 [self._get_image('alien_B_1.png', FLIP_H),
    205                  self._get_image('alien_B_2.png', FLIP_H)], 3),
    206         })
     185    def make_physics(self, space, position):
     186        body = make_body(100, pymunk.inf, position, 0.8)
     187        shape = pymunk.Circle(body, 30)
     188        shape.elasticity = 1.0
     189        shape.friction = 0.05
     190        shape.collision_type = COLLISION_TYPE_ENEMY
     191        return SingleShapePhysicser(space, shape)
    207192
    208193    def get_render_angle(self):
     
    217202            return 'left'
    218203
    219     def set_direction(self, dx, dy):
    220         self.angle = pymunk.Vec2d((dx, dy)).angle
    221         self._body.apply_impulse(
    222             (dx * self.impulse_factor, dy * self.impulse_factor))
    223 
    224204    def update(self, dt):
    225205        # Calculate the step every frame
    226206        # Distance to the protagonist
    227         pos = self._body.position
     207        pos = self.physicser.position
    228208        target = self.world.protagonist.get_shape().body.position
    229209        if pos.get_distance(target) > self._range:
  • nagslang/protagonist.py

    r333 r334  
    11import pymunk
    22import pymunk.pygame_util
    3 from pymunk.vec2d import Vec2d
    43
    54from nagslang import render
     
    1312from nagslang.resources import resources
    1413from nagslang.events import ScreenChange
     14from nagslang.utils import vec_from_angle, vec_with_length
    1515
    1616
     
    171171
    172172    def get_facing_direction(self):
    173         # It's easier to work with a vector than an angle here.
    174         vec = Vec2d.unit()
    175         vec.angle = self.angle
    176         # We probably don't have exactly -1, 0, or 1 here.
     173        # Our angle is quantised to 45 degree intervals, so possible values for
     174        # x and y in a unit vector are +/-(0, sqrt(2)/2, 1) with some floating
     175        # point imprecision. Rounding will normalise these to (-1.0, 0.0, 1.0)
     176        # which we can safely turn into integers and use as dict keys.
     177        vec = vec_from_angle(self.angle)
    177178        x = int(round(vec.x))
    178179        y = int(round(vec.y))
     
    204205            return
    205206        self.is_moving = True
    206         self.angle = pymunk.Vec2d((dx, dy)).angle
    207         self.physicser.apply_impulse(
    208             (dx * self.impulse_factor, dy * self.impulse_factor))
     207        vec = vec_with_length((dx, dy), self.impulse_factor)
     208        self.angle = vec.angle
     209        self.physicser.apply_impulse(vec)
    209210
    210211    def set_position(self, position):
     
    259260        if not self.has_item('gun'):
    260261            return
    261         vec = Vec2d.unit()
    262         vec.angle = self.angle
    263         vec.length = 1000
     262        vec = vec_from_angle(self.angle, 1000)
    264263        FireEvent.post(
    265264            self.physicser.position, vec, BULLET_DAMAGE, COLLISION_TYPE_PLAYER)
    266265
    267266    def claw(self):
    268         vec = Vec2d.unit()
    269         vec.angle = self.angle
    270         vec.length = 30
     267        vec = vec_from_angle(self.angle, 30)
    271268        ClawEvent.post(self.physicser.position, vec, CLAW_DAMAGE)
    272269
  • nagslang/utils.py

    r29 r334  
    11import pygame
     2from pymunk.vec2d import Vec2d
    23
    34
     
    1011        return pygame.Color(colour)
    1112    raise ValueError()
     13
     14
     15def vec_from_angle(angle, length=1):
     16    vec = Vec2d(length, 0)
     17    vec.angle = angle
     18    return vec
     19
     20
     21def vec_with_length(coords, length=1):
     22    vec = Vec2d(coords)
     23    vec.length = length
     24    return vec
Note: See TracChangeset for help on using the changeset viewer.