Jump to content
  • Advertisement
Sign in to follow this  
Vegetable411

Allegro collision detection[fixed]

This topic is 4847 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been editing the code from this page: http://www.loomsoft.net/resources/alltut/alltut_lesson8.htm This is my edited code:
/*******************
Allegro Newbie Tutorial

by
LoomSoft

http://loomsoft.net
email: jay@loomsoft.net
*******************/
/* Allegro Newbie Tutorial : Lesson 8 - Bounding Box Collision Detection
 *
 * This tutorial will show you how to do a very simple implementation of
 * collision detection using bounding boxes. The user can move both images.
 *
 * Controls:
 * Up/Down/Left/Right : move image 1
 * A/W/S/D : move image 2
 * SPACE: draw bounding boxes.
 * ESC: exit
 *
 * This lesson also covers error checking when creating/loading bitmaps, 
 * drawing primitive lines, and displaying text. This is something new that 
 * was skipped in all the previous tutorials for simplicity. It is extremely 
 * good practice to do error checking for any function that allows you to do so.
 * 
 * We also learn about using the function: allegro_message.
 */

/* The include and timer setup, and allegro initialization. This is routine stuff! */
#include <allegro.h> // Include the allegro header file.
#include <stdlib.h> // Include the stdlib header for the exit() function.
#define LEFT 3
#define RIGHT 4
#define UP 5
#define DOWN 6
#define TOPL 7
#define TOPR 8
#define BOTL 9
#define BOTR 10
#define CROSS1 11
#define CROSS2 12
#define AIR 13

/* Timer stuff */
volatile long speed_counter = 0; //A long integer which will store the value of the
								 //speed counter.
void increment_speed_counter() // A function to increment the speed counter
{
	speed_counter++; // This will just increment the speed counter by one.
}
END_OF_FUNCTION(increment_speed_counter); //Make sure you tell it that it's the end of the
										  //function (allegro specific)

