# Collision of two rects?

• 09-09-2006
Blackroot
Collision of two rects?
Hey, I'm trying to make a recreation of breakout for a little practice with images. I'm doing pritty well, but my collision detection is not working quite right. It detects for X collisions fine, but my Y collision algorithim does not work.

I wrote my collision algorithim out in psuedocode:
Check if the ball's y plus half the ball's height is less than or equal to the rects y plus the rects height.
And check if the ball's y minus half the ball's height is greater than or equal to the rects y minus the rects height.

Heres the collision code:

Code:

``` if(BALL_INFO.x < 0) {   if(BALL_INFO.x - BALL_INFO.width <= PAD_INFO[0].x) {   if(BALL_INFO.y + (BALL_INFO.height / 2) <= PAD_INFO[0].y + (PAD_INFO[0].height / 2) && BALL_INFO.y - (BALL_INFO.height / 2)  >= PAD_INFO[0].y - (PAD_INFO[0].height / 2))     BALL_INFO.x = PAD_INFO[0].x + BALL_INFO.width;     BALL_INFO.dx = BeginX;   }  }```
Heres the entire program (Lots of stuff is from the forgers tutorial, with some changes.

Code:

```#include <windows.h> #ifndef defs.h  #include "defs.h" #endif HBITMAP ScreenDisplay_Object = NULL; HBITMAP gBALL = NULL; HBITMAP gPAD1 = NULL; HBITMAP gPAD2 = NULL; const char g_szClassName[] = "myWindowClass"; const int BeginX = -10; const int BeginY = 0; const int ID_TIMER = 1; typedef struct _BALLINFO {  int width;  int height;  int x;  int y;  int dx;  int dy; }BALLINFO; BALLINFO  BALL_INFO; BALLINFO PAD_INFO[1]; int CPI = 0; void Bumprect(RECT* prc) {  if(BALL_INFO.x < 0) {   BALL_INFO.x = 0;   BALL_INFO.dx = BeginX;   if(BALL_INFO.dy < 82)   BALL_INFO.dy+= BeginY;   else   if(BALL_INFO.dy > -82 && BALL_INFO.dy <= 0)     BALL_INFO.dy-=BeginY;  } else   if(BALL_INFO.x + BALL_INFO.width >= prc->right) {   BALL_INFO.x = prc->right - BALL_INFO.width;   BALL_INFO.dx = -BeginX;   }  if(BALL_INFO.y < 0) {   BALL_INFO.y = 0;   BALL_INFO.dy = BeginY;   if(BALL_INFO.dx < 82 && BALL_INFO.dx >= 0)   BALL_INFO.dx+=BeginX;   else   if(BALL_INFO.dx > -82 && BALL_INFO.dy <= 0)     BALL_INFO.dx-=BeginY;  } else   if(BALL_INFO.y + BALL_INFO.height >= prc->bottom) {   BALL_INFO.y = prc->bottom - BALL_INFO.height;   BALL_INFO.dy = -BeginY;   } } void BumpPaddle() {  if(BALL_INFO.x < 0) {   if(BALL_INFO.x - BALL_INFO.width <= PAD_INFO[0].x) {   if(BALL_INFO.y + (BALL_INFO.height / 2) <= PAD_INFO[0].y + (PAD_INFO[0].height / 2) && BALL_INFO.y - (BALL_INFO.height / 2)  >= PAD_INFO[0].y - (PAD_INFO[0].height / 2))   BALL_INFO.x = PAD_INFO[0].x + BALL_INFO.width;   BALL_INFO.dx = BeginX;   }  }  if(BALL_INFO.x >= 0) {   if(BALL_INFO.x + BALL_INFO.width >= PAD_INFO[1].x) {   BALL_INFO.x = PAD_INFO[1].x - BALL_INFO.width;   BALL_INFO.dx = -BeginX;   }  } } void UpdateBall(RECT* prc) {  BALL_INFO.x += BALL_INFO.dx;  BALL_INFO.y += BALL_INFO.dy;  Bumprect(prc);  BumpPaddle(); } void DrawBall(HDC hdc, RECT* rct) { //More preporely, this could just as well be called Draw  HDC hdcBuffer = CreateCompatibleDC(hdc);  HBITMAP hbmNew = CreateCompatibleBitmap(hdc, rct->right, rct->bottom);  HBITMAP hbmOldBuffer = (HBITMAP)SelectObject(hdcBuffer, hbmNew);  HDC hdcMem = CreateCompatibleDC(hdc);  HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, gBALL);  FillRect(hdcBuffer, rct, (HBRUSH)GetStockObject(BLACK_BRUSH));  HDC hdcMem2 = CreateCompatibleDC(hdc);  HBITMAP hbmOld2 = (HBITMAP)SelectObject(hdcMem2, gPAD1);  HDC hdcMem3 = CreateCompatibleDC(hdc);  HBITMAP hbmOld3 = (HBITMAP)SelectObject(hdcMem3, gPAD2);  BitBlt(hdcBuffer, BALL_INFO.x, BALL_INFO.y, BALL_INFO.width, BALL_INFO.height, hdcMem, 0, 0, SRCAND);  SelectObject(hdcMem, gBALL);  BitBlt(hdcBuffer, BALL_INFO.x, BALL_INFO.y, BALL_INFO.width, BALL_INFO.height, hdcMem, 0, 0, SRCPAINT);  //Paddle 1  BitBlt(hdcBuffer, PAD_INFO[0].x, PAD_INFO[0].y, PAD_INFO[0].width, PAD_INFO[0].height, hdcMem2, 0, 0, SRCAND);  SelectObject(hdcMem2, gPAD1);  BitBlt(hdcBuffer, PAD_INFO[0].x, PAD_INFO[0].y, PAD_INFO[0].width, PAD_INFO[0].height, hdcMem2, 0, 0, SRCPAINT);  //Paddle 2  BitBlt(hdcBuffer, PAD_INFO[1].x, PAD_INFO[1].y, PAD_INFO[1].width, PAD_INFO[1].height, hdcMem3, 0, 0, SRCAND);  SelectObject(hdcMem3, gPAD2);  BitBlt(hdcBuffer, PAD_INFO[1].x, PAD_INFO[1].y, PAD_INFO[1].width, PAD_INFO[1].height, hdcMem3, 0, 0, SRCPAINT);  //Render everything  BitBlt(hdc, 0, 0, rct->right, rct->bottom, hdcBuffer, 0, 0, SRCCOPY);  SelectObject(hdcMem, hbmOld);  DeleteDC(hdcMem);  SelectObject(hdcMem2, hbmOld2);  DeleteDC(hdcMem);  SelectObject(hdcMem3, hbmOld3);  DeleteDC(hdcMem);  SelectObject(hdcBuffer, hbmOldBuffer);  DeleteDC(hdcBuffer);  DeleteObject(hbmNew); } void DrawPaddle(HDC hdc, HWND hwnd) {  BITMAP bm;  PAINTSTRUCT ps;  HDC hdcMem = CreateCompatibleDC(hdc);  HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, ScreenDisplay_Object);  GetObject(ScreenDisplay_Object, sizeof(bm), &bm);  BitBlt(hdc, PAD_INFO[CPI].x, PAD_INFO[CPI].y, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);  SelectObject(hdcMem, hbmOld); //81  DeleteDC(hdcMem);    EndPaint(hwnd, &ps); } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {  switch(msg) {   case WM_CLOSE:   DestroyWindow(hwnd);   break;   case WM_DESTROY:   DeleteObject(ScreenDisplay_Object);   PostQuitMessage(0);   break;   case WM_CREATE: {   BITMAP bm;   gBALL = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BALL));   if(gBALL == NULL)     MessageBox(hwnd, "Could not load object!", "Error!", MB_OK | MB_ICONEXCLAMATION);   GetObject(gBALL, sizeof(bm), &bm);   ZeroMemory(&BALL_INFO, sizeof(gBALL));   BALL_INFO.width = bm.bmWidth;   BALL_INFO.height = bm.bmHeight;   BALL_INFO.dx = BeginX;   BALL_INFO.dy = BeginY;   BALL_INFO.x = 377;   BALL_INFO.y = 260;   gPAD1 = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PAD1));   ScreenDisplay_Object = gPAD1;   if(gPAD1 == NULL)     MessageBox(hwnd, "Could not load object!", "Error!", MB_OK | MB_ICONEXCLAMATION);     GetObject(gPAD1, sizeof(bm), &bm);   ZeroMemory(&PAD_INFO[0], sizeof(gPAD1));   PAD_INFO[0].width = bm.bmWidth;   PAD_INFO[0].height = bm.bmHeight;   PAD_INFO[0].x = 0;   PAD_INFO[0].y = 260;   gPAD2 = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PAD2));   ScreenDisplay_Object = gPAD2;   if(gPAD2 == NULL)     MessageBox(hwnd, "Could not load object!", "Error!", MB_OK | MB_ICONEXCLAMATION);     GetObject(gPAD2, sizeof(bm), &bm);   ZeroMemory(&PAD_INFO[1], sizeof(gPAD2));   PAD_INFO[1].width = bm.bmWidth;   PAD_INFO[1].height = bm.bmHeight;   PAD_INFO[1].x = 755;   PAD_INFO[1].y = 260;   SetTimer(hwnd, ID_TIMER, 45, NULL);   }   break;   case WM_TIMER: {   RECT rcClient;   HDC hdc = GetDC(hwnd);   GetClientRect(hwnd, &rcClient);   ScreenDisplay_Object = gBALL;   UpdateBall(&rcClient);   DrawBall(hdc, &rcClient);   ReleaseDC(hwnd, hdc);   }   break;   default:   return DefWindowProc(hwnd, msg, wParam, lParam);  }  return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {  WNDCLASSEX wc;  HWND hwnd;  MSG Msg;  wc.cbSize        = sizeof(WNDCLASSEX);  wc.style        = 0;  wc.lpfnWndProc  = WndProc;  wc.cbClsExtra    = 0;  wc.cbWndExtra    = 0;  wc.hInstance    = hInstance;  wc.hIcon        = LoadIcon(NULL, IDI_APPLICATION);  wc.hCursor      = LoadCursor(NULL, IDC_ARROW);  wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);  wc.lpszMenuName  = NULL;  wc.lpszClassName = g_szClassName;  wc.hIconSm      = LoadIcon(NULL, IDI_APPLICATION);  if(!RegisterClassEx(&wc)) {   MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK);   return 0;  }  hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, g_szClassName, "PONG!", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, NULL, NULL, hInstance, NULL);  if(hwnd == NULL) {   MessageBox(NULL, "Window Creation Failed!", "Error!",   MB_ICONEXCLAMATION | MB_OK);   return 0;  }  ShowWindow(hwnd, nCmdShow);  UpdateWindow(hwnd);  while(GetMessage(&Msg, NULL, 0, 0) > 0) {   TranslateMessage(&Msg);   DispatchMessage(&Msg);  }  return Msg.wParam; }```
Basicaly this creates a ball that gets sent to the left, and it should collide with the first paddle (0)... But it doesnt, it just goes straight into the first paddle. Bah, damn my poor applied math skills -,-.

Anyone see why this doesnt collide proporely?

(Also as an offnote, is there any way to more efficiently render my scene? It seems to me I'm creating far to many hdcs, when only two should be needed for double buffering, but the hdc doesnt seem to like having several instances refer to it with select object.
• 09-09-2006
dwks
Just a pedantic note . . .
Code:

`#ifndef defs.h`
defs.h isn't a valid #define name.
• 09-09-2006
Blackroot
-,- Forgot the underscores.
• 09-09-2006
Tonto
• 09-11-2006
Blackroot
Personal, I'm hopelessly lost in my applied mathmaitcs. But because of that, I tend to avoid using math functions until I understand them.

So, I came up with this instead of my above version (And this one works ^^)
Code:

```BOOL Collide(int I) {  int BALLRECT[3];  int PADRECT[3];  BALLRECT[0] = BALL_INFO.x + (BALL_INFO.width / 2);        //Right  BALLRECT[1] = BALL_INFO.x - (BALL_INFO.width / 2);        //Left  BALLRECT[2] = BALL_INFO.y - (BALL_INFO.height / 2);        //Bottom  BALLRECT[3] = BALL_INFO.y + (BALL_INFO.height / 2);        //Top  PADRECT[0] = PAD_INFO[I].x + (PAD_INFO[I].width / 2);        //Right  PADRECT[1] = PAD_INFO[I].x - (PAD_INFO[I].width / 2);        //Left  PADRECT[2] = PAD_INFO[I].y - (PAD_INFO[I].height / 2);        //Bottom  PADRECT[3] = PAD_INFO[I].y + (PAD_INFO[I].height / 2);        //Top  if(BALLRECT[0] < PADRECT[1] || BALLRECT[1] > PADRECT[0] ||     BALLRECT[3] < PADRECT[2] || BALLRECT[2] > PADRECT[3])   return false;  else   return true; } void BumpPaddle() {  if(Collide(0) == 1) {   BALL_INFO.x = PAD_INFO[0].x + BALL_INFO.width;   BALL_INFO.dx = -BeginX;  }  if(Collide(1) == 1) {   BALL_INFO.x = PAD_INFO[1].x - BALL_INFO.width;   BALL_INFO.dx = +BeginX;  } }```
Alot bigger, but it works :P. But I still dont understand my function didint. It did basicaly the same thing... didint it?
• 09-11-2006
VirtualAce
Collision of rectangles can be done by reversing what you have done. Instead of testing for all points inside, it takes less tests to test for all points outside.
• 09-11-2006
Salem
Yes, the rectangle outside a rectangle test is much easier.
Then overlap is just !outside()
• 09-11-2006
quzah
Rect'm? It damn hear killed'm!

Quzah.