2D Platforming with Pygame

I’ve designed a simple platformer engine with Pygame that incorporates some (basic) physics and collision detection.

Overall View

How It Works

The algorithm works by applying x and y velocities to moving objects (like the player) in two discrete steps. This resolves instances in which the player approaches a platform from a diagonal and it becomes unclear which side of the platform should have a collision. The update method below is a member of the class for the Player entity. It handles input and tells the player entity to check for collisions.

def update(self, up, down, left, right, platforms):
		if up:
			# only jump if on the ground
			if self.onGround: self.yvel -= 7
		if down:
			pass
		if left:
			self.xvel = -5
		if right:
			self.xvel = 5
		if not self.onGround:
			# only accelerate with gravity if in the air
			self.yvel += 0.3
			# max falling speed
			if self.yvel > 30: self.yvel = 30
		if not(left or right):
			self.xvel = 0
		# increment in x direction
		self.rect.left += self.xvel
		# do x-axis collisions
		self.collide(self.xvel, 0, platforms)
		# increment in y direction
		self.rect.top += self.yvel
		# assuming we're in the air
		self.onGround = False;
		# do y-axis collisions
		self.collide(0, self.yvel, platforms)

The collide method checks for collisions against every other collidable element or platform. This means a downside in breaking collision detection down into separate x- and y-dimension checks is that we’ve essentially halved our performance — we’re checking everything twice.

def collide(self, xvel, yvel, platforms):
		for p in platforms:
			if sprite.collide_rect(self, p):
				if isinstance(p, ExitBlock):
					event.post(event.Event(QUIT))
				if xvel > 0: self.rect.right = p.rect.left
				if xvel < 0: self.rect.left = p.rect.right
				if yvel > 0:
					self.rect.bottom = p.rect.top
					self.onGround = True
					self.yvel = 0
				if yvel < 0: self.rect.top = p.rect.bottom

Optimizations

We can tell from line 2 in the above code block that I'm lazily checking for collisions against every possible platform. A potential optimization to this affront to Computer Science is to use "static buckets". Buckets work by dividing the game area into a grid. The simplest example would be to use a two by two grid. Upon initializing the level we would divide each of the collidable elements into one of the four grid square or "buckets". Then, when checking for collisions, we only check the bucket that the Player is currently in. Assuming a uniform distribution of platforms, we've reduced our necessary work by about three-quarters!

Such an approach seems promising but it really breaks down when testing collisions for elements that can move from bucket to bucket because we have to continually recalculate bucket membership. There are a few other approaches outlined in this excellent article that I intend on trying with my platforming engine and doing some benchmarks.

Full code listing available here. Requires Python and Pygame to run.

This entry was posted in Games Programming, Programming, Python. Bookmark the permalink.

2 Responses to 2D Platforming with Pygame

  1. I haven’t checked in here for a while because I thought it was getting boring, but the last few posts are good quality so I guess I’ll add you back to my daily bloglist :)

  2. RylandAlmanza says:

    Hi, I’m working on a platformer game which started using your code, and then I expanded it adding things like walljumps and such. Now, I’m starting it over in c++, and I was wondering if you could help me with my collision detection. Perhaps you could get in touch with me via email?

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>