changeset 93:d6a49f0c1e6e

Rectangular human protagonist shape, refactored physicsers.
author Jeremy Thurgood <firxen@gmail.com>
date Mon, 02 Sep 2013 11:10:50 +0200
parents 4c7e85906453
children 9ef5c5810dcd
files nagslang/game_object.py nagslang/protagonist.py nagslang/screens/area.py
diffstat 3 files changed, 77 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/nagslang/game_object.py	Mon Sep 02 08:47:05 2013 +0200
+++ b/nagslang/game_object.py	Mon Sep 02 11:10:50 2013 +0200
@@ -2,6 +2,7 @@
 
 import pygame
 import pymunk
+import pymunk.pygame_util
 
 from nagslang.constants import SWITCH_PUSHERS, COLLISION_TYPE_SWITCH
 
@@ -15,48 +16,62 @@
 
 
 class FloorSwitchPuzzler(Puzzler):
-    def __init__(self, shape):
-        self.shape = shape
+    def __init__(self, space, shape):
+        self._space = space
+        self._shape = shape
 
-    def get_state(self, space):
-        for shape in space.shape_query(self.shape):
+    def get_state(self):
+        for shape in self._space.shape_query(self._shape):
             if shape.collision_type in SWITCH_PUSHERS:
                 return True
         return False
 
 
 class Physicser(object):
-    def add_to_space(self, space):
+    def __init__(self, space):
+        self.space = space
+
+    def add_to_space(self):
         raise NotImplementedError()
 
-    def remove_from_space(self, space):
+    def remove_from_space(self):
         raise NotImplementedError()
 
-    def render_position(self, surface):
+    def get_render_position(self, surface):
         raise NotImplementedError()
 
-    def render_angle(self):
+    def get_angle(self):
+        raise NotImplementedError()
+
+    def apply_impulse(self, j, r=(0, 0)):
         raise NotImplementedError()
 
 
 class SingleShapePhysicser(Physicser):
-    def __init__(self, shape):
+    def __init__(self, space, shape):
+        super(SingleShapePhysicser, self).__init__(space)
         self._shape = shape
 
-    def add_to_space(self, space):
-        space.add(self._shape, self._shape.body)
+    def add_to_space(self):
+        self.space.add(self._shape)
+        if not self._shape.body.is_static:
+            self.space.add(self._shape.body)
 
-    def remove_from_space(self, space):
-        space.remove(self._shape, self._shape.body)
+    def remove_from_space(self):
+        self.space.remove(self._shape)
+        if not self._shape.body.is_static:
+            self.space.remove(self._shape.body)
 
-    def render_position(self, surface):
+    def get_render_position(self, surface):
         pos = self._shape.body.position
-        import pymunk.pygame_util
         return pymunk.pygame_util.to_pygame(pos, surface)
 
-    def render_angle(self):
+    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)
+
 
 class Renderer(object):
     def render(self, surface, pos, angle):
