changeset 333:3dd32686dbc3

Better wolf claw attack.
author Jeremy Thurgood <firxen@gmail.com>
date Fri, 06 Sep 2013 10:49:19 +0200
parents ffefb93127c5
children a3f1b2f0e3fb
files nagslang/constants.py nagslang/enemies.py nagslang/events.py nagslang/game_object.py nagslang/protagonist.py nagslang/screens/area.py
diffstat 6 files changed, 60 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/nagslang/constants.py	Fri Sep 06 03:10:04 2013 +0200
+++ b/nagslang/constants.py	Fri Sep 06 10:49:19 2013 +0200
@@ -51,3 +51,6 @@
 WEREWOLF_SOAK_FACTOR = 10
 PROTAGONIST_HEALTH_MAX_LEVEL = 100
 PROTAGONIST_HEALTH_MIN_LEVEL = 0
+
+BULLET_DAMAGE = 10
+CLAW_DAMAGE = 5
--- a/nagslang/enemies.py	Fri Sep 06 03:10:04 2013 +0200
+++ b/nagslang/enemies.py	Fri Sep 06 10:49:19 2013 +0200
@@ -24,6 +24,7 @@
 class Enemy(GameObject):
     """A base class for mobile enemies"""
     enemy_type = None  # Image to use for dead Enemy
+    enemy_damage = None
 
     def __init__(self, space, world, position):
         self._setup_physics(space, position)
@@ -61,6 +62,13 @@
             self.remove = True
             EnemyDeathEvent.post(self.physicser.position, self.enemy_type)
 
+    def collide_with_protagonist(self, protagonist):
+        if self.enemy_damage is not None:
+            protagonist.lose_health(self.enemy_damage)
+
+    def collide_with_claw_attack(self, claw_attack):
+        self.lose_health(claw_attack.damage)
+
 
 class DeadEnemy(GameObject):
     def __init__(self, space, world, position, enemy_type='A'):
@@ -135,7 +143,7 @@
         self._body.apply_impulse(
             (dx * self.impulse_factor, dy * self.impulse_factor))
 
-    def update(self, seconds):
+    def update(self, dt):
         # Calculate the step every frame
         if self._direction == 'away':
             target = self._end_pos
@@ -158,10 +166,7 @@
         if abs(x_step) < 1 and abs(y_step) < 1:
             self._switch_direction()
         self.set_direction(x_step, y_step)
-        super(PatrollingAlien, self).update(seconds)
-
-    def collide_with_protagonist(self, protagonist):
-        protagonist.lose_health(15)
+        super(PatrollingAlien, self).update(dt)
 
     @classmethod
     def requires(cls):
@@ -216,7 +221,7 @@
         self._body.apply_impulse(
             (dx * self.impulse_factor, dy * self.impulse_factor))
 
-    def update(self, seconds):
+    def update(self, dt):
         # Calculate the step every frame
         # Distance to the protagonist
         pos = self._body.position
@@ -241,10 +246,7 @@
         if abs(y_step) < 0.5:
             y_step = 0
         self.set_direction(x_step, y_step)
-        super(ChargingAlien, self).update(seconds)
-
-    def collide_with_protagonist(self, protagonist):
-        protagonist.lose_health(20)
+        super(ChargingAlien, self).update(dt)
 
     @classmethod
     def requires(cls):
--- a/nagslang/events.py	Fri Sep 06 03:10:04 2013 +0200
+++ b/nagslang/events.py	Fri Sep 06 10:49:19 2013 +0200
@@ -63,6 +63,5 @@
 
 class ClawEvent(UserEvent):
     @classmethod
-    def post(cls, source, vector, source_collision_type):
-        super(ClawEvent, cls).post(source=source, vector=vector,
-                                   source_collision_type=source_collision_type)
+    def post(cls, source, vector, damage):
+        super(ClawEvent, cls).post(source=source, vector=vector, damage=damage)
--- a/nagslang/game_object.py	Fri Sep 06 03:10:04 2013 +0200
+++ b/nagslang/game_object.py	Fri Sep 06 10:49:19 2013 +0200
@@ -2,7 +2,6 @@
 import pymunk.pygame_util
 
 import math
-import time
 
 from nagslang import environment
 from nagslang import puzzle
@@ -111,6 +110,7 @@
 
     def __init__(self, physicser, renderer, puzzler=None, overlay=None,
                  interactible=None):
