Thread: Collision of two rects?

  1. #1
    60% Braindead
    Join Date
    Dec 2005
    Posts
    379

    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.
    Last edited by Blackroot; 09-09-2006 at 08:17 PM.

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Just a pedantic note . . .
    Code:
    #ifndef defs.h
    defs.h isn't a valid #define name.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    60% Braindead
    Join Date
    Dec 2005
    Posts
    379
    -,- Forgot the underscores.

  4. #4

  5. #5
    60% Braindead
    Join Date
    Dec 2005
    Posts
    379
    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?

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    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.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Yes, the rectangle outside a rectangle test is much easier.
    Then overlap is just !outside()
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Rect'm? It damn hear killed'm!


    Quzah.
    Hope is the first step on the road to disappointment.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Some collision handling fun
    By DavidP in forum Game Programming
    Replies: 9
    Last Post: 04-13-2008, 08:45 AM
  2. Collision Detection Problems
    By Dark_Phoenix in forum Game Programming
    Replies: 1
    Last Post: 12-17-2006, 03:25 PM
  3. Collision Detection
    By Grantyt3 in forum C++ Programming
    Replies: 3
    Last Post: 09-30-2005, 03:21 PM
  4. collision detection
    By DavidP in forum Game Programming
    Replies: 2
    Last Post: 05-11-2002, 01:31 PM
  5. Replies: 4
    Last Post: 05-03-2002, 09:40 PM