Pong Probs: draw sprite & boundaries (Win32)

Started by
1 comment, last by gretty 14 years, 1 month ago
Hi I have made a simple Pong game using strictly Win32 C++ functions. But I have run into some problems. Problems: 1. The sprite for the ball/pong circle should be a perfect white circle but its being draw irregularly (as an irregular ellipse). And my rectangles for my player & computer(bats?) are drawn slightly smaller than they should be drawn. I think there something wrong with my draw function but I dont know what? 2. When the ball/pong moves towards/outside the right & bottom boundary the ball doesn't bounce back like it should but it sticks to the boundary & moves along it. I have looked through my code & I cant seem to figure out why this is happening? Does anyone know of any Pong tutorials that are for Win32, not SDL etc? Thanks for reading my post :) Pong Application http://www.mediafire.com/?eghzmdhej3m Application code:

#include <windows.h>
#include <stdio.h>

#define IDS_MOVETIME 1
#define IDS_DIRTIME  2
#define IDS_PONGMOVE 3

static HINSTANCE gInstance;
class OBJECT {
    
    public:
        HRGN rgn;
        HBRUSH hb;
        int x;
        int y;
        int width;
        int height;
        OBJECT(); 
        bool moveTo(HWND hwnd, RECT &clientR, int n, bool &redraw);
        void drawSprite(HDC hdc);   
        void setStats(int X, int Y, int w, int h, COLORREF fillColour);
};

class BALL {
     
   public: 
       HRGN rgn;
       HBRUSH hb;
       int x;
       int y;
       int width;
       int height;
       int hSpeed; // horizontal speed
       int vSpeed; // vertical speed
       BALL();  
       bool moveTo(HWND hwnd, RECT &clientR, bool &redraw);
       bool checkObjectCollision(OBJECT &o);
       void drawSprite(HDC hdc);   
       void setStats(int X, int Y, int w, int h, COLORREF fillColour); 
};

OBJECT player;
OBJECT computer;
BALL pong;
bool gameStart = true;
bool redrawPlayer = true;
bool redrawComp   = true;
bool redrawPong   = true;
int vSpeed = 2;
UINT movementTimer;
UINT directionTimer;
UINT pongMoveTimer;
RECT clientR;

// Functions List //
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void drawBorder(HDC hdc);
void drawObjects(HDC hdc);


int WINAPI WinMain(HINSTANCE gInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    //Step 1: Registering the Window Class
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = gInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+3);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = "My Class";
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    // if registration of main class fails
    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        "My Class",
        "Pong",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,500,500,
        NULL, NULL, gInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

// Step 4: the Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CREATE:
        {
            movementTimer  = SetTimer(hwnd,IDS_MOVETIME,50,NULL);
            directionTimer = SetTimer(hwnd,IDS_DIRTIME,12000,NULL);
            pongMoveTimer  = SetTimer(hwnd,IDS_PONGMOVE,50,NULL);
            
            GetClientRect(hwnd,&clientR);
            player.setStats(10,200,50,100,RGB(255,255,255));
            computer.setStats(clientR.right-60,15,50,100,RGB(255,0,0));
            pong.setStats(clientR.right-100,40,20,20,RGB(255,255,255));
        }     
        break;
        case WM_SIZE:
        {
             GetClientRect(hwnd,&clientR);                     // update clientR 
             computer.x   = clientR.right-(computer.width+10); // update computer.x position 
             gameStart    = true;                              // update White Rectangular Border
             redrawPlayer = true;
             redrawComp   = true;
             redrawPong   = true;
             InvalidateRect(hwnd,NULL,true);
             // It is unecessary to update player.x value as it doesn't change
        }     
        break;
        case WM_KEYDOWN:
        {
             switch(LOWORD(wParam)) {
                
                case VK_UP:
                {
                     player.moveTo(hwnd,clientR,-5,redrawPlayer);
                }     
                break;
                case VK_DOWN:
                {
                     player.moveTo(hwnd,clientR,5,redrawPlayer);
                }     
                break;
                default:
                break;                    
             }
        }
        break;
        case WM_TIMER:
        {
            switch(LOWORD(wParam)) {
               
               case IDS_PONGMOVE:
               {    // Move ball/pong & collision check
                    pong.moveTo(hwnd,clientR,redrawPong);
               }     
               break;
               case IDS_MOVETIME:
               {     // Move in direction at vSpeed
                     computer.moveTo(hwnd,clientR,vSpeed,redrawComp);
               }
               break;
               case IDS_DIRTIME:
               {     // change computer pong objects' direction
                     if (vSpeed==2) {
                        vSpeed = -2;   // direction = up
                     }
                     else vSpeed = 2;  // direction = down
               }
               break;
               default:
               break;                    
            } 
        }     
        break;
        case WM_PAINT:
        {
            HDC hdc;
            PAINTSTRUCT ps;
            
            hdc = BeginPaint(hwnd,&ps);
            
            if (gameStart) {
                drawBorder(hdc);
                gameStart = false;
            }
            
            drawObjects(hdc);
            
            EndPaint(hwnd,&ps); 
        }     
        break;
        case WM_CLOSE:
            DeleteObject(player.hb);
            DeleteObject(computer.hb);
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