@@ -108,39 +123,39 @@
     This has a rendery thing, physicsy things and maybe some other things.
     """
 
-    def __init__(self, renderer, physicser, puzzler=None):
+    def __init__(self, physicser, renderer, puzzler=None):
+        self.physicser = physicser
+        self.physicser.add_to_space()
         self.renderer = renderer
-        self.physicser = physicser
         self.puzzler = puzzler
 
-    def add_to_space(self, space):
-        self.physicser.add_to_space(space)
+    def get_render_position(self, surface):
+        return self.physicser.get_render_position(surface)
+
+    def get_render_angle(self):
+        return self.physicser.get_angle()
 
     def render(self, surface):
         return self.renderer.render(
-            surface, self.physicser.render_position(surface),
-            self.physicser.render_angle())
+            surface, self.get_render_position(surface),
+            self.get_render_angle())
 
 
 class FloorSwitch(GameObject):
-    def __init__(self, position):
+    def __init__(self, space, position):
         body = pymunk.Body()
         body.position = position
         self.shape = pymunk.Circle(body, 30)
         self.shape.collision_type = COLLISION_TYPE_SWITCH
         self.shape.sensor = True
         super(FloorSwitch, self).__init__(
+            SingleShapePhysicser(space, self.shape),
             ShapeRenderer(self.shape),
-            SingleShapePhysicser(self.shape),
-            FloorSwitchPuzzler(self.shape),
+            FloorSwitchPuzzler(space, self.shape),
         )
 
-    def add_to_space(self, space):
-        # XXX: Hacky hack.
-        self._space = space
-
     def render(self, surface):
-        if self.puzzler.get_state(self._space):
+        if self.puzzler.get_state():
             self.shape.color = pygame.color.THECOLORS['green']
         else:
             self.shape.color = pygame.color.THECOLORS['red']
--- a/nagslang/protagonist.py	Mon Sep 02 08:47:05 2013 +0200
+++ b/nagslang/protagonist.py	Mon Sep 02 11:10:50 2013 +0200
@@ -17,26 +17,34 @@
     HUMAN_FORM = 'human'
     WOLF_FORM = 'wolf'
 
-    def __init__(self, position):
-        self._setup_physics(position)
+    def __init__(self, space, position):
+        self._setup_physics(space, position)
         self._setup_renderers()
         self.inventory = {}
         self.form = self.HUMAN_FORM
 
         super(Protagonist, self).__init__(
-            self._renderers[self.form], SingleShapePhysicser(self.shape))
+            self._physicsers[self.form], self._renderers[self.form])
 
         self.go_human()
 
-    def _setup_physics(self, position):
-        self._body = pymunk.Body(10, 10000)
+    def _setup_physics(self, space, position):
+        self._body = pymunk.Body(10, pymunk.inf)
         self._body.position = position
         self._body.velocity_func = self.velocity_func
 
-        self.shape = pymunk.Circle(self._body, 30)
-        self.shape.elasticity = 1.0
-        self.shape.friction = 10.0
-        self.shape.collision_type = COLLISION_TYPE_PLAYER
+        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),
+        }
+        self._physicsers = {}
+        for form, shape in self._shapes.iteritems():
+            shape.elasticity = 1.0
+            shape.friction = 10.0
+            shape.collision_type = COLLISION_TYPE_PLAYER
+            self._physicsers[form] = SingleShapePhysicser(space, shape)
+        self.angle = 0
 
     def _get_image(self, name, *transforms):
         return resources.get_image('creatures', name, transforms=transforms)
@@ -62,19 +70,24 @@
     def velocity_func(self, body, gravity, damping, dt):
         return pymunk.Body.update_velocity(body, gravity, self.damping, dt)
 
+    def get_render_angle(self):
+        return self.angle
+
     def go_werewolf(self):
+        self._physicsers[self.form].remove_from_space()
         self.form = self.WOLF_FORM
+        self._physicsers[self.form].add_to_space()
         self._body.mass = 100
-        self._body.moment = 10000
         self._body.velocity_limit = 1000
         self.impulse_factor = 4000
         self.damping = 0.9
         self.renderer = self._renderers[self.form]
 
     def go_human(self):
+        self._physicsers[self.form].remove_from_space()
         self.form = self.HUMAN_FORM
+        self._physicsers[self.form].add_to_space()
         self._body.mass = 10
-        self._body.moment = 1000
         self._body.velocity_limit = 1000
         self.impulse_factor = 500
         self.damping = 0.8
@@ -83,8 +96,7 @@
     def set_direction(self, dx, dy):
         if (dx, dy) == (0, 0):
             return
-        vec = pymunk.Vec2d((dx, dy))
-        self._body.angle = vec.angle
+        self.angle = pymunk.Vec2d((dx, dy)).angle
         self._body.apply_impulse(
             (dx * self.impulse_factor, dy * self.impulse_factor))
 
@@ -118,3 +130,7 @@
         if (dx, dy) == (0, 0):
             return
         self._body.apply_impulse((dx, dy))
+
+    def render(self, surface):
+        pymunk.pygame_util.draw(surface, self._shapes[self.form])
+        super(Protagonist, self).render(surface)
--- a/nagslang/screens/area.py	Mon Sep 02 08:47:05 2013 +0200
+++ b/nagslang/screens/area.py	Mon Sep 02 11:10:50 2013 +0200
@@ -53,10 +53,8 @@
         self.space.add(*self.walls)
 
     def add_protagonist(self):
-        self.protagonist = Protagonist((350, 300))
-        self.protagonist.add_to_space(self.space)
-        self.toy_switch = FloorSwitch((300, 400))
-        self.toy_switch.add_to_space(self.space)
+        self.protagonist = Protagonist(self.space, (350, 300))
+        self.toy_switch = FloorSwitch(self.space, (300, 400))
 
     def handle_event(self, ev):
         if ev.type == pygame.locals.KEYDOWN:
@@ -69,7 +67,7 @@
     def _calc_viewport(self, level_surface, display_surface):
         level_size = level_surface.get_size()
         display_size = display_surface.get_size()
-        protagnist_pos = self.protagonist.physicser.render_position(
+        protagnist_pos = self.protagonist.physicser.get_render_position(
                 level_surface)
         x_wide = display_size[0] // 2
         y_wide = display_size[1] // 2