Changeset 627:35919d12b792


Ignore:
Timestamp:
05/07/11 18:28:06 (12 years ago)
Author:
Jeremy Thurgood <firxen@…>
Branch:
default
Phase:
public
Message:

Path-based collision minimisation and axis-projection backout.

Location:
skaapsteker
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • skaapsteker/physics.py

    r626 r627  
    1313from . import options
    1414from .constants import EPSILON
    15 from .utils import cadd, csub, cmul, cdiv, cclamp, cint, cneg, cabs
     15from .utils import (cadd, csub, cmul, cdiv, cclamp, cabsmax, cint, cneg, cabs,
     16                    rect_projection)
    1617
    1718class Sprite(pygame.sprite.Sprite):
     
    253254        return dt
    254255
     256
     257    # def collide_sprite(self, dt, sprite):
     258    #     sprite.apply_velocity(dt)
     259    #     sprite_collides = sprite.collide_rect.colliderect
     260    #     collisions = []
     261    #     for other in self._collision_groups[sprite.collision_layer]:
     262    #         if sprite_collides(other.collide_rect) \
     263    #                 and sprite.check_collides(other):
     264    #             collisions.append(other)
     265    #     if collisions:
     266    #         self._backout_collisions(sprite, collisions, dt)
     267    #     contact_rect = pygame.Rect(
     268    #         (sprite.collide_rect.left, sprite.collide_rect.bottom),
     269    #         (sprite.collide_rect.width, 1))
     270    #     return contact_rect.colliderect
     271
     272
     273    def get_sprite_collisions(self, dt, sprite):
     274        sprite.apply_velocity(dt)
     275        sprite_collides = sprite.collide_rect.colliderect
     276        collisions = []
     277        for other in self._collision_groups[sprite.collision_layer]:
     278            if (sprite_collides(other.collide_rect)
     279                and sprite.check_collides(other)):
     280                collisions.append(other)
     281        return collisions
     282
     283
     284    def path_collide(self, dt, sprite):
     285        dts = [dt/10] * 9
     286        dts.append(dt - sum(dts))
     287        dtf_acc = 0
     288        collisions = []
     289        for dtf in dts:
     290            dtf_acc += dtf
     291            collisions = self.get_sprite_collisions(dtf, sprite)
     292            for col in collisions:
     293                if sprite.block and (col.floor or col.block):
     294                    return collisions, dtf_acc
     295        return collisions, dt
     296
     297
     298    def collide_sprite(self, dt, sprite):
     299        initial_pos = sprite._float_pos
     300        collisions = self.get_sprite_collisions(dt, sprite)
     301        escape_vector = (0, 0)
     302        if collisions:
     303            # If we've collided, reset and try again with smaller time increments
     304            sprite.update_position(initial_pos)
     305            collisions, dtf = self.path_collide(dt, sprite)
     306            for col in collisions:
     307                if sprite.block and (col.floor or col.block):
     308                    escape_vector = cabsmax(escape_vector, rect_projection(sprite.collide_rect, col.collide_rect))
     309                sprite.collided(col)
     310            sprite.update_position(cadd(sprite._float_pos, escape_vector))
     311            # if escape_vector[0] != 0:
     312            #     sprite.velocity = (0, sprite.velocity[1])
     313            # if escape_vector[1] != 0:
     314            #     sprite.velocity = (sprite.velocity[0], 1)
     315            # self._backout_collisions(sprite, collisions, dtf)
     316        contact_rect = pygame.Rect(
     317            cadd(sprite.collide_rect.bottomleft, (1, 0)),
     318            (sprite.collide_rect.width, 1))
     319        return contact_rect.colliderect
     320
     321
    255322    def update_sprite_positions(self, dt):
    256323        # position update and collision check (do last)
    257324        for sprite in self._mobiles:
    258             sprite.apply_velocity(dt)
    259             sprite_collides = sprite.collide_rect.colliderect
    260             collisions = []
    261             for other in self._collision_groups[sprite.collision_layer]:
    262                 if sprite_collides(other.collide_rect) \
    263                         and sprite.check_collides(other):
    264                     collisions.append(other)
    265             if collisions:
    266                 self._backout_collisions(sprite, collisions, dt)
    267             contact_rect = pygame.Rect(
    268                     (sprite.collide_rect.left, sprite.collide_rect.bottom),
    269                     (sprite.collide_rect.width, 1))
    270             collides = contact_rect.colliderect
     325            collides = self.collide_sprite(dt, sprite)
     326
     327            # Are we currently in contact with the ground?
     328            if not sprite.block:
     329                continue
    271330            floors = []
    272 
    273             # Are we currently in contact with the ground?
    274331            sprite.on_solid = False
    275332            for other in self._collision_groups[sprite.collision_layer]:
    276333                if (other.floor or other.block) and collides(other.floor_rect):
    277334                    sprite.on_solid = True
     335                    if sprite.velocity[1] > 0:
     336                        sprite.velocity = (sprite.velocity[0], 0)
    278337                    floors.append(other)
    279338            sprite.check_floors(floors)
  • skaapsteker/sprites/player.py

    r623 r627  
    4242        self._inv_cache = {} # invisible fox image cache
    4343        self._shield_cache = {} # shielded fox image cache
    44         self._shield_image = 0 # shield image
    4544        # State flags and such
    4645        self.attacking = 0
     
    121120        # TODO: can save a lot of calculation here by caching collision rects
    122121        cand_image = images[int(self._animation_frame)]
    123         cand_collide_rect = cand_image.get_bounding_rect(1).inflate(-2,-2)
     122        # cand_collide_rect = cand_image.get_bounding_rect(1).inflate(-2,-2)
     123        cand_collide_rect = cand_image.get_bounding_rect(1)
    124124        cand_rect = cand_image.get_rect()
    125125        cand_rect_offset = cand_rect.centerx - cand_collide_rect.centerx, cand_rect.bottom - cand_collide_rect.bottom
  • skaapsteker/utils.py

    r619 r627  
    2828cdiv = mk_cop(operator.div)
    2929cclamp = mk_cop(lambda a, b: max(min(a, b), -b))
     30cabsmax = mk_cop(lambda a, b: a if abs(a) > abs(b) else b)
    3031
    3132cint = mk_cuop(int)
     
    3334cabs = mk_cuop(abs)
    3435
     36
     37def rect_projection(rect1, rect2):
     38    if not rect1.colliderect(rect2):
     39        # No collision?
     40        return (0, 0)
     41
     42    if rect1.center[0] < rect2.center[0]:
     43        x_projection = rect2.left - rect1.right
     44    else:
     45        x_projection = rect2.right - rect1.left
     46
     47    if rect1.center[1] < rect2.center[1]:
     48        y_projection = rect2.top - rect1.bottom
     49    else:
     50        y_projection = rect2.bottom - rect1.top
     51
     52    if abs(x_projection) < abs(y_projection):
     53        return (x_projection, 0)
     54    return (0, y_projection)
     55
Note: See TracChangeset for help on using the changeset viewer.