Windows API problem (c++, VS08)

  • Bozebo
  • Expert
  • Expert
  • User avatar
  • Posts: 709
  • Loc: 404

Post 3+ Months Ago

Hi, I am working on my university coursework and I need to produce a basic 2D game using the windows API (no dx/opengl required yet). It is overall extremely simple, but there is one stupid issue with the Windows API that is getting on my nerves.

Firstly, I shall dump my code:
CPP Code: [ Select ]
//Windows Example Code
//Matthew Bett 2005
 
#include <windows.h>
#include <stdio.h>
#include <mmsystem.h>
#include <math.h>
 
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
 
/* not using any mouse input
typedef struct Mouse{
  int x,y;
} Mouse;
*/
 
typedef struct Sprite{
  int x, y, width, height;
  HBITMAP bitmap;
} Sprite;
 
int xpos, ypos;
int ticker = 0;
 
HBITMAP theOldFrontBitMap, theOldBackBitMap;
HWND ghwnd;
RECT screenRect;
HDC backHDC, frontHDC, bitmapHDC;   //Hardware device contexts for the Buffers
 
bool keys[256];
 
Sprite TestSprite;
 
BOOL waitFor(unsigned long delay);
 
 
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
 
void RegisterMyWindow(HINSTANCE hInstance){
  WNDCLASSEX  wcex;                          
 
  wcex.cbSize = sizeof(wcex);
  wcex.style = CS_HREDRAW | CS_VREDRAW;
  wcex.lpfnWndProc = WndProc;
  wcex.cbClsExtra = 0;
  wcex.cbWndExtra = 0;
  wcex.hInstance = hInstance;
  wcex.hIcon = 0;
  wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
               
  wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  wcex.lpszMenuName = NULL;
  wcex.lpszClassName = L"FirstWindowClass";
  wcex.hIconSm = 0;
 
  RegisterClassEx(&wcex);
}
 
 
BOOL InitialiseMyWindow(HINSTANCE hInstance, int nCmdShow){
  HWND hwnd;
  hwnd = CreateWindow(L"FirstWindowClass", L"Double Buffering", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
  CW_USEDEFAULT, CW_USEDEFAULT, SCREEN_WIDTH, SCREEN_HEIGHT, NULL,   NULL, hInstance,
  NULL);                     
  if(!hwnd) return FALSE;
 
  ShowWindow(hwnd, nCmdShow);                
  UpdateWindow(hwnd);  
  ghwnd = hwnd;
  return TRUE;
}
 
 
 
BOOL WaitFor(unsigned long delay){
  static unsigned long clockStart = 0;
  unsigned long timePassed;
  unsigned long now = timeGetTime();
 
  timePassed = now - clockStart;
  if(timePassed > delay){
    clockStart = now;
    return TRUE;
  } //why was there an else here? <!-- s;) --><img src=\"{SMILIES_PATH}/icon_wink.gif\" alt=\";)\" title=\"Wink\"><!-- s;) -->
  return FALSE;
}
 
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
  switch(message){                                         
    case WM_CREATE:  
    break;
 
    case WM_SIZE:
    break;
 
    case WM_KEYDOWN:
    keys[wParam]=true;
    break;
 
    case WM_KEYUP:
    keys[wParam]=false;
    break;
 
    /*
    case WM_MOUSEMOVE:
    MousePos.x = LOWORD (lParam);
    MousePos.y = HIWORD (lParam);
    break;
    */
 
    case WM_PAINT:
    break;
 
    case WM_DESTROY:
    PostQuitMessage(0);
    break;
  }
 
  return DefWindowProc(hwnd, message, wParam, lParam);
}
 
