Collision detection with rotated and/or flipped bitmaps

I’ve been working on a game using the Gamebuino library and everything has gone well so far. I have now started the collision detection and I’ve come across a problem.

The API has a function:

gb.collideBitmapBitmap(x1,y1,bmp1,x2,y2,bmp2)

This is a pixel for pixel check to see if bmp1 and bmp2 have collided. However, I have been making use of the ability for drawBitmap() to rotate or flip the bitmaps when they are drawn. This has made animation very easy in some cases, as well as saving memory.

However, this collision check has no way of knowing that I have flipped or rotated the bitmaps and will compare the untransformed bitmaps.

Am I going to have to stop using rotate and flip in favor of having the actual bitmaps or is there a way around this I’m not seeing?

Thanks everyone!

My advice is to use the bounding box for collisions. This is much much faster, and the result is quite good. It depends on what you would like to collide though.

1 Like

Okay, thanks. I’ll give that a shot then.

Hey @jdoolin!

Taking a look at the gamebuino library code (link)… No… rotation does not work with the collideBitmapBitmap function :frowning:

But, I’m sure that with a bit (or lot) of time, you can make your own version of the function so it takes rotation into account :slight_smile:. That would be a nice contribution to the library repository, in my opinion, so if you I were you (and had the time, of course), I would give it a try :slight_smile:

1 Like

Ooooh, I like that idea. Methinks it’s time for a git clone.

1 Like

@jdoolin, @Tom and @ladbsoft have already answered your question quite good and fast.
I’m just asking whether you’ve made any progress on this? I would love to see that cool coding project of yours where you’re going to implement the rotation collision function :slight_smile:

I cloned the repository and started looking at the code. I determined that I either needed to write a second collision function that included the flip and rotation options, or to just write a transform function. After examining the code I decided the complexity (as in Big O) might not be worth pixel-perfect collision with rotation.

So for the time being I opted for @Tom’s option of using bounding boxes. Most of the collisions are with bullets, so I’m not using the actual bounding boxes of the bullets. I’m using their y position + 2 for the y position of the bounding box. That way the bullet has to overlap by two pixels before a collision, which on average makes up for the lack of pixel perfect collision.

I still want to make a change to the library however. Maybe version 2.0 of my game will use it.

As for the project itself, with a little more balancing it may be ready for release soon! It’s basically a port of the old Intellivision game Astrosmash that I’m currently calling MeteoSmash.

I’ve also got a port of Atlantis working.

If you are dealing with bullets (circles then), you can simply use the euclidian distance with the center of the bullet. This is fast and precise.

Check out the player file for collision. It should be easy for you pick it up amd use it

https://github.com/Duhjoker/Dune_esp32

A couple if statements should fix the rotation

