changeset 122:51bcc909873d

Saner, buggier collision rectangles
author Neil Muller <drnlmuller@gmail.com>
date Mon, 04 Apr 2011 22:39:42 +0200
parents 5f5e43391395
children 592477d8b09b
files skaapsteker/physics.py skaapsteker/sprites/base.py skaapsteker/sprites/player.py
diffstat 3 files changed, 29 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/skaapsteker/physics.py	Mon Apr 04 22:37:59 2011 +0200
+++ b/skaapsteker/physics.py	Mon Apr 04 22:39:42 2011 +0200
@@ -37,6 +37,7 @@
         super(Sprite, self).__init__(*args, **kwargs)
         self.velocity = (0.0, 0.0)
         self.rect = pygame.Rect(0, 0, 10, 10) # sub-classes should override
+        self.collide_rect = pygame.Rect(0, 0, 10, 10) # rectangle we use for collisions
         self.image = pygame.Surface((10, 10))
         self.image.fill((0, 0, 200))
         self.visible = 1
@@ -50,7 +51,8 @@
         return self.debug_color
 
     def draw_debug(self, surface):
-        pygame.draw.rect(surface, self.get_debug_color(), self.rect, 1)
+        pygame.draw.rect(surface, (240, 0, 0), self.collide_rect, 1)
+        pygame.draw.rect(surface, self.get_debug_color(), self.collide_rect, 1)
 
     def deltaf(self, df):
         dv = df[0] / self.mass, df[1] / self.mass
@@ -67,12 +69,15 @@
         self.velocity = (v_x, v_y)
 
     def deltap(self, dt):
+        old_pos = self.rect.topleft
         v_x, v_y = self.velocity
         f_x, f_y = self._float_pos
         d_x, d_y = v_x * dt, v_y * dt
         f_x, f_y = f_x + d_x, f_y + d_y
         self._float_pos = f_x, f_y
         self.rect.topleft = int(f_x), int(f_y)
+        delta_pos = self.rect.left - old_pos[0], self.rect.top - old_pos[1]
+        self.collide_rect.move_ip(delta_pos)
 
     def check_collides(self, other):
         return True # default to relying purefly on collision_layer and collides_with
@@ -145,12 +150,12 @@
         self._collision_groups[layer] = pygame.sprite.Group()
 
     def _backout_collisions(self, sprite, others, dt):
-        frac, normal, idx = 0.0, None, None
+        frac, normal, idx = -1.0, None, None
         v_x, v_y = sprite.velocity
         abs_v_x, abs_v_y = abs(v_x), abs(v_y)
 
         for i, other in enumerate(others):
-            clip = sprite.rect.clip(other.rect)
+            clip = sprite.collide_rect.clip(other.collide_rect)
             # TODO: avoid continual "if abs_v_? > EPSILON"
             frac_x = clip.width / abs_v_x if abs_v_x > EPSILON else dt
             frac_y = clip.height / abs_v_y if abs_v_y > EPSILON else dt
@@ -183,7 +188,7 @@
         # position update and collision check (do last)
         for sprite in self._mobiles:
             sprite.deltap(dt)
-            sprite_collides = sprite.rect.colliderect
+            sprite_collides = sprite.collide_rect.colliderect
             collisions = []
             for other in self._collision_groups[sprite.collision_layer]:
                 if sprite_collides(other) and sprite.check_collides(other):
--- a/skaapsteker/sprites/base.py	Mon Apr 04 22:37:59 2011 +0200
+++ b/skaapsteker/sprites/base.py	Mon Apr 04 22:39:42 2011 +0200
@@ -27,6 +27,7 @@
         self.image = data.load_image('sprites/' + self.image_file)
         self.starting_tile_pos = pos
         self.rect = self.image.get_rect(topleft=(pos[0]*TILE_SIZE[0], pos[1]*TILE_SIZE[1]))
+        self.collide_rect = self.image.get_rect(topleft=(pos[0]*TILE_SIZE[0], pos[1]*TILE_SIZE[1]))
         self._layer = Layers.PLAYER
         self.setup(**opts)
 
@@ -57,7 +58,11 @@
         Sprite.__init__(self)
         self.tile_pos = pos
         self.image = image
-        self.rect = Rect((pos[0] * TILE_SIZE[0], pos[1] * TILE_SIZE[1]), TILE_SIZE)
+        self.collide_rect = self.image.get_bounding_rect(1)
+        self.rect = self.image.get_rect()
+        self.rect_offset = self.collide_rect.left - self.rect.left, self.rect.top - self.rect.top
+        self.collide_rect.topleft = pos[0] * TILE_SIZE[0] + self.rect_offset[0], pos[1] * TILE_SIZE[1] + self.rect_offset[1]
+        self.rect.topleft = pos[0] * TILE_SIZE[0], pos[1] * TILE_SIZE[1]
 
     def get_debug_color(self):
         if self.floor or self.block:
--- a/skaapsteker/sprites/player.py	Mon Apr 04 22:37:59 2011 +0200
+++ b/skaapsteker/sprites/player.py	Mon Apr 04 22:39:42 2011 +0200
@@ -18,6 +18,7 @@
     def __init__(self):
         Sprite.__init__(self)
         self.image = None
+        self.rect = None
         self._image_dict = {}
         self._animation_frame = 0.0
         # State flags and such
@@ -37,7 +38,17 @@
         images = self._image_dict[key]
         if self._animation_frame >= len(images):
             self._animation_frame = 0.0
+        if self.rect:
+            cur_pos = self.rect.topleft
+        else:
+            cur_pos = (0, 0)
         self.image = images[int(self._animation_frame)]
+        self.rect = self.image.get_rect()
+        self.collide_rect = self.image.get_bounding_rect(1)
+        self.rect_offset = self.collide_rect.left - self.rect.left, self.collide_rect.top - self.rect.top
+        self.rect.topleft = cur_pos
+        self.collide_rect.topleft = cur_pos[0] + self.rect_offset[0], cur_pos[1] + self.rect_offset[1]
+
 
     def update(self):
         v_x, v_y = self.velocity
@@ -51,10 +62,11 @@
     def set_facing(self, new_facing):
         self.facing = new_facing
 
+
     def set_pos(self, pos):
         self.starting_tile_pos = pos
-        self.rect = self.image.get_rect(topleft=(pos[0]*TILE_SIZE[0], pos[1]*TILE_SIZE[1]))
-        self.rect.inflate_ip(-10, -10)
+        self.collide_rect.topleft = pos[0] * TILE_SIZE[0] + self.rect_offset[0], pos[1] * TILE_SIZE[1] + self.rect_offset[1]
+        self.rect.topleft = pos[0] * TILE_SIZE[0], pos[1] * TILE_SIZE[1]
 
     def action_left(self):
         if self.facing != 'left':