+        self.lifetime = 0
         self.physicser = physicser
         physicser.set_game_object(self)
         self.physicser.add_to_space()
@@ -147,8 +147,9 @@
     def render(self, surface):
         return self.renderer.render(surface)
 
-    def update(self, seconds):
-        self.renderer.update(seconds)
+    def update(self, dt):
+        self.lifetime += dt
+        self.renderer.update(dt)
 
     def hit(self, weapon):
         '''Was hit with a weapon (such as a bullet)'''
@@ -165,6 +166,9 @@
     def collide_with_furniture(self, furniture):
         return True
 
+    def collide_with_claw_attack(self, claw_attack):
+        return True
+
     @classmethod
     def requires(cls):
         """Hints for the level editor"""
@@ -364,8 +368,8 @@
         )
         self.physicser.apply_impulse(impulse)
 
-    def update(self, seconds):
-        super(Bullet, self).update(seconds)
+    def update(self, dt):
+        super(Bullet, self).update(dt)
         position = (self.physicser.position.x, self.physicser.position.y)
         r = self.get_space().segment_query(self.last_position, position)
         self.last_position = position
@@ -414,33 +418,22 @@
 
 
 class ClawAttack(GameObject):
-    def __init__(self, space, position, vector, source_collision_type):
-        body = make_body(1, pymunk.inf, position)
-        self.last_position = position
+    def __init__(self, space, position, vector, damage):
+        body = make_body(1, pymunk.inf, position + vector)
+        body.angle = vector.angle
         self.shape = pymunk.Circle(body, 30)
         self.shape.sensor = True
         self.shape.collision_type = COLLISION_TYPE_WEREWOLF_ATTACK
-        self.source_collision_type = source_collision_type
+        self.damage = damage
         super(ClawAttack, self).__init__(
             SingleShapePhysicser(space, self.shape),
-            render.ImageRenderer(resources.get_image
-                                ('objects', 'werewolf_SW_claw_attack.png')),
+            render.ImageRenderer(resources.get_image(
+                'objects', 'werewolf_SW_claw_attack.png',
+                transforms=(FLIP_H,))),
         )
-        self.time_created = time.time()
 
-    def update(self, seconds):
-        super(ClawAttack, self).update(seconds)
-        position = (self.physicser.position.x, self.physicser.position.y)
-        r = self.get_space().segment_query(self.last_position, position)
-        self.last_position = position
-        for collision in r:
-            shape = collision.shape
-            if (shape.collision_type == self.source_collision_type
-                    or shape == self.physicser.get_shape()
-                    or shape.sensor):
-                continue
-            if hasattr(shape, 'physicser'):
-                shape.physicser.game_object.hit(self)
-        if time.time() - self.time_created > 0.2:
+    def update(self, dt):
+        super(ClawAttack, self).update(dt)
+        if self.lifetime > 0.2:
             self.physicser.remove_from_space()
             self.remove = True
--- a/nagslang/protagonist.py	Fri Sep 06 03:10:04 2013 +0200
+++ b/nagslang/protagonist.py	Fri Sep 06 10:49:19 2013 +0200
@@ -6,7 +6,7 @@
 from nagslang.constants import (
     COLLISION_TYPE_PLAYER, ZORDER_MID, WEREWOLF_SOAK_FACTOR,
     PROTAGONIST_HEALTH_MIN_LEVEL, PROTAGONIST_HEALTH_MAX_LEVEL,
-    NON_GAME_OBJECT_COLLIDERS, COLLISION_TYPE_WEREWOLF_ATTACK)
+    NON_GAME_OBJECT_COLLIDERS, BULLET_DAMAGE, CLAW_DAMAGE)
 from nagslang.events import FireEvent, ClawEvent
 from nagslang.game_object import GameObject, Physicser, make_body
 from nagslang.mutators import FLIP_H
@@ -59,7 +59,6 @@
         self.health_level = 100
 
         self.go_human()
-        self._time = 0
 
     def _make_physics(self, space, position):
         body = make_body(10, pymunk.inf, position, 0.8)
@@ -262,15 +261,14 @@
         vec = Vec2d.unit()
         vec.angle = self.angle
         vec.length = 1000
