Chronicles of a Videogame in Java – 5. Collision detection for dummies

Previously on the Chronicles of a Videogame in Java: Bulding a tiled map.

The code discussed below is already available on my GitHub page at theBoyWithNoName (“collisions” branch). Please feel free to download it to take a better look. Ask me anything about it.

Hi guys and welcome back to our beautiful journey through the development of a 2D platform-game in Java Swing. Today we’re gonna talk about collisions, maybe one of the trickiest topics in the making of a bidimensional game.

Before we start I want to make sure that you remember what a Block object is in my project. A Block object has two important features:

  • It is not movable.
  • It doesn’t involve interactions with the player whatsoever.

Pretty basic stuff. So how did I approach collisions with blocks in my code? Well, what we know is that there are essentially three cases in which you can collide with an immovable block in a 2D platform, and those are: you’re running left, running right or jumping/falling in the air. Now, remember those rectangles we built around each and every object of the game? The bounding boxes? Well, those rectangles are the foundation of collision detection. Here’s a simple picture that explains why:

collisionNoCollision

See the red rectangle around our chill protagonist? That’s his bounding box. The block object you see next to the main character in the picture above has its own bounding box, visually represented by a blue outline. If two bounding boxes intersect, a collision happens.

On the left you can see a situation where the character and the block do not collide. On the right side of the picture, instead, they are colliding pretty hard I’d say. And that’s a situation we don’t want to happen in the game. If the Character is running right and faces a Block object, his bounding box must never intersect the Block’s one.

Now let’s put it to code.

	public void checkBlockCollisions(){
		[...]
		//if last direction was right..
		if(last_direction==KeyEvent.VK_RIGHT){
			
			//get the left side of the bounding box
			int footX=(int)boundingBox.getMinX();
			
			//get the tile position (in the tiled map) 
			//relative to the tile in front of the character
			int tileInFrontOfFootRow=((footY-1)/Tile.TILE_SIZE);
			int tileInFrontOfFootCol=(footX/Tile.TILE_SIZE)+1;
			
			if(tileInFrontOfFootCol<World.COLS){
				//if the tile in front of the character contains a block..
				if(World.tiledMap[tileInFrontOfFootRow][tileInFrontOfFootCol] instanceof Block){
					//..and the character's bounding box intersect the block's one
					if(boundingBox.intersects(World.tiledMap[tileInFrontOfFootRow][tileInFrontOfFootCol].getBoundingBox())){
						//push the character away and re-set its position
						currentX-=DISPLACEMENT;
						boundingBox.setLocation(currentX, currentY);
						currentCol=currentX/Tile.TILE_SIZE;
					}
				}
				
				if(World.tiledMap[currentRow][currentCol] instanceof Block){
					//if the tile the character finds himself in contains a block, act like above
					if(boundingBox.intersects(World.tiledMap[currentRow][currentCol].getBoundingBox())){
						currentX-=DISPLACEMENT;
						boundingBox.setLocation(currentX, currentY);
						currentCol=currentX/Tile.TILE_SIZE;
					}
				}
			}
		} else {
			//the same thing you see above happens here for the left direction 
			[...]	
		}
	}

Notice that when the character runs left or right and his bounding box intersects a Block’s one, he’s pushed away of an amount of pixels equals to the number of pixels he covers with a single step (the DISPLACEMENT value). This way the character’s bounding box can never intersect the Block.

The code you see above works perfectly for side collisions, but it doesn’t help much if our little protagonist is jumping and slamming his head on a block that is placed above him.

As for jump collisions I had to rethink the jump mechanic I talked about in one of my previous posts. “How” you say? Well, first thing I did was splitting the ascending phase and the descending phase of the jump. In particular, when the character is going up we have that the jumping boolean is set to true and the falling is set to false. When the character is going down we have the opposite setting of those variables. To have a specific falling state is really helpful even in other situations: for example I can set it to true when the character doesn’t have a Block object under his feet. This way I can make character fall (increment y position) while falling=true. But collision-wise, we have that the character’s head can only collide if he’s in ascending phase. So here’s how I dealt with the problem:

		
		//if the character is jumping, his head must not touch a block;
		//if it touches a block, stop the ascending phase of the jump (start falling)
		if(jumping){
			
			//row position of the cell above the character's head (in the tiled map)
			int upRow=(int)((boundingBox.getMinY()-1)/Tile.TILE_SIZE);
			
			//tile position relative to the upper-left corner of the character's bounding box
			int upLeftCornerCol=(int)(boundingBox.getMinX()/Tile.TILE_SIZE);
			
			//tile position relative to the upper-right corner of the character's bounding box
			int upRightCornerCol=(int)((boundingBox.getMaxX())/Tile.TILE_SIZE);

			if(currentRow>=0){
				if(World.tiledMap[upRow][upLeftCornerCol] instanceof Block){
					//if the upper-left corner stats intersecting a block, stop the jumping phase
					//and start the falling phase, setting the jump_count to 0
					if(World.tiledMap[upRow][upLeftCornerCol].getBoundingBox().intersects(boundingBox)){
						jumping=false;
						jump_count=0;
						falling=true;
						return;
					}
				}
				if(World.tiledMap[upRow][upRightCornerCol] != null){
					//if the upper-right corner stats intersecting a block, stop the jumping phase
					//and start the falling phase, setting the jump_count to 0
					if(World.tiledMap[upRow][upRightCornerCol].getBoundingBox().intersects(boundingBox)){
						jumping=false;
						jump_count=0;
						falling=true;
						return;
					}
				}
			}
		
		}

This chunk of code you see above is still part of the checkBlockCollision() function we saw earlier, so now we have all the stuff we need to make the character move around the screen, jump on blocks, collide with blocks and well, even die…if he falls too deep.

Aaaaaaand that would be all for today’s diary. Once again, remember that this is not a proper tutorial, but just a “how I make things” kind of thing. So if you have suggestions or you don’t understand what I say, please comment below or get in touch with me on twitter. I’m also on tumblr, drawing stuff. See you soon guys!

Advertisements
Chronicles of a Videogame in Java – 5. Collision detection for dummies

3 thoughts on “Chronicles of a Videogame in Java – 5. Collision detection for dummies

  1. Good day I am so grateful I found your webpage, I really found
    you by mistake, while I was researching on Digg for something else, Regardless I am here
    now and would just like to say thank you for a tremendous post and a all round enjoyable blog (I also love the
    theme/design), I don’t have time to read through it all at the moment but
    I have book-marked it and also added your RSS
    feeds, so when I have time I will be back to read more, Please do
    keep up the excellent work.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s