changeset 215:325c317cbfa1

Better protagonist physicser.
author Jeremy Thurgood <firxen@gmail.com>
date Wed, 04 Sep 2013 13:13:11 +0200
parents d3d602a527bd
children f23ab2dd6ce8
files nagslang/game_object.py nagslang/protagonist.py
diffstat 2 files changed, 71 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/nagslang/game_object.py	Wed Sep 04 01:14:49 2013 +0200
+++ b/nagslang/game_object.py	Wed Sep 04 13:13:11 2013 +0200
@@ -25,19 +25,34 @@
         raise NotImplementedError()
 
     def add_to_space(self):
-        raise NotImplementedError()
+        shape = self.get_shape()
+        self.get_space().add(shape)
+        if not shape.body.is_static:
+            self.get_space().add(shape.body)
 
     def remove_from_space(self):
-        raise NotImplementedError()
+        shape = self.get_shape()
+        self.get_space().remove(shape)
+        if not shape.body.is_static:
+            self.get_space().remove(shape.body)
 
     def get_render_position(self, surface):
-        raise NotImplementedError()
+        pos = self.get_shape().body.position
+        return pymunk.pygame_util.to_pygame(pos, surface)
 
     def get_angle(self):
-        raise NotImplementedError()
+        return self.get_shape().body.angle
+
+    @property
+    def position(self):
+        return self.get_shape().body.position
+
+    @position.setter
+    def position(self, position):
+        self.get_shape().body.position = position
 
     def apply_impulse(self, j, r=(0, 0)):
-        raise NotImplementedError()
+        return self.get_shape().body.apply_impulse(j, r)
 
 
 class SingleShapePhysicser(Physicser):
@@ -49,26 +64,6 @@
     def get_shape(self):
         return self._shape
 
-    def add_to_space(self):
-        self.get_space().add(self._shape)
-        if not self._shape.body.is_static:
-            self.get_space().add(self._shape.body)
-
-    def remove_from_space(self):
-        self.get_space().remove(self._shape)
-        if not self._shape.body.is_static:
-            self.get_space().remove(self._shape.body)
-
-    def get_render_position(self, surface):
-        pos = self._shape.body.position
-        return pymunk.pygame_util.to_pygame(pos, surface)
-
-    def get_angle(self):
-        return self._shape.body.angle
-
-    def apply_impulse(self, j, r=(0, 0)):
-        return self._shape.body.apply_impulse(j, r)
-
 
 def damping_velocity_func(body, gravity, damping, dt):
     """Apply custom damping to this body's velocity.
--- a/nagslang/protagonist.py	Wed Sep 04 01:14:49 2013 +0200
+++ b/nagslang/protagonist.py	Wed Sep 04 13:13:11 2013 +0200
@@ -5,11 +5,27 @@
 
 from nagslang import render
 from nagslang.constants import COLLISION_TYPE_PLAYER, ZORDER_MID
-from nagslang.game_object import GameObject, SingleShapePhysicser, make_body
+from nagslang.game_object import GameObject, Physicser, make_body
 from nagslang.mutators import FLIP_H
 from nagslang.resources import resources
 
 
+class ProtagonistPhysicser(Physicser):
+    def __init__(self, space, form_shapes):
+        self._space = space
+        self._form_shapes = form_shapes
+
+    def switch_form(self, old_form, new_form):
+        self._space.remove(self._form_shapes[old_form])
+        shape = self._form_shapes[new_form]
+        self._space.add(shape)
+        for attr, value in shape.protagonist_body_props.iteritems():
+            setattr(shape.body, attr, value)
+
+    def get_shape(self):
+        return self._form_shapes[self.game_object.form]
+
+
 class Protagonist(GameObject):
     """Representation of our fearless protagonist.
 
@@ -22,39 +38,48 @@
     WOLF_FORM_BACK = 'wolf_back'
 
     def __init__(self, space, position):
-        self._setup_physics(space, position)
+        physicser = self._make_physics(space, position)
         self._setup_renderers()
         self.inventory = {}
         self.form = self.HUMAN_FORM
         self.render_form = self.HUMAN_FORM
 
         super(Protagonist, self).__init__(
-            self._physicsers[self.form], self._renderers[self.form])
+            physicser, self._renderers[self.form])
         self.zorder = ZORDER_MID
 
         self.go_human()
 
-    def _setup_physics(self, space, position):
-        self._body = make_body(10, pymunk.inf, position, 0.8)
+    def _make_physics(self, space, position):
+        body = make_body(10, pymunk.inf, position, 0.8)
+        body.velocity_limit = 1000
 