// Main & Drawing functions
void drawBorder(HDC hdc)
{
   // Post: Draw white rectangular border for pong ball to bounce off
   HPEN hP = CreatePen(PS_SOLID,2,WHITE_PEN);
   SelectObject(hdc,hP);
   SetROP2(hdc,R2_NOT);
   SelectObject(hdc,GetStockObject(NULL_BRUSH));  // make inside of rectangle transparent DO I NEED TO DeleteObect this??
   Rectangle(hdc,3,3,clientR.right-3,clientR.bottom-3);
   DeleteObject(hP);  
}

void drawObjects(HDC hdc)
{
   // Post: Draw player, computer &/or pong when necessary
   /*
   bool *drawObject[3] = {&redrawPlayer,&redrawComp,&redrawPong);
   
   for (int i=0; i<3; i++) {
       
       if (&drawObject == true) {
           
   }
   */
   if (redrawPlayer) {
       player.drawSprite(hdc);
       redrawPlayer = false;             
   }
   
   if (redrawComp) {
       computer.drawSprite(hdc);
       redrawComp = false;
   }
   if (redrawPong) {
       pong.drawSprite(hdc);       
       redrawPong = false;           
   } 
}


// Class member functions
OBJECT::OBJECT()
{
   // Constructor
   x      = 0;
   y      = 0;
   width  = 0;
   height = 0;
   rgn    = NULL;
   hb     = NULL;             
}

bool OBJECT::moveTo(HWND hwnd, RECT &clientR, int n, bool &redraw)
{
   // Post: Moves object up or down according to n & updates objects HRGN
   
   // make sure we dont move outside the client window
   if ((y+n)>=5 && (y+height+n)<=(clientR.bottom-5)) {
       
       y += n;
       redraw = true;
       InvalidateRgn(hwnd,rgn,true);
       //rgn = CreateRectRgn(x,y,(x+width),(y+height));
       return true;
   }
   else return false;
}

void OBJECT::drawSprite(HDC hdc)
{
   // Post: draw sprite
   rgn = CreateRectRgn(x,y,(x+width),(y+height));
   FillRgn(hdc,rgn,hb);   
}

void OBJECT::setStats(int X, int Y, int w, int h, COLORREF fillColour)
{
   // Post: Set structures variables 
   x      = X;
   y      = Y;
   width  = w;
   height = h;
   rgn    = CreateRectRgn(x,y,x+width,y+height);
   hb     = CreateSolidBrush(fillColour);             
}

BALL::BALL()
{
   // Constructor
   x      = 0;
   y      = 0;
   width  = 0;
   height = 0;
   rgn    = NULL;
   hb     = NULL; 
   hSpeed = -2;
   vSpeed = -2;       
}

bool BALL::moveTo(HWND hwnd, RECT &clientR, bool &redraw)
{
   // Post: Moves ball/pong up or down according to n & perform collision checking 
   
   x += hSpeed;
   y += vSpeed;
   
   // if collision with player or computer
   if (checkObjectCollision(player) || checkObjectCollision(computer)) {
       //x = x-hSpeed;
       //y = y-vSpeed;
       hSpeed = -hSpeed;
       vSpeed = -vSpeed;
       return false;
   }       
   
   // Check for collisions with rectangular barrier
   if (x < 6) {
        x = 6;
        hSpeed = -hSpeed;
   }
   
   if (x+width > clientR.right-6) {  // this code is not stopping the ball from moving outside the rectangle
        x = clientR.right-6;
        hSpeed = -hSpeed;
   }
   
   if (y < 6) {
        y = 6;
        vSpeed = -vSpeed;
   }
   
   if (y+height > clientR.bottom-6) { // this code is not stopping the ball from moving outside the rectangle
        y = clientR.bottom-7;
        vSpeed = -vSpeed;
   }
   
   redraw = true;
   InvalidateRgn(hwnd,rgn,true);
}