/////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////collision/////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
bool checkcolision(void) // Transformed it into a function 
{
  for(uint16_t i=0; i < tft.numcolision + 1; i++)
  {
    if(tft.collideRectRect(player_x, player_y,16,16,tft.solid[i].x,tft.solid[i].y,16,16))
    {
        if(tft.solid[i].spritecol == bedtop)return true;
   else if(tft.solid[i].spritecol == bedbot)return true;
   else if(tft.solid[i].spritecol == bones11)return true;
   else if(tft.solid[i].spritecol == bones12)return true;
   else if(tft.solid[i].spritecol == bones13)return true;
   else if(tft.solid[i].spritecol == bones21)return true; 
   else if(tft.solid[i].spritecol == bones22)return true;
   else if(tft.solid[i].spritecol == bones23)return true;
   else if(tft.solid[i].spritecol == bookstop )return true;
   else if(tft.solid[i].spritecol == booksbot)return true; 
   else if(tft.solid[i].spritecol == cabtop)return true;
   else if(tft.solid[i].spritecol == cabbot)return true;
   else if(tft.solid[i].spritecol == cactus)return true;
   else if(tft.solid[i].spritecol == chimneytop)return true;
   else if(tft.solid[i].spritecol == chimneybot)return true;
   else if(tft.solid[i].spritecol == couchtop)return true;
   else if(tft.solid[i].spritecol == couchbot)return true;
   else if(tft.solid[i].spritecol == dish11)return true;
   else if(tft.solid[i].spritecol == dish12)return true;
   else if(tft.solid[i].spritecol == dish13)return true;
   else if(tft.solid[i].spritecol == dish21)return true;
   else if(tft.solid[i].spritecol == dish22)return true;
   else if(tft.solid[i].spritecol == dish23)return true;
   else if(tft.solid[i].spritecol == dish31)return true;
   else if(tft.solid[i].spritecol == dish32)return true;
   else if(tft.solid[i].spritecol == dish33)return true;
   else if(tft.solid[i].spritecol == dishv2)return true;
   else if(tft.solid[i].spritecol == machine1t)return true;
   else if(tft.solid[i].spritecol == machine1b)return true; 
   else if(tft.solid[i].spritecol == machine2t)return true;
   else if(tft.solid[i].spritecol == machine2b)return true;
   else if(tft.solid[i].spritecol == machine3t)return true;
   else if(tft.solid[i].spritecol == machine3b)return true;
   else if(tft.solid[i].spritecol == machine4t)return true;
   else if(tft.solid[i].spritecol == machine4b)return true;
   else if(tft.solid[i].spritecol == machine511)return true;
   else if(tft.solid[i].spritecol == machine512)return true;
   else if(tft.solid[i].spritecol == machine513)return true;
   else if(tft.solid[i].spritecol == machine521)return true;
   else if(tft.solid[i].spritecol == machine522)return true; 
   else if(tft.solid[i].spritecol == machine523)return true;
   else if(tft.solid[i].spritecol == machine531)return true;
   else if(tft.solid[i].spritecol == machine532)return true; 
   else if(tft.solid[i].spritecol == machine533)return true;
   else if(tft.solid[i].spritecol == machine611)return true;
   else if(tft.solid[i].spritecol == machine612)return true; 
   else if(tft.solid[i].spritecol == machine613)return true;
   else if(tft.solid[i].spritecol == machine621)return true;
   else if(tft.solid[i].spritecol == machine622)return true;
   else if(tft.solid[i].spritecol == machine623)return true;
   else if(tft.solid[i].spritecol == machine631)return true;
   else if(tft.solid[i].spritecol == machine632)return true;
   else if(tft.solid[i].spritecol == machine633)return true;
   else if(tft.solid[i].spritecol == mart)return true; 
   else if(tft.solid[i].spritecol == palmtl)return true;
   else if(tft.solid[i].spritecol == palmtr)return true;
   else if(tft.solid[i].spritecol == palmbl)return true;
   else if(tft.solid[i].spritecol == palmbr)return true;
   else if(tft.solid[i].spritecol == pot)return true;
   else if(tft.solid[i].spritecol == printerl)return true;
   else if(tft.solid[i].spritecol == printerr)return true;
   else if(tft.solid[i].spritecol == ptreetop)return true;
   else if(tft.solid[i].spritecol == ptreebot)return true;
   else if(tft.solid[i].spritecol == rocktopcap)return true;
   else if(tft.solid[i].spritecol == rockbotcap)return true;
   else if(tft.solid[i].spritecol == rockleftcap)return true;
   else if(tft.solid[i].spritecol == rockrightcap)return true;
   else if(tft.solid[i].spritecol == rockcornertl)return true;
   else if(tft.solid[i].spritecol == rockcornertr)return true;
   else if(tft.solid[i].spritecol == rockcornerbl)return true;
   else if(tft.solid[i].spritecol == rockcornerbr)return true;
   else if(tft.solid[i].spritecol == rockcornersharptl)return true;
   else if(tft.solid[i].spritecol == rockcornersharptr)return true;
   else if(tft.solid[i].spritecol == rockcornersharpbl)return true;
   else if(tft.solid[i].spritecol == rockcornersharpbr)return true;
   else if(tft.solid[i].spritecol == rockwalllc)return true;
   else if(tft.solid[i].spritecol == rockwallrc)return true;
   else if(tft.solid[i].spritecol == rockwall)return true;
   else if(tft.solid[i].spritecol == stonewall1)return true;
   else if(tft.solid[i].spritecol == stonewall2)return true;
   else if(tft.solid[i].spritecol == tablel)return true;
   else if(tft.solid[i].spritecol == tabler)return true;
   else if(tft.solid[i].spritecol == tablesm)return true;
   else if(tft.solid[i].spritecol == tank11 )return true;
   else if(tft.solid[i].spritecol == tank12)return true;
   else if(tft.solid[i].spritecol == tank21)return true;
   else if(tft.solid[i].spritecol == tank22)return true;
   else if(tft.solid[i].spritecol == tank31)return true;
   else if(tft.solid[i].spritecol == tank32)return true;
   else if(tft.solid[i].spritecol == tomb)return true;
   else if(tft.solid[i].spritecol == water)return true;
   else if(tft.solid[i].spritecol == register1)return true;
//////////////////////////////////////////////////////////////////////////////////////////// 
////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////Action Tiles/////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////////// top center rock formation
 else if((tft.solid[i].spritecol == area1exit1s) && room == 1){room = 4; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -0; cameraXMin = -2080; cameraYMin = -2144;}     /////101
 else if((tft.solid[i].spritecol == area1exit2e) && room == 1){room = 2; player_x = 122; player_y = 188; cameraX = -0; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}     /////102
//////////////////////////////////////////////////////////////////////////////////////////// 
 else if((tft.solid[i].spritecol == area2exit1w) && room == 2){room = 1; player_x = 122; player_y = 188; cameraX = -2080; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}  /////103
 else if((tft.solid[i].spritecol == area2exit2s) && room == 2){room = 5; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -0; cameraXMin = -2080; cameraYMin = -2144;}     /////104
 else if((tft.solid[i].spritecol == area2exit3e) && room == 2){room = 3; player_x = 122; player_y = 188; cameraX = -0; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}     /////105
//////////////////////////////////////////////////////////////////////////////////////////// 
 else if((tft.solid[i].spritecol == area3exit1w) && room == 3){room = 2; player_x = 122; player_y = 188; cameraX = -2080; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}  /////106
 else if((tft.solid[i].spritecol == area3exit2s) && room == 3){room = 6; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -0; cameraXMin = -2080; cameraYMin = -2144;}     /////107
////////////////////////////////////////////////////////////////////////////////////////////
 else if((tft.solid[i].spritecol == area4exit1n) && room == 4){room = 1; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -2144; cameraXMin = -2080; cameraYMin = -2144;}  /////108
 else if((tft.solid[i].spritecol == area4exit2s) && room == 4){room = 7; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -0; cameraXMin = -2080; cameraYMin = -2144;}     /////109
 else if((tft.solid[i].spritecol == area4exit3e) && room == 4){room = 5; player_x = 122; player_y = 188; cameraX = -0; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}     /////110
//////////////////////////////////////////////////////////////////////////////////////////// 
 else if((tft.solid[i].spritecol == area5exit1n) && room == 5){room = 2; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -2144; cameraXMin = -2080; cameraYMin = -2144;}  /////111
 else if((tft.solid[i].spritecol == area5exit2w) && room == 5){room = 4; player_x = 122; player_y = 188; cameraX = -2080; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}  /////112
 else if((tft.solid[i].spritecol == area5exit3s) && room == 5){room = 8; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -0; cameraXMin = -2080; cameraYMin = -2144;}     /////113
 else if((tft.solid[i].spritecol == area5exit4e) && room == 5){room = 6; player_x = 122; player_y = 188; cameraX = -0; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}     /////114
////////////////////////////////////////////////////////////////////////////////////////////
else if((tft.solid[i].spritecol == area6exit1n) && room == 6){room = 3; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -2144; cameraXMin = -2080; cameraYMin = -2144;}   /////115
else if((tft.solid[i].spritecol == area6exit2w) && room == 6){room = 5; player_x = 122; player_y = 188; cameraX = -2080; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}   /////116
else if((tft.solid[i].spritecol == area6exit3s) && room == 6){room = 9; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -0; cameraXMin = -2080; cameraYMin = -2144;}      /////117
////////////////////////////////////////////////////////////////////////////////////////////
else if((tft.solid[i].spritecol == area7exit1n) && room == 7){room = 4; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -2144; cameraXMin = -2080; cameraYMin = -2144;}   /////118
else if((tft.solid[i].spritecol == area7exit2e) && room == 7){room = 8; player_x = 122; player_y = 188; cameraX = -0; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}      /////119
////////////////////////////////////////////////////////////////////////////////////////////
else if((tft.solid[i].spritecol == area8exit1n) && room == 8){room = 5; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -2144; cameraXMin = -2080; cameraYMin = -2144;}   /////120
else if((tft.solid[i].spritecol == area8exit2w) && room == 8){room = 7; player_x = 122; player_y = 188; cameraX = -2080; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}   /////121
else if((tft.solid[i].spritecol == area8exit3e) && room == 8){room = 9; player_x = 122; player_y = 188; cameraX = -0; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}      /////122
///////////////////////////////////////////////////////////////////////////////////////////
else if((tft.solid[i].spritecol == area9exit1n) && room == 9){room = 6; player_x = 122; player_y = 188; cameraX = -1200; cameraY = -2144; cameraXMin = -2080; cameraYMin = -2144;}    /////123
else if((tft.solid[i].spritecol == area9exit2w) && room == 9){room = 8; player_x = 122; player_y = 188; cameraX = -2080; cameraY = -1200; cameraXMin = -2080; cameraYMin = -2144;}    /////124
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

As far as i know the rotation is taken care of in the bitmap function. So when you display it by calling the bitmap function the collision is still going to see the bitmap as a bitmap whether its rotated or flipped.

OMG, are you sure you want this series of “if”? Why not using a table? You initialize it once for all, then use “ bedtop”, “ bedbot”, etc. as indices. It will be much much faster.

Thats how i was taught. Willing to learn a new way if you have an example. Im still trying to learn c++ so im always up for new ways to do things.

What i need is to be able to set the same tile down in 3-4 places in the sane tilemap and be able to use it to do 3-4 different things.

As you can see im having to take my entrance/exit tiles and place an extra bitmap for each enteance/exit in my bitmap file to be able to stuff. This causes alot of my storage space to be used.

So say i need two exits in the same room it would be nice to only list the bitmap once and still be able to use it for more than one operation.

See world.h

Well, let’s say bedtop=0, bedbot=1 and so on. Then you need a table like
table[bedtop]=true, table[bedbot]=true, … table[bedbot] = false, …

then: table[tft.solid[i].spritecol] == true for all the lines in the first part of your code.

That’s a first step. But looking at your code, you can do something better, without a table. You can insert another element between register1 and area1exit2e, like “solid”. Then
if (tft.solid[i].spritecol < stop) return true
else => second part

Then I am unsure what restrictions you have to not use the same bitmap several times.