-        self._shapes = {
-            self.HUMAN_FORM: pymunk.Poly(
-                self._body, [(-15, -30), (15, -30), (15, 30), (-15, 30)]),
-            self.WOLF_FORM: pymunk.Circle(self._body, 30),
+        human = pymunk.Poly(body, [(-15, -30), (15, -30), (15, 30), (-15, 30)])
+        human.elasticity = 1.0
+        human.collision_type = COLLISION_TYPE_PLAYER
+        human.protagonist_body_props = {
+            'mass': 10,
+            'damping': 0.8,
         }
-        self._shapes[self.HUMAN_FORM].friction = 1.0
-        self._shapes[self.WOLF_FORM].friction = 0.05
-        self._physicsers = {}
-        for form, shape in self._shapes.iteritems():
-            shape.elasticity = 1.0
-            shape.collision_type = COLLISION_TYPE_PLAYER
-            self._physicsers[form] = SingleShapePhysicser(space, shape)
-        self.angle = 0
+
+        wolf = pymunk.Circle(body, 30)
+        wolf.elasticity = 1.0
+        wolf.collision_type = COLLISION_TYPE_PLAYER
+        wolf.protagonist_body_props = {
+            'mass': 100,
+            'damping': 0.9,
+        }
+
+        return ProtagonistPhysicser(space, {
+            self.HUMAN_FORM: human,
+            self.WOLF_FORM: wolf,
+        })
 
     def _get_image(self, name, *transforms):
         return resources.get_image('creatures', name, transforms=transforms)
 
     def _setup_renderers(self):
+        self.angle = 0
         self._renderers = {
             self.HUMAN_FORM: render.AnimatedFacingImageRenderer(
                 (self._get_image('human_1.png'),
@@ -124,14 +149,10 @@
         return self.angle
 
     def go_werewolf(self):
-        self._physicsers[self.form].remove_from_space()
+        self.physicser.switch_form(self.form, self.WOLF_FORM)
         self.form = self.WOLF_FORM
-        self._physicsers[self.form].add_to_space()
-        self.physicser = self._physicsers[self.form]
-        self._body.mass = 100
-        self._body.velocity_limit = 1000
         self.impulse_factor = 4000
-        self._body.damping = 0.9
+
         if self.render_form == self.HUMAN_FORM:
             self.render_form = self.WOLF_FORM
         elif self.render_form == self.HUMAN_FORM_BACK:
@@ -141,14 +162,10 @@
         self.renderer = self._renderers[self.render_form]
 
     def go_human(self):
-        self._physicsers[self.form].remove_from_space()
+        self.physicser.switch_form(self.form, self.HUMAN_FORM)
         self.form = self.HUMAN_FORM
-        self._physicsers[self.form].add_to_space()
-        self.physicser = self._physicsers[self.form]
-        self._body.mass = 10
-        self._body.velocity_limit = 1000
         self.impulse_factor = 500
-        self._body.damping = 0.8
+
         if self.render_form == self.WOLF_FORM:
             self.render_form = self.HUMAN_FORM
         elif self.render_form == self.WOLF_FORM_BACK:
@@ -186,23 +203,21 @@
                 self._switch_to_back()
             elif self.angle < 0 and old_angle != self.angle:
                 self._switch_to_front()
-        self._body.apply_impulse(
+        self.physicser.apply_impulse(
             (dx * self.impulse_factor, dy * self.impulse_factor))
         self.renderer.start()
 
     def set_position(self, position):
-        self._body.position = position
+        self.physicser.position = position
 
     def copy_state(self, old_protagonist):
-        self._physicsers[self.form].remove_from_space()
-        self._body.position = old_protagonist._body.position
+        self.physicser.position = old_protagonist.physicser.position
+        self.physicser.switch_form(self.form, old_protagonist.form)
         self.form = old_protagonist.form
         self.angle = old_protagonist.angle
         self.render_form = old_protagonist.render_form
         self.inventory = old_protagonist.inventory
         self.renderer = self._renderers[self.render_form]
-        self._physicsers[self.form].add_to_space()
-        self.physicser = self._physicsers[self.form]
 
     def toggle_form(self):
         if self.form == self.WOLF_FORM:
@@ -233,4 +248,4 @@
     def environmental_movement(self, dx, dy):
         if (dx, dy) == (0, 0):
             return
-        self._body.apply_impulse((dx, dy))
+        self.physicser.apply_impulse((dx, dy))