bool BALL::checkObjectCollision(OBJECT &o)
{
   // Post: Checks for a collision between ball/pong & OBJECT
   
   bool xCollision = false;
   bool yCollision = false;
   
   // find left most object
   if (x <= o.x) {
       // COLLISION, if horizontal distance between this & other object is <= width
       if (abs(x-o.x) <= width) { xCollision = true; }
   }
   // other object = left most object
   else if (abs(x-o.x) <= o.width) { xCollision = true; }
   
   // find upper most object
   if (y <= o.y) {
       // COLLISION, if vertical distance between this & other object is <= height
       if (abs(y-o.y) <= height) { yCollision = true; }
   }
   // other object = upper most object
   else if (abs(y-o.y) <= o.height) { yCollision = true; }
   
   return (xCollision==true && yCollision==true);
}

void BALL::drawSprite(HDC hdc)
{
   // Post: draw sprite
   rgn = CreateEllipticRgn(x,y,(x+width),(y+height));
   FillRgn(hdc,rgn,hb);  
}
  
void BALL::setStats(int X, int Y, int w, int h, COLORREF fillColour)
{
   // Post: Set structures variables 
   x      = X;
   y      = Y;
   width  = w;
   height = h;
   rgn    = CreateEllipticRgn(x,y,x+width,y+height);
   hb     = CreateSolidBrush(fillColour);    
}



Ball draw function & ball collision functions

// ball draw function
void BALL::drawSprite(HDC hdc)
{
   // Post: draw sprite
   rgn = CreateEllipticRgn(x,y,(x+width),(y+height));
   FillRgn(hdc,rgn,hb);  
}

// ball collision functions
bool BALL::moveTo(HWND hwnd, RECT &clientR, bool &redraw)
{
   // Post: Moves ball/pong up or down according to n & perform collision checking 
   
   x += hSpeed;
   y += vSpeed;
   
   // if collision with player or computer
   if (checkObjectCollision(player) || checkObjectCollision(computer)) {
       //x = x-hSpeed;
       //y = y-vSpeed;
       hSpeed = -hSpeed;
       vSpeed = -vSpeed;
       return false;
   }       
   
   // Check for collisions with rectangular barrier
   if (x < 6) {
        x = 6;
        hSpeed = -hSpeed;
   }
   
   if (x+width > clientR.right-6) {  // this code is not stopping the ball from moving outside the rectangle
        x = clientR.right-6;
        hSpeed = -hSpeed;
   }
   
   if (y < 6) {
        y = 6;
        vSpeed = -vSpeed;
   }
   
   if (y+height > clientR.bottom-6) { // this code is not stopping the ball from moving outside the rectangle
        y = clientR.bottom-7;
        vSpeed = -vSpeed;
   }
   
   redraw = true;
   InvalidateRgn(hwnd,rgn,true);
}

bool BALL::checkObjectCollision(OBJECT &o)
{
   // Post: Checks for a collision between ball/pong & OBJECT
   
   bool xCollision = false;
   bool yCollision = false;
   
   // find left most object
   if (x <= o.x) {
       // COLLISION, if horizontal distance between this & other object is <= width
       if (abs(x-o.x) <= width) { xCollision = true; }
   }
   // other object = left most object
   else if (abs(x-o.x) <= o.width) { xCollision = true; }
   
   // find upper most object
   if (y <= o.y) {
       // COLLISION, if vertical distance between this & other object is <= height
       if (abs(y-o.y) <= height) { yCollision = true; }
   }
   // other object = upper most object
   else if (abs(y-o.y) <= o.height) { yCollision = true; }
   
   return (xCollision==true && yCollision==true);
}


Advertisement
Quote:Original post by gretty
2. When the ball/pong moves towards/outside the right & bottom boundary the ball doesn't bounce back like it should but it sticks to the boundary & moves along it. I have looked through my code & I cant seem to figure out why this is happening?

You need to change
   if (x+width > clientR.right-6) {        x = clientR.right-6;        hSpeed = -hSpeed;   }

..to..
   if (x+width > clientR.right-6) {        x = clientR.right-6-width;        hSpeed = -hSpeed;   }

..and similarly for the Y-axis check.
Thanks :D

This topic is closed to new replies.

Advertisement