Rectangular Map Collisions

A simple collider class is provided called RectMapCollider. This collider is particularly useful in 2D side-scrolling platformers, or top-down dungeon crawlers, to control movement of the player.

It assumes that the cells within your tile map have the boolean properties "left", "right", "top" and "bottom" defined for those cells which are to be collidable. See Map, Cell and Tile Properties for information about properties.

A solid block would probably have all four sides set. A platform would usually only have the top set so the player might jump up from underneath and pass through.

For convenience these properties would typically be set ont he tiles themselves, rather than on individual cells. Of course for the cell which is the entrance to a secret area you could override a wall's properties to set the side to False and allow ingress.

The basic interface to RectMapCollider is to invoke collide_map to collide a single moving actor with a RectMapLayer.

You would typically override RectMapCollider to provide implementations of its collision methods, for example:

class PlayerCollider(tiles.RectMapCollider):
   def __init__(self, player):
       self.player = player

   def collide_bottom(self, dy):
       if self.player.dy:
           self.player.do_landed()

   def collide_left(self, dx):
       self.player.stop_walk()

   def collide_right(self, dx):
       self.player.stop_walk()

   def collide_top(self, dy):
       if self.player.dy:
           self.player.do_ouch()

Then you would instantiate the collider (possibly only once) passing in the object representing the player which manages the player's velocity (dx and dy). Once per update you would could something like:

collider = PlayerCollider(player)
dx, dy = player.velocity

# using the player controls, gravity and other acceleration influences
# update the velocity
dx = ...
dy = dy - gravity

# get the player's current bounding rectangle
last = player.get_rect()
new = last.copy()
new.x += dx
new.y += dy

# run the collider
collider.collide_map(map, last, new, dy, dx)

# move the player
player.position = new.position

Another approach which may be simpler is to mix the collider into your Player class, and then just provide those collide methods on your Player class.

A third approach is to create a cocos Action derivative which handles the player controls and collision. This is the approach taken in the test/test_platformer.py code.