HBITMAP LoadABitmap(LPCWSTR szFileName){
  return (HBITMAP)LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
 
void drawSprite(Sprite theSprite){
  HBITMAP originalBitMap;
  originalBitMap = (HBITMAP)SelectObject(bitmapHDC,theSprite.bitmap);
  BitBlt(backHDC,theSprite.x,theSprite.y,theSprite.x+theSprite.width,theSprite.y+theSprite.height,bitmapHDC,0,0,SRCCOPY);
  SelectObject(bitmapHDC,originalBitMap);
}
 
void setBuffers(){
  GetClientRect(ghwnd, &screenRect); //creates rect based on window client area
  frontHDC = GetDC(ghwnd); // Initialises front buffer device context (window)
  backHDC = CreateCompatibleDC(frontHDC); // sets up Back DC to be compatible with the front
  bitmapHDC=CreateCompatibleDC(backHDC);
  theOldFrontBitMap = CreateCompatibleBitmap(frontHDC, screenRect.right,
  screenRect.bottom); //creates bitmap compatible with the front buffer
  theOldBackBitMap = (HBITMAP)SelectObject(backHDC, theOldFrontBitMap);
  //creates bitmap compatible with the back buffer
  FillRect(backHDC, &screenRect, (HBRUSH)GetStockObject(0));   
}
 
void displayFrame(){
  BitBlt(frontHDC, screenRect.left,screenRect.top, screenRect.right,
  screenRect.bottom, backHDC, 0, 0, SRCCOPY);
  FillRect(backHDC, &screenRect, (HBRUSH)GetStockObject(0));   
}
 
void releaseResources(){
  SelectObject(backHDC,theOldBackBitMap);
  DeleteDC(backHDC);
  DeleteDC(bitmapHDC);
  ReleaseDC(ghwnd,frontHDC);
}
 
/*
  classes
*/
 
//player ship
class Player{
  public:
  int x,y,height,width;
  float vSpeed,maxVSpeed,acceleration,friction;
  bool visible;
  Sprite sprite;
 
  //constructor
  Player(int setX, int setY, LPCWSTR bmp, int w, int h){
    sprite.bitmap = LoadABitmap(bmp);
    sprite.x = setX;
    sprite.y = setY;
    sprite.width = w;
    sprite.height = h;
    x = setX;
    y = setY;
    visible = true;
    vSpeed = 0;
    maxVSpeed = 14;
    acceleration = 1.3;
    friction = 0.7;
  }
 
  //every frame
  void step(){
    /*
      basic movement physics
    */
 
    //up
    if(keys[87]){
      //if not moving too fast upwards
      if(vSpeed > -maxVSpeed){
        //accelerate up
        vSpeed -= acceleration;
        //cap speed
        if(vSpeed < -maxVSpeed) vSpeed = -maxVSpeed;
      }
    }
    //down
    if(keys[83]){
      //if not moving too fast downwards
      if(vSpeed < maxVSpeed){
        //accelerate down
        vSpeed += acceleration;
        //cap speed
        if(vSpeed > maxVSpeed) vSpeed = maxVSpeed;
      }
    }
 
    //friction
    if(vSpeed > 0){
      vSpeed -= friction;
      if(vSpeed < 0) vSpeed = 0;
    } else if(vSpeed < 0){
      vSpeed += friction;
      if(vSpeed > 0) vSpeed = 0;
    }
 
 
    //apply motion
    y += vSpeed;
 
    //don't go out of the screen
    if(y < 0){
      vSpeed = 0;
      y = 0;
    } else if(y > 428){
      vSpeed = 0;
      y = 428;
    }
  }
 
  void draw(){
    if(!visible)
      return;
    sprite.x = x;
    sprite.y = y;
    drawSprite(sprite);
  }
};
 
 
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  PSTR szCmdLine, int nCmdShow){                         
  MSG msg;
  HDC hdcWindow;
 
  //create the player
  Player player(50,SCREEN_HEIGHT/2,L"icon.bmp",32,32);
 
  RegisterMyWindow(hInstance);
 
  if(!InitialiseMyWindow(hInstance, nCmdShow))
    return FALSE;
 
  setBuffers();
  while(TRUE){                   
    if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
      if(msg.message==WM_QUIT)
        break;
 
      TranslateMessage(&msg);                  
      DispatchMessage(&msg);
    } else if(WaitFor(10)){  
      //step the player
      player.step();
      //draw the player
      player.draw();
         
      displayFrame();  
    }
  }
 
  releaseResources();
  return msg.wParam;                           
}
 
 
  1. //Windows Example Code
  2. //Matthew Bett 2005
  3.  
  4. #include <windows.h>
  5. #include <stdio.h>
  6. #include <mmsystem.h>
  7. #include <math.h>
  8.  
  9. #define SCREEN_WIDTH 640
  10. #define SCREEN_HEIGHT 480
  11.  
  12. /* not using any mouse input
  13. typedef struct Mouse{
  14.   int x,y;
  15. } Mouse;
  16. */
  17.  
  18. typedef struct Sprite{
  19.   int x, y, width, height;
  20.   HBITMAP bitmap;
  21. } Sprite;
  22.  
  23. int xpos, ypos;
  24. int ticker = 0;
  25.  
  26. HBITMAP theOldFrontBitMap, theOldBackBitMap;
  27. HWND ghwnd;
  28. RECT screenRect;
  29. HDC backHDC, frontHDC, bitmapHDC;   //Hardware device contexts for the Buffers
  30.  
  31. bool keys[256];
  32.  
  33. Sprite TestSprite;
  34.  
  35. BOOL waitFor(unsigned long delay);
  36.  
  37.  
  38. LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
  39.  
  40. void RegisterMyWindow(HINSTANCE hInstance){
  41.   WNDCLASSEX  wcex;                          
  42.  
  43.   wcex.cbSize = sizeof(wcex);
  44.   wcex.style = CS_HREDRAW | CS_VREDRAW;
  45.   wcex.lpfnWndProc = WndProc;
  46.   wcex.cbClsExtra = 0;
  47.   wcex.cbWndExtra = 0;
  48.   wcex.hInstance = hInstance;
  49.   wcex.hIcon = 0;
  50.   wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  51.                
  52.   wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  53.   wcex.lpszMenuName = NULL;
  54.   wcex.lpszClassName = L"FirstWindowClass";
  55.   wcex.hIconSm = 0;
  56.  
  57.   RegisterClassEx(&wcex);
  58. }
  59.  
  60.  
  61. BOOL InitialiseMyWindow(HINSTANCE hInstance, int nCmdShow){
  62.   HWND hwnd;
  63.   hwnd = CreateWindow(L"FirstWindowClass", L"Double Buffering", WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
  64.   CW_USEDEFAULT, CW_USEDEFAULT, SCREEN_WIDTH, SCREEN_HEIGHT, NULL,   NULL, hInstance,
  65.   NULL);                     
  66.   if(!hwnd) return FALSE;
  67.  
  68.   ShowWindow(hwnd, nCmdShow);                
  69.   UpdateWindow(hwnd);  
  70.   ghwnd = hwnd;
  71.   return TRUE;
  72. }
  73.  
  74.  
  75.  
  76. BOOL WaitFor(unsigned long delay){
  77.   static unsigned long clockStart = 0;
  78.   unsigned long timePassed;
  79.   unsigned long now = timeGetTime();
  80.  
  81.   timePassed = now - clockStart;
  82.   if(timePassed > delay){
  83.     clockStart = now;
  84.     return TRUE;
  85.   } //why was there an else here? <!-- s;) --><img src=\"{SMILIES_PATH}/icon_wink.gif\" alt=\";)\" title=\"Wink\"><!-- s;) -->
  86.   return FALSE;
  87. }
  88.  
  89. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
  90.   switch(message){                                         
  91.     case WM_CREATE:  
  92.     break;
  93.  
  94.     case WM_SIZE:
  95.     break;
  96.  
  97.     case WM_KEYDOWN:
  98.     keys[wParam]=true;
  99.     break;
  100.  
  101.     case WM_KEYUP:
  102.     keys[wParam]=false;
  103.     break;
  104.  
  105.     /*
  106.     case WM_MOUSEMOVE:
  107.     MousePos.x = LOWORD (lParam);
  108.     MousePos.y = HIWORD (lParam);
  109.     break;
  110.     */
  111.  
  112.     case WM_PAINT:
  113.     break;
  114.  
  115.     case WM_DESTROY:
  116.     PostQuitMessage(0);
  117.     break;
  118.   }
  119.  
  120.   return DefWindowProc(hwnd, message, wParam, lParam);
  121. }
  122.  
  123. HBITMAP LoadABitmap(LPCWSTR szFileName){
  124.   return (HBITMAP)LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
  125. }
  126.  
  127. void drawSprite(Sprite theSprite){
  128.   HBITMAP originalBitMap;
  129.   originalBitMap = (HBITMAP)SelectObject(bitmapHDC,theSprite.bitmap);
  130.   BitBlt(backHDC,theSprite.x,theSprite.y,theSprite.x+theSprite.width,theSprite.y+theSprite.height,bitmapHDC,0,0,SRCCOPY);
  131.   SelectObject(bitmapHDC,originalBitMap);
  132. }
  133.  
  134. void setBuffers(){
  135.   GetClientRect(ghwnd, &screenRect); //creates rect based on window client area
  136.   frontHDC = GetDC(ghwnd); // Initialises front buffer device context (window)
  137.   backHDC = CreateCompatibleDC(frontHDC); // sets up Back DC to be compatible with the front
  138.   bitmapHDC=CreateCompatibleDC(backHDC);
  139.   theOldFrontBitMap = CreateCompatibleBitmap(frontHDC, screenRect.right,
  140.   screenRect.bottom); //creates bitmap compatible with the front buffer
  141.   theOldBackBitMap = (HBITMAP)SelectObject(backHDC, theOldFrontBitMap);
  142.   //creates bitmap compatible with the back buffer
  143.   FillRect(backHDC, &screenRect, (HBRUSH)GetStockObject(0));   
  144. }
  145.  
  146. void displayFrame(){
  147.   BitBlt(frontHDC, screenRect.left,screenRect.top, screenRect.right,
  148.   screenRect.bottom, backHDC, 0, 0, SRCCOPY);
  149.   FillRect(backHDC, &screenRect, (HBRUSH)GetStockObject(0));   
  150. }
  151.  
  152. void releaseResources(){
  153.   SelectObject(backHDC,theOldBackBitMap);
  154.   DeleteDC(backHDC);
  155.   DeleteDC(bitmapHDC);
  156.   ReleaseDC(ghwnd,frontHDC);
  157. }
  158.  
  159. /*
  160.   classes
  161. */
  162.  
  163. //player ship
  164. class Player{
  165.   public:
  166.   int x,y,height,width;
  167.   float vSpeed,maxVSpeed,acceleration,friction;
  168.   bool visible;
  169.   Sprite sprite;
  170.  
  171.   //constructor
  172.   Player(int setX, int setY, LPCWSTR bmp, int w, int h){
  173.     sprite.bitmap = LoadABitmap(bmp);
  174.     sprite.x = setX;
  175.     sprite.y = setY;
  176.     sprite.width = w;
  177.     sprite.height = h;
  178.     x = setX;
  179.     y = setY;
  180.     visible = true;
  181.     vSpeed = 0;
  182.     maxVSpeed = 14;
  183.     acceleration = 1.3;
  184.     friction = 0.7;
  185.   }
  186.  
  187.   //every frame
  188.   void step(){
  189.     /*
  190.       basic movement physics
  191.     */
  192.  
  193.     //up
  194.     if(keys[87]){
  195.       //if not moving too fast upwards
  196.       if(vSpeed > -maxVSpeed){
  197.         //accelerate up
  198.         vSpeed -= acceleration;
  199.         //cap speed
  200.         if(vSpeed < -maxVSpeed) vSpeed = -maxVSpeed;
  201.       }
  202.     }
  203.     //down
  204.     if(keys[83]){
  205.       //if not moving too fast downwards
  206.       if(vSpeed < maxVSpeed){
  207.         //accelerate down
  208.         vSpeed += acceleration;
  209.         //cap speed
  210.         if(vSpeed > maxVSpeed) vSpeed = maxVSpeed;
  211.       }
  212.     }
  213.  
  214.     //friction
  215.     if(vSpeed > 0){
  216.       vSpeed -= friction;
  217.       if(vSpeed < 0) vSpeed = 0;
  218.     } else if(vSpeed < 0){
  219.       vSpeed += friction;
  220.       if(vSpeed > 0) vSpeed = 0;
  221.     }
  222.  
  223.  
  224.     //apply motion
  225.     y += vSpeed;
  226.  
  227.     //don't go out of the screen
  228.     if(y < 0){
  229.       vSpeed = 0;
  230.       y = 0;
  231.     } else if(y > 428){
  232.       vSpeed = 0;
  233.       y = 428;
  234.     }
  235.   }
  236.  
  237.   void draw(){
  238.     if(!visible)
  239.       return;
  240.     sprite.x = x;
  241.     sprite.y = y;
  242.     drawSprite(sprite);
  243.   }
  244. };
  245.  
  246.  
  247. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  248.   PSTR szCmdLine, int nCmdShow){                         
  249.   MSG msg;
  250.   HDC hdcWindow;
  251.  
  252.   //create the player
  253.   Player player(50,SCREEN_HEIGHT/2,L"icon.bmp",32,32);
  254.  
  255.   RegisterMyWindow(hInstance);
  256.  
  257.   if(!InitialiseMyWindow(hInstance, nCmdShow))
  258.     return FALSE;
  259.  
  260.   setBuffers();
  261.   while(TRUE){                   
  262.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
  263.       if(msg.message==WM_QUIT)
  264.         break;
  265.  
  266.       TranslateMessage(&msg);                  
  267.       DispatchMessage(&msg);
  268.     } else if(WaitFor(10)){  
  269.       //step the player
  270.       player.step();
  271.       //draw the player
  272.       player.draw();
  273.          
  274.       displayFrame();  
  275.     }
  276.   }
  277.  
  278.   releaseResources();
  279.   return msg.wParam;                           
  280. }
  281.  
  282.  

NOTE: Input linker: winmm.lib

Now, allow me to explain the problem. When I define SCREEN_HEIGHT as 640, I would surely expect the usable area of the window to be 640px high, no? Well, windows seems to think it would be fun to take the title bar and the border out of that value (also with SCREEN_WIDTH). So when I program various pieces of code I have to hard code in the value to offset from the border, to stop this happening when the user moves down for too long:
Image

Now, I can solve this (by fixing the hard coded value because I didn't fix/remove it in the screenshot example). But, it will be different for different versions of windows and also if the user has changed their theme. So, is there a way within the windows api to find out how thick that border is so I can fix it? Oddly, the y = 0 position is in the correct place, but the bottom of the working are of the window is offset by the thickness of the title bar.

Can this be fixed? Or have I done something horribly wrong?
  • Anonymous
  • Bot
  • No Avatar
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post 3+ Months Ago

Post Information

  • Total Posts in this topic: 1 post
  • Users browsing this forum: No registered users and 60 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
cron
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.