int main(int argc, char *argv[])
{
	allegro_init(); // Initialize Allegro
	install_keyboard(); // Initialize keyboard routines
	install_timer(); // Initialize the timer routines
	
	LOCK_VARIABLE(speed_counter); //Used to set the timer - which regulates the game's
	LOCK_FUNCTION(increment_speed_counter);//speed.
	install_int_ex(increment_speed_counter, BPS_TO_TIMER(60));//Set our BPS
			
	set_color_depth(16); // Set the color depth
			
	set_gfx_mode(GFX_AUTODETECT, 640,480,0,0); // Change our graphics mode to 640x480
			
	/* This bitmap is for double buffering. This is covered in a previous tutorial.
	 * However, this time, we do error checking - just to make sure the buffer was 
	 * actually created properly. This is something you'll always want to do, since 
	 * you can output an error and let the user know what didn't work!
	 */
	BITMAP *buffer = create_bitmap(640,480); // Create a buffer for smooth animation.
	
	/* We do a little test here to see if the bitmap was created. If the pointer is 
	 * NULL after calling create_bitmap, then that means it's not pointing to anything, 
	 * thus the create_bitmap did not work. 
	 */
	if(buffer == NULL)
	{
		/* Here's some new stuff. This sets up allegro to go into a text only mode. 
		 * This ensures that the message you want to display will be shown on any platform.
		 */
		set_gfx_mode(GFX_TEXT,0,0,0,0);
					
		/* This is a new function. It's called allegro_message. Obviously enough, 
		 * it outputs a message. 
		 */
		allegro_message("Error: Could not create buffer!");
					
		/* This function simply will stop the program since the buffer could not 
		 * be created we do not want to continue.
		 */
						
		exit(EXIT_FAILURE);
	}
				
	/* Here we load the two bitmap images which we want to test collision for.
	 * We test to see they were loaded correctly. If not, output an error message 
	 * and exit. This is important. If your images can't load, when you try to 
	 * blit them, your program will crash. Safely exiting is the better choice, by far!
	 */
	BITMAP *image1 = load_bitmap("image1.bmp", NULL);//Load image 1
	if(image1 == NULL)
	{
		set_gfx_mode(GFX_TEXT,0,0,0,0); //Set the screen mode for allegro messages
		allegro_message("Error: Could not load image1.bmp");
		exit(EXIT_FAILURE);
	}
				
	BITMAP *image2 = load_bitmap("image2.bmp", NULL); //Load image 2
	if(image2 == NULL)
	{
		set_gfx_mode(GFX_TEXT,0,0,0,0); //Set the screen mode for allegro messages
		allegro_message("Error: Could not load image2.bmp");
		exit(EXIT_FAILURE);
	}
					
	/* Next we're going to do a bit of variable declaring. First off, we're going 
	 * to want to know the x and y positions of both images.
	 */
	int image1_x_position = 0; //Set the x position of image 1 to 0.
	int image1_y_position = 0; //Set the y position of image 1 to 0.
	int image2_x_position = 0; //Set the x position of image 2 to 100.
	int image2_y_position = 416; //Set the y position of image 2 to 100.
									
	/* Next, we need to know where the bounding boxes are for these 
	 * images. This is going to be a little complicated:
	 * A box (2D square) has four sides, so we will need to have 4 variables. 
	 * Two y coordinates, and two x coordinates. 
	 * The two y coordinates will represent the top and bottom "sides" of the box, 
	 * while the x coordinates will represent the left and right "sides" of the box.
	 *
	 * For the purposes of this lesson, we will have the bounding box be the same 
	 * size as the image we are going to apply it to. So, lets set these variables. 
	 * We will need a total of 8. 4 for each image.
	 *
	 * Note - bb stands for bounding box
	 * Here we set the left side of the bounding box to Image 1's x position. 
	 * Why do we do this? Well, we want the bounding box to surround the image at all times, 
	 * so we have to set it to the images current position. The x position of the image just
	 * so happens to be the same x coordinate of the left side of the box.
	 */
	int image1_bb_left = image1_x_position;
									
	/* The same idea goes for the top "side" */
	int image1_bb_top = image1_y_position;
									
	/* Next we need to set the bottom and right "sides" of the box. Since we are going to
	 * use the bitmap's dimensions for the bounding boxes, this is simple. Since we don't want
	 * to have to keep track of the actual size of the image any time we change the image itself
	 * we can use a data member of the BITMAP structure to find out the width or height of 
	 * a bitmap image dynamically! We can do this using the pointer->w or pointer->h data members.
	 *	
	 * We know the width of the image. That is: (image1->w)
	 * If we have the left side of the box, well, the right side is just the image width away 
	 * from the left side.
	 */
	int image1_bb_right = (image1_bb_left + image1->w);
	
	/* Use the same idea for the bottom. */
	int image1_bb_bottom = (image1_bb_top + image1->h);
	
	/* Now, we will create the box for image 2 using the same principles. */
	int image2_bb_left = image2_x_position;
	int image2_bb_top = image2_y_position;
	int image2_bb_right = (image2_bb_left + image2->w);
	int image2_bb_bottom = (image2_bb_top + image2->h);
									
	/* This is just a variable to hold the value of whether we want to show the bounding boxes 
	 * or not. We'll see more about it later.
	 * When setting the initial value of this variable we will use an Allegro constant FALSE.
	 * There is also the constant TRUE. FALSE and TRUE are useful for doing variable testing,
	 * as they take away the ambiguity of doing something like 
	 *
	 * if(variable == 0)
	 */
	int show_bbox = FALSE;
	
	/* This is just a variable to hold the value of whether there is a collision taking 
	 * place or not. We'll see more about it later. 
	 */
	int collision = FALSE;
	
	/* Okay, now that we've set up all our variables, we need to make our loop. You've 
	 * seen this before; it should be familiar.
	 */
	while(!key[KEY_ESC]) // Keep going until we hit escape.
	{
		while(speed_counter > 0) // Do the logic loop while the speed counter is > 0.
		{
			/* Things get a little tricky in here. We want to be able to move both images. 
			 * The controls are described at the beginning of this lesson. Lets make some 
			 * statements to take care of moving the images.
			 *
			 * Notice how each test is a standalone "if" statement? This will allow for 
			 * diagonal movement without explicitly coding it in.
			 */

			/* Key checks for image1 */
			if((key[KEY_LEFT] && collision==FALSE) || (key[KEY_LEFT] && (collision==LEFT || collision==UP || collision==DOWN || collision==TOPL || collision==TOPR)))
				image1_x_position --; //Move image 1 left.
			
			if(key[KEY_RIGHT] && collision==FALSE || (key[KEY_RIGHT] && (collision==UP || collision==DOWN || collision==LEFT || collision==TOPL || collision==TOPR)))
				image1_x_position ++; //Move image 1 right.
			
			if((key[KEY_DOWN] && (collision==DOWN || collision==RIGHT || collision==LEFT)))
				image1_y_position ++; //Move image 1 down.

			if((key[KEY_UP] && (collision==UP || collision==LEFT || collision==RIGHT || collision==TOPL || collision==TOPR)))
				image1_y_position --; //Move image 1 up.
				
            if(collision!=UP || collision!=DOWN || collision!=LEFT || collision!=RIGHT || collision!=TOPL || collision!=TOPR || collision!=BOTL || collision!=BOTR)
             image1_y_position ++;
              
             

			/* Here's where we use show_bbox. 
             * If the space key is held down, it will show. Otherwise, it wont. 
			 * This only works when the space key is held down.
			 */
			if(key[KEY_SPACE])
				show_bbox = TRUE;
			
			else if(!key[KEY_SPACE])
				show_bbox = FALSE;

			/* Things get a little tricky here. Since the player can move the images, 
			 * we need to update the locations of the bounding boxes. Lets do it just
			 * like we did when we initialized them, using the same ideas and principles
			 */

			/* Update image 1's bounding box */
			image1_bb_left = image1_x_position;
			image1_bb_top = image1_y_position;
			image1_bb_right = (image1_bb_left + image1->w);
			image1_bb_bottom = (image1_bb_top + image1->h);

			/* Update image 2's bounding box. */
			image2_bb_left = image2_x_position;
			image2_bb_top = image2_y_position;
			image2_bb_right = (image2_bb_left + image2->w);
			image2_bb_bottom = (image2_bb_top + image2->h);

			/* Alright, so now we finally get to actually detecting collisions. 
			 * This could easily be written to it's own function, but I will flesh 
			 * it out in the logical loop for sake of keeping everything together.
			 *
			 * The way we check for collisions is simple. First, we assume there is no collision.
			 * Then we check to see if any corners of the first bounding box are inside or on the
			 * boundary of the second box. Next, we do the same for the second box: check to make
			 * sure none of its corners are inside or on the boundary of the first box. Then we 
			 * must take into account a special case where we have a "cross" pattern, where no
			 * corners are within another box, but there is still a collision.
			 */
			collision = FALSE; // Assume that there is no collision

			/* Notice the next chunk of if/else if statements. This chunk is
			 * for checking box 1 against box 2
			 */

			/* Test the top left corner of the first box to the second
			 * (Is the corner in or on the second box?)
			 */
			if(
			   ((image1_bb_left == image2_bb_right) && (image1_bb_top == image2_bb_bottom) )
			   )
			{
				collision = LEFT;
			}

			/* Test the top right corner of the first box to the second
			 * (Is the corner in or on the second box?)
			 */
			if(
					((image1_bb_right == image2_bb_left) && (image1_bb_top == image2_bb_bottom))
					)
			{
				collision = RIGHT;
			} 
			
			/* Test the bottom left corner of the first box to the second
			 * (Is the corner in or on the second box?)
			 */
			if(
					(image1_bb_top == image2_bb_bottom)
					)
			{
				collision = DOWN;
			}

			/* Test the bottom right corner of the first box to the second
			 * (Is the corner in or on the second box?)
			 */
			if(
					(image1_bb_bottom == image2_bb_top)
					)
			{
				collision = UP;
			}

			/* Now check to see if any corners of box two are inside or on the boundary 
			 * of box 1. This is good for cases where box 2 is much smaller than box 1
			 */

			/* Test the top left corner of the second box to the first box
			 * (Is the corner in or on the first box?)
			 */
			if(
			   (image2_bb_left >= image1_bb_left) && (image2_bb_top >= image1_bb_top) &&
			   (image2_bb_left <= image1_bb_right) && (image2_bb_top <= image1_bb_bottom)
			   )
			{
				collision = TOPL;
			}

			/* Test the top right corner of the second box to the first box
			 * (Is the corner in or on the second box?)
			 */
			else if(
					(image2_bb_right <= image1_bb_right) && (image2_bb_right >= image1_bb_left) &&
					(image2_bb_top >= image1_bb_top) && (image2_bb_top <= image1_bb_bottom)
				   )
			{
				collision = TOPR;
			}

			/* Test the bottom left corner of the second box to the first box
			 * (Is the corner in or on the second box?)
			 */
			else if(
					(image2_bb_right <= image1_bb_right) && (image2_bb_right >= image1_bb_left) &&
					(image2_bb_bottom <= image1_bb_bottom) && (image2_bb_bottom >= image1_bb_top)
				   )
			{
				collision = BOTL;
			}

			/* Test the bottom right corner of the second box to the first box
			 * (Is the corner in or on the second box?)
			 */
			else if(
					(image2_bb_right <= image1_bb_right) && (image2_bb_right >= image1_bb_left) &&
					(image2_bb_bottom <= image1_bb_bottom) && (image2_bb_bottom >= image1_bb_top)
				   )
			{
				collision = BOTR;
			}

			/* Now we must test for the cross pattern. */

			/* Check box 1 for a horizontal cross on box 2
			 * (This covers a vertical cross for box 2 on box 1)
			 */
			if(
			   (image1_bb_top > image2_bb_top) && (image1_bb_bottom < image2_bb_bottom) &&
			   (image2_bb_left > image1_bb_left) && (image2_bb_right < image1_bb_right)
			  )
			{
				collision = CROSS1;
			}

			/* Check box 2 for a horizontal cross on box 1
			 * (This covers veritcal cross for box 1 on box 2)
			 */
			if(
			   (image2_bb_top > image1_bb_top) && (image2_bb_bottom < image1_bb_bottom) &&
			   (image1_bb_left > image2_bb_left) && (image1_bb_right < image2_bb_right)
			  )
			{
				collision = CROSS2;
			}
			
			/* And we're done! */

			speed_counter --; // Decrement the speed counter.
		} // This is the closing bracket to the (speed_counter > 0) test.

		/* Time for the drawing stuff! */
		draw_sprite(buffer, image1, image1_x_position, image1_y_position); //Draw image1
		draw_sprite(buffer, image2, image2_x_position, image2_y_position); //Draw image2

		/* Here we do the drawing of the bounding box if the player is hitting space. */
		if(show_bbox == TRUE)
		{
			/* This uses the simple line drawing function of allegro.
			 * It should be quite self explanitory.
			 *
			 * line(BITMAP *bmp, int x1, int y1, int x2, int y2, int color);
			 *
			 * How we draw the box is quite simple. We draw four lines:
			 *
			 * A line from the left coordinate to the right coordinate with it's y 
			 * coordinate corrosponding to the top y coordinate.
			 *
			 * Another line with the same idea, except using the bottom y coordinate.
			 *
			 * A line from the top coordinate to the bottom coordinate with it's x 
			 * coordinate corrosponding to the left x coordinate.
			 *
			 * Another line with the same idea, except using the right x coordinate.
			 */
			
			/* Draw image1's bounding box. */
			line(buffer, image1_bb_left, image1_bb_top, image1_bb_right, image1_bb_top, makecol(255,0,0));
			line(buffer, image1_bb_left, image1_bb_bottom, image1_bb_right, image1_bb_bottom, makecol(255,0,0));
			line(buffer, image1_bb_left, image1_bb_top, image1_bb_left, image1_bb_bottom, makecol(255,0,0));
			line(buffer, image1_bb_right, image1_bb_top, image1_bb_right, image1_bb_bottom, makecol(255,0,0));

			/* Draw image2's bounding box. */
			line(buffer, image2_bb_left, image2_bb_top, image2_bb_right, image2_bb_top, makecol(255,0,0));
			line(buffer, image2_bb_left, image2_bb_bottom, image2_bb_right, image2_bb_bottom, makecol(255,0,0));
			line(buffer, image2_bb_left, image2_bb_top, image2_bb_left, image2_bb_bottom, makecol(255,0,0));
			line(buffer, image2_bb_right, image2_bb_top, image2_bb_right, image2_bb_bottom, makecol(255,0,0));
			
		}	/* Just the closing bracket... */

		/* Now, if there's a collision, we want to state it! */
		if(collision == TRUE)
		{
			/* This is the allegro text printing function. It prints text to the screen. 
			 * It's pretty self explanitory
			 *
			 * textprintf_ex(bitmap, font, x_pos, y_pos, color, transparency, "string", formatting stuff); It works just like C style printf.
			 */
			textprintf_ex(buffer, font, 0,0, makecol(255,255,255), -1, "Collision!");
		}

		/* Do the normal blitting of the buffer. */
		blit(buffer, screen, 0, 0, 0, 0, 640, 480);//Blit the buffer
		clear(buffer);//Clear the buffer
		release_screen();//Release the screen
	}
		
	/* Destroy bitmaps and quit. */
	destroy_bitmap(buffer);
	destroy_bitmap(image1);
	destroy_bitmap(image2);
	return 0;
}
END_OF_MAIN()




The horizontal collision works fine when I move up against the block manually, but when I try to get the code to force the image down into the block when the image is airborne, the image just moves right through the block. Any idea how I can fix this? Also, are there any free tutorials that will help me with collision detection in general? [Edited by - Vegetable411 on August 11, 2005 3:12:10 PM]

Share this post


Link to post
Share on other sites
Advertisement
Here's a pretty good article on collision detection for 2D games. That should get you started. http://www.gamedev.net/reference/articles/article735.asp

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!