-        FireEvent.post(self.physicser.position, vec, 10, COLLISION_TYPE_PLAYER)
+        FireEvent.post(
+            self.physicser.position, vec, BULLET_DAMAGE, COLLISION_TYPE_PLAYER)
 
     def claw(self):
         vec = Vec2d.unit()
         vec.angle = self.angle
-        vec.length = 100
-        ClawEvent.post(self.physicser.position, vec,
-                       COLLISION_TYPE_WEREWOLF_ATTACK)
-        print "Claw", self.physicser.position, vec
+        vec.length = 30
+        ClawEvent.post(self.physicser.position, vec, CLAW_DAMAGE)
 
     def in_wolf_form(self):
         return self.form == self.WOLF_FORM
@@ -310,9 +308,7 @@
             self.health_level = PROTAGONIST_HEALTH_MAX_LEVEL
 
     def update(self, dt):
-        last_secs = int(self._time)
-        self._time += dt
-        secs = int(self._time)
-        if self.form == self.WOLF_FORM and secs > last_secs:
-            self.gain_health(1)
+        if int(self.lifetime + dt) > int(self.lifetime):
+            if self.form == self.WOLF_FORM:
+                self.gain_health(1)
         super(Protagonist, self).update(dt)
--- a/nagslang/screens/area.py	Fri Sep 06 03:10:04 2013 +0200
+++ b/nagslang/screens/area.py	Fri Sep 06 10:49:19 2013 +0200
@@ -6,10 +6,10 @@
 
 from nagslang.constants import (
     COLLISION_TYPE_WALL, COLLISION_TYPE_PLAYER, CALLBACK_COLLIDERS,
-    COLLISION_TYPE_FURNITURE)
+    COLLISION_TYPE_FURNITURE, COLLISION_TYPE_WEREWOLF_ATTACK)
 from nagslang.enemies import DeadEnemy
-from nagslang.events import ScreenChange, DoorEvent, FireEvent, \
-    EnemyDeathEvent, ClawEvent
+from nagslang.events import (
+    ScreenChange, DoorEvent, FireEvent, EnemyDeathEvent, ClawEvent)
 from nagslang.level import Level
 from nagslang.screens.base import Screen
 from nagslang.game_object import Bullet, ClawAttack
@@ -93,9 +93,13 @@
         # The collision handler must return `True` or `False`. We don't want to
         # accidentally reject collisions from handlers that return `None`, so
         # we explicitly check for `False` and treate everything else as `True`.
-        if result is False:
-            return False
-        return True
+        return result is not False
+
+    def _claw_attack_collision_pre_solve_handler(self, space, arbiter):
+        claw = arbiter.shapes[0].physicser.game_object
+        gobj = arbiter.shapes[1].physicser.game_object
+        result = gobj.collide_with_claw_attack(claw)
+        return result is not False
 
     def _furniture_collision_pre_solve_handler(self, space, arbiter):
         furniture = arbiter.shapes[0].physicser.game_object
@@ -111,6 +115,9 @@
             self.space.add_collision_handler(
                 COLLISION_TYPE_FURNITURE, collision_type,
                 pre_solve=self._furniture_collision_pre_solve_handler)
+            self.space.add_collision_handler(
+                COLLISION_TYPE_WEREWOLF_ATTACK, collision_type,
+                pre_solve=self._claw_attack_collision_pre_solve_handler)
 
     def add_walls(self):
         self.walls = []
@@ -173,7 +180,7 @@
             self._drawables.add(dead_enemy)
         elif ClawEvent.matches(ev):
             claw_attack = ClawAttack(self.space, ev.source, ev.vector,
-                                     ev.source_collision_type)
+                                     ev.damage)
             self._drawables.add(claw_attack)
         self.keys.handle_event(ev)
 
@@ -234,11 +241,10 @@
             health_box_colour = pygame.color.THECOLORS['red']
         else:
             health_box_colour = pygame.color.THECOLORS['white']
-        pygame.draw.rect(surface,  health_box_colour, rect, 0)
+        pygame.draw.rect(surface, health_box_colour, rect, 0)
         if self.protagonist.in_human_form():
             health_colour = pygame.color.THECOLORS['red']
         else:
             health_colour = pygame.color.THECOLORS['purple']
         rect = pygame.Rect(55, 505, self.protagonist.get_health_level(), 40)
-        pygame.draw.rect(surface,  health_colour,
-                         rect, 0)
+        pygame.draw.rect(surface, health_colour, rect, 0)