Thread: My pong game stops painting

  1. #1
    Banned SniperSAS's Avatar
    Join Date
    Aug 2005
    Posts
    175

    My pong game stops painting

    I wrote a pong game in windows, I am like half way done. I have encountered a problem i have been trying to solve for hours, so maybe you guys can help me.


    Code:
    #include <windows.h>
    #include <time.h>
    #include <cstdlib>
    
    
    const char g_szClassName[] = "myWindowClass";
    
    
    struct hball{ int xslope; int yslope; int xpos; int ypos; int upleftx; 
    int uplefty; int bottomrightx; int bottomrighty; int size; int dir; int diry; };
    
    struct paddle{ int xpos; int length; int ypos;};
    
    paddle paddle1;
    paddle paddle2;
    
    HDC OFFSCRN;
    HDC SCREEN;
    HPEN ppen = CreatePen(PS_SOLID, 3, RGB(255, 255, 255));
    HPEN bpen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    HPEN ballpen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
    HBRUSH bbrush = CreateSolidBrush(RGB(0, 0, 0));
    HBRUSH wbrush = CreateSolidBrush(RGB(255, 255, 255));
    RECT brect;
    RECT urect;
    HBITMAP offscreenbm;
    HBITMAP screenbm;
    PAINTSTRUCT ps;
    int currtick;
    int oldtick;
    int newtick;
    bool gamestart;
    
    HFONT font = CreateFont( 0, 0, 0, 0, 700, FALSE, FALSE, FALSE, 0, 
    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, 
    NULL); 
        
    hball ball;
    
    
    // Step 4: the Window Procedure
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        if(ball.ypos >= 400) { ball.diry = 2; }
        if(ball.ypos <= 5) { ball.diry = 1; }
        
        if(ball.xpos == paddle1.xpos)
                {
                    if(ball.ypos == paddle1.ypos)
                    {
                         ball.dir == 2;
                    }
                }
        if(ball.xpos == paddle2.xpos)
                {
                    if(ball.ypos == paddle2.ypos)
                    {
                         ball.dir == 1;
                    }
                }
        if(ball.dir == 1) { ball.xpos = ball.xpos - ball.xslope; }
        if(ball.dir == 2) { ball.xpos = ball.xpos + ball.xslope; }
        if(ball.diry == 1) { ball.ypos = ball.ypos + ball.yslope; }
        if(ball.diry == 2) { ball.ypos = ball.ypos - ball.yslope; }
        ball.upleftx = ball.xpos;
        ball.uplefty = ball.ypos;
        ball.bottomrightx = ball.xpos - ball.size;
        ball.bottomrighty = ball.ypos - ball.size;
        newtick = GetTickCount();
        currtick = newtick - oldtick;
        if(currtick >= 2) 
        {
            oldtick = GetTickCount();
            RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
        }
        switch(msg)
        {
            case WM_CLOSE:
                DestroyWindow(hwnd);
            break;
            case WM_DESTROY:
                PostQuitMessage(0);
            break;
            case WM_KEYDOWN:
                 switch(wParam)
                 {
                               case VK_UP:
                                    paddle1.ypos = paddle1.ypos - 6;
                               break;
                               case VK_DOWN:
                                    paddle1.ypos = paddle1.ypos + 6;
                               break;
                               case 13:
                                    gamestart = true;
                                    
                               break;
                 }
            break;
            case WM_PAINT:
                
                //  Sizing hdcs and bitmaps to the screen so it will draw to the whole
                //  windows client area
                GetClientRect(hwnd, &brect);
                OFFSCRN = CreateCompatibleDC(GetDC(hwnd));
                SCREEN = CreateCompatibleDC(GetDC(hwnd));
                offscreenbm = CreateCompatibleBitmap(GetDC(hwnd), brect.right, brect.bottom);
                screenbm = CreateCompatibleBitmap(GetDC(hwnd), brect.right, brect.bottom);
                
                SCREEN = BeginPaint(hwnd, &ps);
                SelectObject(OFFSCRN, offscreenbm);
                SelectObject(SCREEN, screenbm);
    
                //Prepare to draw the background
                SelectObject(OFFSCRN, bpen);
                SelectObject(OFFSCRN, bbrush);
                
                //Draw the background
                Rectangle(OFFSCRN, brect.left, brect.top, brect.right, brect.bottom);
                
                //Prepare to draw the board
                SelectObject(OFFSCRN, ballpen);
                
                //Draw the board
                Rectangle(OFFSCRN, 5, 5, 700, 400);
                MoveToEx(OFFSCRN, 350, 5, NULL);
                LineTo(OFFSCRN, 350, 400);
                
                //Prepare to draw the paddles
                SelectObject(OFFSCRN, ppen);
                SelectObject(OFFSCRN, bbrush);
                
                //Paddle 1
                MoveToEx(OFFSCRN, paddle1.xpos, paddle1.ypos + paddle1.length / 2, NULL);
                LineTo(OFFSCRN, paddle1.xpos, paddle1.ypos - paddle1.length);
                
                //Paddle 2
                MoveToEx(OFFSCRN, paddle2.xpos, paddle2.ypos + paddle2.length / 2, NULL);
                LineTo(OFFSCRN, paddle2.xpos, paddle2.ypos - paddle2.length);
                
                //Ball
                SelectObject(OFFSCRN, wbrush);
                SelectObject(OFFSCRN, ballpen);
                Ellipse(OFFSCRN, ball.upleftx, ball.uplefty, ball.bottomrightx, ball.bottomrighty);
                if(gamestart == false)
                {
                     SelectObject(OFFSCRN, font);
                     TextOut(OFFSCRN, 290, 190, "Hit <Enter> to start!", 21);
                }
                BitBlt(SCREEN, 0, 0, brect.right, brect.bottom, OFFSCRN, 0, 0, SRCCOPY);     
                ReleaseDC(hwnd, OFFSCRN);
                ReleaseDC(hwnd, SCREEN);
                EndPaint(hwnd, &ps);
            break;
            default:
                return DefWindowProc(hwnd, msg, wParam, lParam);
                RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); 
                break;
        }
        return 0;
    }
    
    MSG Msg;
    WNDCLASSEX wc;
    HWND hwnd;
    
    
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
    {
        time_t seconds;
        time(&seconds);
        srand((unsigned int) seconds);
        
        ball.yslope = rand() % (1 - 7);
        ball.dir = 1;
        ball.diry = 2;
        ball.xslope = 5;
        
        paddle1.xpos     = 20;
        paddle1.ypos     = 197;
        paddle1.length   = 45;
        
        paddle2.xpos     = 680;
        paddle2.ypos     = 197;
        paddle2.length   = 46;
        
        ball.xpos = 347;
        ball.ypos = 197;
        ball.size = 10;
        
        ball.xslope = 1;
        ball.upleftx = ball.xpos - (ball.size / 2);
        ball.uplefty = ball.ypos - (ball.size / 2);
        
        ball.bottomrightx = ball.xpos + ball.size;
        ball.bottomrighty = ball.ypos + ball.size;
        
        // Registering the Window Class
        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)(COLOR_WINDOW+1);
        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;
        }
    
        
        
        
        // Creating the Window
        hwnd = CreateWindowEx(
            WS_EX_CLIENTEDGE,
            g_szClassName,
            "Pong",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, 750, 510,
            NULL, NULL, hInstance, NULL);
    
        if(hwnd == NULL)
        {
            MessageBox(NULL, "Window Creation Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
    
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
    
        
        
        oldtick = GetTickCount();
        
        
        
        // The Message Loop
        while(GetMessage(&Msg, hwnd, 0, 0) > 0)
        {
            PeekMessage(&Msg, hwnd, 0, 0, 0);
            TranslateMessage(&Msg);
            DispatchMessage(&Msg);
        }
    return Msg.wParam;    
    }
    I am running Dev-C++ 4.9.9.2. If you compile this code, you will see what i am talking about. It stops drawing, and even if you minimize it and reopen it, a WM_PAINT message isn't sent.

    Any ideas?

  2. #2
    Registered User Queatrix's Avatar
    Join Date
    Apr 2005
    Posts
    1,342
    I get those same problems and use the same compiler as you.
    It normaly happends when I send any kind of painting message over and over in a loop.
    I think your problem is a memory leak. (I may be wrong though.)

  3. #3
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    There is some strange stuff in that code. I would suggest moving to a peek-based message loop first of all. It should look something like:

    Code:
    MSG mssg;
    
            
    // prime the message structure PeekMessage( &mssg, NULL, 0, 0, PM_NOREMOVE); // run till completed while (mssg.message!=WM_QUIT) { // is there a message to process? if (PeekMessage( &mssg, NULL, 0, 0, PM_REMOVE)) { // dispatch the message TranslateMessage(&mssg); DispatchMessage(&mssg); } else { // Game stuff happens here!
    } }



    You should put your logic and rendering in that else clause and remove it from your wndproc. You can, of course, leave the handling of keydown messages to move paddles there if you like, or you could add a HandleInput function and asynchronously check keystate info with
    Code:
    SHORT GetAsyncKeyState(int vKey);
    This is how I would do it, it will be much more organized and also faster cause you aren't posting messages and rendering sometimes which is probably something to do with your stalling. I would just start a reorganize now. If you start it and get stuck, just post back here and I or someone else will assist you.

    EDIT:
    Also, what's going on here? You have code in the top of your wndproc in two places that look like this:

    Code:
    if(ball.ypos == paddle1.ypos)
    {
      ball.dir == 2;
    }
    Probably don't want comparison there as it would have no effect on anything.

    Also you have quite a few resource leaks. Remember when you create something you need to delete it! You have a lot of trouble in your WM_PAINT handler. You call GetDC when you need an hdc parameter to a function, that's bad. That's a resource leak you can never fix. Anytime you call GetDC you need to have an accompanying ReleaseDC. So call it once when you first need it, use the variable, then call release when you're done. When you call CreateCompatibleDC you don't release those, you call DeleteDC for them. Get / Release , Create / Delete. Try to keep that in mind. I'll continue posting in this edit section the more I run across.
    Last edited by MrWizard; 11-17-2005 at 01:51 PM.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  4. #4
    Banned SniperSAS's Avatar
    Join Date
    Aug 2005
    Posts
    175
    Yeah I am not done and there is a bunch of code in there from stuff I was just testing out since I was just doing this to get better, sorry about that.

    I am going to try what you guys suggested though.

  5. #5
    Banned SniperSAS's Avatar
    Join Date
    Aug 2005
    Posts
    175
    Okay, I think i did what you said to do properly, but I am still getting the same problem.


    Code:
    #include <windows.h>
    #include <time.h>
    #include <cstdlib>
    
    
    const char g_szClassName[] = "myWindowClass";
    
    
    struct hball{ int xslope; int yslope; int xpos; int ypos; int upleftx; 
    int uplefty; int bottomrightx; int bottomrighty; int size; int dir; int diry; int speed; };
    
    struct paddle{ int xpos; int length; int ypos; int speed;};
    
    paddle paddle1;
    paddle paddle2;
    
    HDC OFFSCRN;
    HDC SCREEN;
    HDC dc;
    HPEN ppen = CreatePen(PS_SOLID, 3, RGB(255, 255, 255));
    HPEN bpen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    HPEN ballpen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
    HBRUSH bbrush = CreateSolidBrush(RGB(0, 0, 0));
    HBRUSH wbrush = CreateSolidBrush(RGB(255, 255, 255));
    RECT brect;
    RECT urect;
    HBITMAP offscreenbm;
    HBITMAP screenbm;
    PAINTSTRUCT ps;
    bool gamestart;
    
    HFONT font = CreateFont( 0, 0, 0, 0, 700, FALSE, FALSE, FALSE, 0, 
    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, 
    NULL); 
        
    hball ball;
    
    
    // Step 4: the Window Procedure
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    
        switch(msg)
        {
            case WM_CLOSE:
                DestroyWindow(hwnd);
                DeleteDC(OFFSCRN);
                DeleteDC(SCREEN);
            break;
            case WM_DESTROY:
                PostQuitMessage(0);
            break;
            case WM_PAINT:
                
                //  Sizing hdcs and bitmaps to the screen so it will draw to the whole
                //  windows client area
                dc = GetDC(hwnd);
                GetClientRect(hwnd, &brect);
                OFFSCRN = CreateCompatibleDC(dc);
                SCREEN = CreateCompatibleDC(dc);
                offscreenbm = CreateCompatibleBitmap(dc, brect.right, brect.bottom);
                screenbm = CreateCompatibleBitmap(dc, brect.right, brect.bottom);
                
                SCREEN = BeginPaint(hwnd, &ps);
                SelectObject(OFFSCRN, offscreenbm);
                SelectObject(SCREEN, screenbm);
    
                //Prepare to draw the background
                SelectObject(OFFSCRN, bpen);
                SelectObject(OFFSCRN, bbrush);
                
                //Draw the background
                Rectangle(OFFSCRN, brect.left, brect.top, brect.right, brect.bottom);
                
                //Prepare to draw the board
                SelectObject(OFFSCRN, ballpen);
                
                //Draw the board
                Rectangle(OFFSCRN, 5, 5, 700, 400);
                MoveToEx(OFFSCRN, 350, 5, NULL);
                LineTo(OFFSCRN, 350, 400);
                
                //Prepare to draw the paddles
                SelectObject(OFFSCRN, ppen);
                SelectObject(OFFSCRN, bbrush);
                
                //Paddle 1
                MoveToEx(OFFSCRN, paddle1.xpos, paddle1.ypos + paddle1.length / 2, NULL);
                LineTo(OFFSCRN, paddle1.xpos, paddle1.ypos - paddle1.length);
                
                //Paddle 2
                MoveToEx(OFFSCRN, paddle2.xpos, paddle2.ypos + paddle2.length / 2, NULL);
                LineTo(OFFSCRN, paddle2.xpos, paddle2.ypos - paddle2.length);
                
                //Ball
                SelectObject(OFFSCRN, wbrush);
                SelectObject(OFFSCRN, ballpen);
                Ellipse(OFFSCRN, ball.upleftx, ball.uplefty, ball.bottomrightx, ball.bottomrighty);
                if(gamestart == false)
                {
                     SelectObject(OFFSCRN, font);
                     TextOut(OFFSCRN, 290, 190, "Hit <Enter> to start!", 21);
                }
                BitBlt(SCREEN, 0, 0, brect.right, brect.bottom, OFFSCRN, 0, 0, SRCCOPY);     
                DeleteDC(OFFSCRN);
                DeleteDC(SCREEN);
                ReleaseDC(hwnd, dc);
                EndPaint(hwnd, &ps);
    
            break;
            default:
                return DefWindowProc(hwnd, msg, wParam, lParam);
                break;
        }
        return 0;
    }
    
    MSG Msg;
    WNDCLASSEX wc;
    HWND hwnd;
    
    
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
    {
        time_t seconds;
        time(&seconds);
        srand((unsigned int) seconds);
        
        ball.yslope      = rand() % (1 - 7);
        ball.dir         = 1;
        ball.diry        = 2;
        ball.xslope      = 5;
        
        paddle1.xpos     = 20;
        paddle1.ypos     = 197;
        paddle1.length   = 45;
        paddle1.speed    = 3;
        
        paddle2.xpos     = 680;
        paddle2.ypos     = 197;
        paddle2.length   = 46;
        paddle2.speed    = 3;
        
        ball.xpos        = 347;
        ball.ypos        = 197;
        ball.size        = 10;
        
        ball.xslope      = 1;
        ball.upleftx     = ball.xpos - (ball.size / 2);
        ball.uplefty     = ball.ypos - (ball.size / 2);
        
        ball.bottomrightx= ball.xpos + ball.size;
        ball.bottomrighty= ball.ypos + ball.size;
        
        gamestart = false;
        
        // Registering the Window Class
        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)(COLOR_WINDOW+1);
        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;
        }
    
        
        
        
        // Creating the Window
        hwnd = CreateWindowEx(
            WS_EX_CLIENTEDGE,
            g_szClassName,
            "Pong",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, 750, 510,
            NULL, NULL, hInstance, NULL);
    
        if(hwnd == NULL)
        {
            MessageBox(NULL, "Window Creation Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
        
        PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE);
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
    
        // The Message Loop
        while(Msg.message != WM_QUIT)
        {
            if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
            {
    	         TranslateMessage(&Msg);
    	         DispatchMessage(&Msg);
            }
            else
            {
                  if(ball.ypos >= 400) { ball.diry = 2; }
                  if(ball.ypos <= 5) { ball.diry = 1; }
                  if(ball.xpos == paddle1.xpos)
                  {
                       if(ball.ypos == paddle1.ypos)
                       {
                            ball.dir == 2;
                       }
                  }
                  if(ball.xpos == paddle2.xpos)
                  {
                       if(ball.ypos == paddle2.ypos)
                       {
                         ball.dir == 1;
                       }
                  }
                  if(ball.dir == 1) { ball.xpos = ball.xpos - ball.xslope; }
                  else if(ball.dir == 2) { ball.xpos = ball.xpos + ball.xslope; }
                  if(ball.diry == 1) { ball.ypos = ball.ypos + ball.yslope; }
                  else if(ball.diry == 2) { ball.ypos = ball.ypos - ball.yslope; }
                  ball.upleftx = ball.xpos;
                  ball.uplefty = ball.ypos;
                  ball.bottomrightx = ball.xpos - ball.size;
                  ball.bottomrighty = ball.ypos - ball.size;int ballhandle(); 
                  if(GetAsyncKeyState(VK_UP) < 0) { paddle1.ypos = paddle1.ypos - paddle1.speed; }
                  else if(GetAsyncKeyState(VK_DOWN) < 0) {paddle1.ypos = paddle1.ypos + paddle1.speed; }
                  else if(GetAsyncKeyState(VK_RETURN) < 0) { gamestart = true; }
                  RedrawWindow(hwnd, 0, 0, RDW_INVALIDATE);
                  if(GetAsyncKeyState(VK_UP) < 0) { paddle1.ypos = paddle1.ypos - paddle1.speed; }
                  else if(GetAsyncKeyState(VK_DOWN) < 0) {paddle1.ypos = paddle1.ypos + paddle1.speed; }
                  else if(GetAsyncKeyState(VK_RETURN) < 0) { gamestart = true; }
                  RedrawWindow(hwnd, 0, 0, RDW_INVALIDATE);
            }
        }
    return Msg.wParam;    
    }

    Edit: Also thanks for the good way to handle keyboard input, this feels alot smoother then the way I had.
    Last edited by SniperSAS; 11-19-2005 at 08:14 PM.

  6. #6
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
    #include <time.h>
    #include <cstdlib>
    What language are you using?
    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.

  7. #7
    Banned SniperSAS's Avatar
    Join Date
    Aug 2005
    Posts
    175
    I need them for random, though. Do you think that is what is making it lock up?

  8. #8
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    No, no, no. In C++, you include the old C headers by dropping the .h and adding a C prefix:
    Code:
    /* C */
    #include <time.h>
    Code:
    /* C++ */
    #include <ctime>
    I was just wondering, because you have a C++ header file (<cstdlib>) and a C one (<time.h>). You should probably change <time.h> to <ctime>.
    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.

  9. #9
    Banned SniperSAS's Avatar
    Join Date
    Aug 2005
    Posts
    175
    Oh, read about that in the c++ primer but didn't think it mattered, haha.

  10. #10
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Few things I have noticed. Take the code out of your WM_PAINT message and turn that into a function called something like RenderScene. Then call that from your message loop. In your WM_PAINT handler just call BeginPaint followed immediately by EndPaint. Also, you redraw your window twice in the loop, don't know why you do this. You also check input twice which seems unnecessary.

    You create a DC called SCREEN but then you overwrite it when you call BeginPaint. BeginPaint returns the current device context for the window. So you don't need to call GetDC(hwnd), because BeginPaint will give it to you. You also need to call DeleteObject for those bitmaps you are creating. Try to clean it up some more and post what you have. I don't have time right now to go into more detail, but this should push you a few more steps in the right direction. So you won't call RedrawWindow at all, just Render scene which you will draw everything to your back buffer like you are doing now, and then blt to the main dc at the end. You won't need to call Begin/End paint in your RenderScene, a GetDC / ReleaseDC for your main hwnd will suffice.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  11. #11
    Banned SniperSAS's Avatar
    Join Date
    Aug 2005
    Posts
    175
    I must be doing it wrong or something. It's not painting at all now.

    Code:
    #include <windows.h>
    #include <ctime>
    #include <cstdlib>
    
    
    const char g_szClassName[] = "myWindowClass";
    
    
    struct hball{ int xslope; int yslope; int xpos; int ypos; int upleftx; 
    int uplefty; int bottomrightx; int bottomrighty; int size; int dir; int diry; int speed; };
    
    struct paddle{ int xpos; int length; int ypos; int speed;};
    
    paddle paddle1;
    paddle paddle2;
    
    HDC OFFSCRN;
    HDC SCREEN;
    HDC dc;
    HPEN ppen = CreatePen(PS_SOLID, 3, RGB(255, 255, 255));
    HPEN bpen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    HPEN ballpen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
    HBRUSH bbrush = CreateSolidBrush(RGB(0, 0, 0));
    HBRUSH wbrush = CreateSolidBrush(RGB(255, 255, 255));
    RECT brect;
    RECT urect;
    HBITMAP offscreenbm;
    HBITMAP screenbm;
    PAINTSTRUCT ps;
    bool gamestart;
    
    HFONT font = CreateFont( 0, 0, 0, 0, 700, FALSE, FALSE, FALSE, 0, 
    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, 
    NULL); 
        
    hball ball;
    
    
    // the Window Procedure
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    
        switch(msg)
        {
            case WM_CLOSE:
                DestroyWindow(hwnd);
                DeleteDC(OFFSCRN);
                DeleteDC(SCREEN);
            break;
            case WM_DESTROY:
                PostQuitMessage(0);
            break;
            case WM_PAINT:
                BeginPaint(hwnd, &ps);
    
                EndPaint(hwnd, &ps);
            break;
            default:
                return DefWindowProc(hwnd, msg, wParam, lParam);
                break;
        }
        return 0;
    }
    
    MSG Msg;
    WNDCLASSEX wc;
    HWND hwnd;
    
    
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
    {
        time_t seconds;
        time(&seconds);
        srand((unsigned int) seconds);
        
        ball.yslope      = rand() % (1 - 7);
        ball.dir         = 1;
        ball.diry        = 2;
        ball.xslope      = 5;
        
        paddle1.xpos     = 20;
        paddle1.ypos     = 197;
        paddle1.length   = 45;
        paddle1.speed    = 3;
        
        paddle2.xpos     = 680;
        paddle2.ypos     = 197;
        paddle2.length   = 46;
        paddle2.speed    = 3;
        
        ball.xpos        = 347;
        ball.ypos        = 197;
        ball.size        = 10;
        
        ball.upleftx     = ball.xpos - (ball.size / 2);
        ball.uplefty     = ball.ypos - (ball.size / 2);
        
        ball.bottomrightx= ball.xpos + ball.size;
        ball.bottomrighty= ball.ypos + ball.size;
        
        gamestart = false;
        
        // Registering the Window Class
        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)(COLOR_WINDOW+1);
        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;
        }
    
        
        
        
        // Creating the Window
        hwnd = CreateWindowEx(
            WS_EX_CLIENTEDGE,
            g_szClassName,
            "Pong",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, 750, 510,
            NULL, NULL, hInstance, NULL);
    
        if(hwnd == NULL)
        {
            MessageBox(NULL, "Window Creation Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
        
        PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE);
        int DrawScreen();
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
    
        // The Message Loop
        while(Msg.message != WM_QUIT)
        {
            if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
            {
    	         TranslateMessage(&Msg);
    	         DispatchMessage(&Msg);
            }
            else
            {
                  if(ball.ypos >= 400) 
                  { 
                       ball.diry = 2; 
                  }
                  if(ball.ypos <= 5) 
                  { 
                       ball.diry = 1; 
                  }
                  if(ball.xpos == paddle1.xpos)
                  {
                       if(ball.ypos == paddle1.ypos)
                       {
                            ball.dir == 2;
                       }
                  }
                  if(ball.xpos == paddle2.xpos)
                  {
                       if(ball.ypos == paddle2.ypos)
                       {
                         ball.dir == 1;
                       }
                  }
                  if(ball.dir == 1) 
                  { 
                       ball.xpos = ball.xpos - ball.xslope; 
                  }
                  else if(ball.dir == 2) 
                  { 
                       ball.xpos = ball.xpos + ball.xslope; 
                  }
                  if(ball.diry == 1) 
                  { 
                       ball.ypos = ball.ypos + ball.yslope; 
                  }
                  else if(ball.diry == 2) 
                  { 
                       ball.ypos = ball.ypos - ball.yslope; 
                  }
                  ball.upleftx = ball.xpos;
                  ball.uplefty = ball.ypos;
                  ball.bottomrightx = ball.xpos - ball.size;
                  ball.bottomrighty = ball.ypos - ball.size;
                  
                  
                  if(GetAsyncKeyState(VK_UP) < 0) 
                  { 
                       paddle1.ypos = paddle1.ypos - paddle1.speed; 
                  }
                  else if(GetAsyncKeyState(VK_DOWN) < 0) 
                  {
                       paddle1.ypos = paddle1.ypos + paddle1.speed; 
                  }
                  else if(GetAsyncKeyState(VK_RETURN) < 0) 
                  { 
                       ball.yslope  = rand() % (1 - 7);
                       gamestart    = true; 
                       ball.xslope  = 1;
                  }
                  int DrawScreen();
            }
        }
    return Msg.wParam;    
    }
    
    void DrawScreen()
    {
                //  Sizing hdcs and bitmaps to the screen so it will draw to the whole
                //  windows client area
                GetClientRect(hwnd, &brect);
                SCREEN = GetDC(hwnd);
                OFFSCRN = CreateCompatibleDC(SCREEN);
                offscreenbm = CreateCompatibleBitmap(OFFSCRN, brect.right, brect.bottom);
                screenbm = CreateCompatibleBitmap(SCREEN, brect.right, brect.bottom);
                
                
                SelectObject(OFFSCRN, offscreenbm);
                SelectObject(SCREEN, screenbm);
    
                //Prepare to draw the background
                SelectObject(OFFSCRN, bpen);
                SelectObject(OFFSCRN, bbrush);
                
                //Draw the background
                Rectangle(OFFSCRN, brect.left, brect.top, brect.right, brect.bottom);
                
                //Prepare to draw the board
                SelectObject(OFFSCRN, ballpen);
                
                //Draw the board
                Rectangle(OFFSCRN, 5, 5, 700, 400);
                MoveToEx(OFFSCRN, 350, 5, NULL);
                LineTo(OFFSCRN, 350, 400);
                
                //Prepare to draw the paddles
                SelectObject(OFFSCRN, ppen);
                SelectObject(OFFSCRN, bbrush);
                
                //Paddle 1
                MoveToEx(OFFSCRN, paddle1.xpos, paddle1.ypos + paddle1.length / 2, NULL);
                LineTo(OFFSCRN, paddle1.xpos, paddle1.ypos - paddle1.length);
                
                //Paddle 2
                MoveToEx(OFFSCRN, paddle2.xpos, paddle2.ypos + paddle2.length / 2, NULL);
                LineTo(OFFSCRN, paddle2.xpos, paddle2.ypos - paddle2.length);
                
                //Ball
                SelectObject(OFFSCRN, wbrush);
                SelectObject(OFFSCRN, ballpen);
                Ellipse(OFFSCRN, ball.upleftx, ball.uplefty, ball.bottomrightx, ball.bottomrighty);
                if(gamestart == false)
                {
                     SelectObject(OFFSCRN, font);
                     TextOut(OFFSCRN, 290, 190, "Hit <Enter> to start!", 21);
                }
                
                BitBlt(SCREEN, 0, 0, brect.right, brect.bottom, OFFSCRN, 0, 0, SRCCOPY);
                ReleaseDC(hwnd, SCREEN);     
                DeleteObject(offscreenbm);
                DeleteObject(screenbm);
                DeleteDC(OFFSCRN);
                
    }
    Edit: Also, I can't see how I am checking input twice.


    I'm probably hard to work with, but thanks for all this help man.

    Edit 2: Hey, I think I got it working. Let me make sure.
    Last edited by SniperSAS; 11-20-2005 at 04:09 PM.

  12. #12
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Hey, I'm about to run out but you have the following line in your message loop. I'm sure this is just a typo, late night coding error, but you don't want a prototype you want to call the function. I'll look at it more when I get home.
    Code:
    int DrawScreen();
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

  13. #13
    Banned SniperSAS's Avatar
    Join Date
    Aug 2005
    Posts
    175
    Okay, I got it so that it doesn't stop painting, but now i am having trouble doing hit detection on the paddles. I haven't gotten very far into this part, so I am going to keep trying to see if I can get it, but if i still can't figure it out after a bit I'll post it.

    Thanks again for all this help.

    And yeah the draw screen thing was just me screwing around.

  14. #14
    Banned SniperSAS's Avatar
    Join Date
    Aug 2005
    Posts
    175
    Sorry this took so long, but some stuff has been going down for me that I have been busy with.

    Anyway, i finished the code sometime last week, and here it is:

    Code:
    #include <windows.h>
    #include <ctime>
    #include <cstdlib>
    
    
    const char g_szClassName[] = "myWindowClass";
    
    struct hball{ int xslope; int yslope; int xpos; int ypos; RECT ballrect;  
                  int size; int dir; int diry; int speed; };
    
    struct paddle{ int xpos; int length; int ypos; int speed; RECT hitdet; int score; };
    
    paddle paddle1;
    paddle paddle2;
    
    HDC OFFSCRN;
    HDC SCREEN;
    HDC dc;
    HPEN ppen = CreatePen(PS_SOLID, 4, RGB(255, 255, 255));
    HPEN bpen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    HPEN ballpen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
    HBRUSH bbrush = CreateSolidBrush(RGB(0, 0, 0));
    HBRUSH wbrush = CreateSolidBrush(RGB(255, 255, 255));
    RECT brect;
    RECT rectbuff;
    HBITMAP offscreenbm;
    HBITMAP screenbm;
    PAINTSTRUCT ps;
    bool gamestart;
    
    HFONT font = CreateFont( 0, 0, 0, 0, 700, FALSE, FALSE, FALSE, 0, 
    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, 
    NULL); 
        
    hball ball;
    
    
    // Step 4: the Window Procedure
    LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        
        switch(msg)
        {
            case WM_CLOSE:
                DestroyWindow(hwnd);
                DeleteDC(OFFSCRN);
                DeleteDC(SCREEN);
            break;
            case WM_DESTROY:
                PostQuitMessage(0);
            break;
            case WM_PAINT:
                BeginPaint(hwnd, &ps);
                //  Sizing hdcs and bitmaps to the screen so it will draw to the whole
                //  windows client area
                GetClientRect(hwnd, &brect);
                SCREEN = GetDC(hwnd);
                OFFSCRN = CreateCompatibleDC(SCREEN);
                offscreenbm = CreateCompatibleBitmap(OFFSCRN, brect.right, brect.bottom);
                screenbm = CreateCompatibleBitmap(SCREEN, brect.right, brect.bottom);
                
                
                SelectObject(OFFSCRN, offscreenbm);
                SelectObject(SCREEN, screenbm);
    
                //Prepare to draw the background
                SelectObject(OFFSCRN, bpen);
                SelectObject(OFFSCRN, bbrush);
                
                //Draw the background
                Rectangle(OFFSCRN, brect.left, brect.top, brect.right, brect.bottom);
                
                //Prepare to draw the board
                SelectObject(OFFSCRN, ballpen);
                
                //Draw the board
                Rectangle(OFFSCRN, 5, 5, 700, 400);
                MoveToEx(OFFSCRN, 350, 5, NULL);
                LineTo(OFFSCRN, 350, 400);
                
                //Prepare to draw the paddles
                SelectObject(OFFSCRN, ppen);
                SelectObject(OFFSCRN, bbrush);
                
                //Paddle 1
                MoveToEx(OFFSCRN, paddle1.xpos, paddle1.ypos - paddle1.length / 2, NULL);
                LineTo(OFFSCRN, paddle1.xpos, paddle1.ypos + paddle1.length);
                
                //Paddle 2
                MoveToEx(OFFSCRN, paddle2.xpos, paddle2.ypos - paddle2.length / 2, NULL);
                LineTo(OFFSCRN, paddle2.xpos, paddle2.ypos + paddle2.length);
                
                //Ball
                SelectObject(OFFSCRN, wbrush);
                SelectObject(OFFSCRN, ballpen);
                Ellipse(OFFSCRN, ball.ballrect.left, ball.ballrect.top, ball.ballrect.right, ball.ballrect.bottom);
                if(gamestart == false)
                {
                     SelectObject(OFFSCRN, font);
                     TextOut(OFFSCRN, 290, 190, "Hit <Enter> to start!", 21);
                }
                
                BitBlt(SCREEN, 0, 0, brect.right, brect.bottom, OFFSCRN, 0, 0, SRCCOPY);
                ReleaseDC(hwnd, SCREEN);     
                DeleteObject(offscreenbm);
                DeleteObject(screenbm);
                DeleteDC(OFFSCRN);
                EndPaint(hwnd, &ps);
            break;
            default:
                return DefWindowProc(hwnd, msg, wParam, lParam);
                break;
        }
        return 0;
    }
    
    MSG Msg;
    WNDCLASSEX wc;
    HWND hwnd;
    
    int oldtick;
    int currtick;
    int newtick;
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
    {
        time_t seconds;
        time(&seconds);
        srand((unsigned int) seconds);
        oldtick = GetTickCount();
        ball.dir         = 1;
        ball.diry        = 2;
        
        paddle1.xpos            = 10;
        paddle1.ypos            = 197;
        paddle1.length          = 45;
        paddle1.speed           = 4;
        paddle1.hitdet.left     = 10;
        paddle1.hitdet.top      = paddle1.ypos - paddle1.length / 2;
        paddle1.hitdet.right    = 20;
        paddle1.hitdet.bottom   = paddle1.ypos + paddle1.length / 2;    
        
        paddle2.xpos            = 693;
        paddle2.ypos            = 197;
        paddle2.length          = 46;
        paddle2.speed           = 4;
        paddle1.hitdet.left     = 693;
        paddle2.hitdet.top      = paddle2.ypos - paddle1.length / 2;
        paddle2.hitdet.right    = 697;
        paddle2.hitdet.bottom   = paddle2.ypos + paddle1.length / 2;
        
        
        ball.xpos            = 347;
        ball.ypos            = 197;
        ball.size            = 7;
        
        ball.ballrect.left   = ball.xpos - (ball.size / 2);
        ball.ballrect.top    = ball.ypos - (ball.size / 2);
        ball.ballrect.right  = ball.xpos + (ball.size / 2);
        ball.ballrect.bottom = ball.ypos + (ball.size / 2);
        
        gamestart = false;
        
        // Registering the Window Class
        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)(COLOR_WINDOW+1);
        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;
        }
    
        
        
        
        // Creating the Window
        hwnd = CreateWindowEx(
            WS_EX_CLIENTEDGE,
            g_szClassName,
            "Pong",
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, CW_USEDEFAULT, 750, 510,
            NULL, NULL, hInstance, NULL);
    
        if(hwnd == NULL)
        {
            MessageBox(NULL, "Window Creation Failed!", "Error!",
                MB_ICONEXCLAMATION | MB_OK);
            return 0;
        }
        
        PeekMessage(&Msg, NULL, 0, 0, PM_NOREMOVE);
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);
    
        // The Message Loop
        while(Msg.message != WM_QUIT)
        {
            newtick = GetTickCount();
            currtick = newtick - oldtick;
            if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
            {
    	         TranslateMessage(&Msg);
    	         DispatchMessage(&Msg);
            }
            else
            {
                  if(currtick >= 10) {
                  if(ball.ypos >= 395) 
                  { 
                       ball.diry = 2; 
                  }
                  if(ball.ypos <= 10) 
                  { 
                       ball.diry = 1; 
                  }
                  if(ball.xpos >= 685)
                  {
                      ball.dir = 1;
                  }
                  if(ball.dir == 1) 
                  { 
                       ball.xpos = ball.xpos - ball.xslope; 
                  }
                  else if(ball.dir == 2) 
                  { 
                       ball.xpos = ball.xpos + ball.xslope; 
                  }
                  if(ball.diry == 1) 
                  {
                       ball.ypos = ball.ypos + ball.yslope; 
                  }
                  else if(ball.diry == 2) 
                  { 
                       ball.ypos = ball.ypos - ball.yslope; 
                  }
                  
                  ball.ballrect.left   = ball.xpos - (ball.size / 2);
                  ball.ballrect.top    = ball.ypos - (ball.size / 2);
                  ball.ballrect.right  = ball.xpos + ball.size;
                  ball.ballrect.bottom = ball.ypos + ball.size;
                  
                  if(GetAsyncKeyState(VK_UP) < 0) 
                  { 
                       if(paddle1.ypos - paddle1.length / 2 <=8) { }
                       else { paddle1.ypos = paddle1.ypos - paddle1.speed; }
                  }
                  else if(GetAsyncKeyState(VK_DOWN) < 0) 
                  {
                       if(paddle1.ypos + paddle1.length >= 397) {  }
                       else { paddle1.ypos = paddle1.ypos + paddle1.speed; } 
                  }
                  else if(GetAsyncKeyState(VK_RETURN) < 0) 
                  { 
                       ball.yslope  = rand() % (3 - 9);
                       ball.xslope  = 5;
                       gamestart    = true; 
                  }
                  paddle1.hitdet.left     = 10;
                  paddle1.hitdet.top      = paddle1.ypos - paddle1.length / 2;
                  paddle1.hitdet.right    = 15;
                  paddle1.hitdet.bottom   = paddle1.ypos + paddle1.length;    
                  if(ball.ballrect.top > paddle2.ypos) 
                  { 
                       if(paddle2.hitdet.bottom >=  397) { }
                       else { paddle2.ypos = paddle2.ypos + paddle2.speed; }
                  }
                  else if(ball.ypos < paddle2.ypos) 
                  { 
                       if(paddle2.hitdet.bottom <= 8) { }
                       else { paddle2.ypos = paddle2.ypos - paddle2.speed; }    
                  }
                  
                  if(ball.ballrect.left <= 10)
                  {
                      if(IntersectRect(&rectbuff, &ball.ballrect, &paddle1.hitdet))
                      {
                          ball.dir = 2;
                      }
                      else
                      {
                         paddle2.score++;
                         gamestart = false;
                         ball.xslope = 0;
                         ball.yslope = 0; 
                         ball.xpos = 347;
                         ball.ypos = 197;
                      }
                  }
                  paddle2.hitdet.left     = 693;
                  paddle2.hitdet.top      = paddle2.ypos - paddle2.length / 2;
                  paddle2.hitdet.right    = 697;
                  paddle2.hitdet.bottom   = paddle2.ypos + paddle2.length;  
                  if(ball.ballrect.right >= 693)
                  {
                      if(IntersectRect(&rectbuff, &ball.ballrect, &paddle2.hitdet))
                      {
                          
                          ball.dir = 1;
                      }
                      else
                      {
                         paddle1.score++;
                         gamestart = false;
                         ball.xslope = 0;
                         ball.yslope = 0; 
                         ball.xpos = 347;
                         ball.ypos = 197;
                      }
                  }
        
                  
                  RedrawWindow(hwnd, 0, 0, RDW_INVALIDATE);
                  oldtick = newtick;
                  }
            }
        }
    return Msg.wParam;    
    }

  15. #15
    Registered User
    Join Date
    Apr 2002
    Posts
    1,571
    Well done. I didn't really look over your code too much but what I did see was a few memory leaks. You create several objects globally and never destroy them. Make sure you call DeleteObject in your WM_CLOSE on those 3 pens, 2 brushes and 1 font that you create as globals. Also, don't call DeleteDC in your WM_CLOSE on your SCREEN and OFFSCRN global DC's. You already call the appropriate ReleaseDC and DeleteDC calls for those in your WM_PAINT handler.
    "...the results are undefined, and we all know what "undefined" means: it means it works during development, it works during testing, and it blows up in your most important customers' faces." --Scott Meyers

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Please comment on my c++ game
    By MegaManZZ in forum Game Programming
    Replies: 10
    Last Post: 01-22-2008, 11:03 AM
  2. New Project, text game, design stage.
    By Shamino in forum Game Programming
    Replies: 9
    Last Post: 05-23-2007, 06:39 AM
  3. 2D Game project requires extra C++ programmers, new or experienced
    By drallstars in forum Projects and Job Recruitment
    Replies: 2
    Last Post: 05-16-2007, 10:46 AM
  4. HELP!wanting to make full screen game windowed
    By rented in forum Game Programming
    Replies: 3
    Last Post: 06-11-2004, 04:19 AM
  5. Game Programmer's AIM Circle: Join Today
    By KingZoolerius66 in forum A Brief History of Cprogramming.com
    Replies: 28
    Last Post: 12-20-2003, 12:12 PM