View Full Version: Hit The Ball game

C++ Learning Community > C++ Creations > Hit The Ball game


Title: Hit The Ball game


Xception - June 26, 2003 08:01 PM (GMT)
not much comments in the source but if you have any questions then ask.
it uses gdi graphic functions, no directdraw. compile as win32 gui project

CODE

// hittheball
// made by Xception

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

// Global Variables
HBRUSH red_brush=CreateSolidBrush(0x2020f0);
HDC game,backbuffer;
HBITMAP back_bmp = NULL;
HBITMAP old_bmp = NULL;
RECT rt;
int iScore,iTime;
bool game_over=false;

class Ball {
private:
int x;  // horizontal position
int y;  // vertical position
int hspeed; // horizontal speed
int vspeed; // vertical speed
public:
Ball(void);
void draw(HDC hdc);
void move(void);
bool Collision(int mx, int my);
void SetRandomPos(void);
};

void Ball::SetRandomPos(void) {
x=rand()%340;y=rand()%240;
}

Ball::Ball(void) {
SetRandomPos();
hspeed=3; vspeed=3;
}

void Ball::draw(HDC hdc) {
SelectObject(hdc,red_brush);
Ellipse(hdc,x,y,x+25,y+25);
}

bool Ball::Collision(int mx, int my) {
if ((abs((mx)-(x+12))<(12))&&(abs((my)-(y+12))<(12))) return true;
return false;
}

void Ball::move(void) {
x+=hspeed; y+=vspeed;
if ((x>rt.right-25) || (x<0)) hspeed*=-1;
if ((y>rt.bottom-25) || (y<0)) vspeed*=-1;
}

Ball* ball1;
Ball* ball2;

LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
HWND hwnd;
MSG msg;
WNDCLASSEX wcex;

wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style   = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra  = 0;
wcex.cbWndExtra  = 0;
wcex.hInstance  = hInstance;
wcex.hIcon   = LoadIcon(hInstance, (LPCTSTR)IDI_WINLOGO);
wcex.hCursor  = LoadCursor(NULL, IDC_CROSS);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "MainWnd";
wcex.hIconSm  = LoadIcon(hInstance, (LPCTSTR)IDI_WINLOGO);

// Register the window class, and if it fails quit the program
   if (!RegisterClassEx (&wcex))
       return 0;
// Create the window
   hwnd = CreateWindowEx (
          0,                 // no extended window style
          "MainWnd",         // Window Classname
          "Hit The Ball",           // Window Title Text
          WS_SYSMENU, // Window style: Systemmenu
          (int)GetSystemMetrics(SM_CXFULLSCREEN)/2-200,       // center window horizontally
          (int)GetSystemMetrics(SM_CYFULLSCREEN)/2-150,      // and vertically
          400,                 // Window width
          300,                 // Window height
          NULL,        // Window has no parent window
          NULL,        // no menu
          hInstance,       // Window Instance handle
          NULL);                 // No Window Creation data    
   ShowWindow (hwnd, nCmdShow); // Show the window
game=GetDC(hwnd);
backbuffer=CreateCompatibleDC(game); // Create backbuffer
back_bmp = CreateCompatibleBitmap(game, 400, 300); // for doublebuffering
  old_bmp = (HBITMAP)SelectObject(backbuffer, back_bmp); // select backbuffer
  SetTimer(hwnd,1,10,NULL);    // timer for balls
  SetTimer(hwnd,2,1000,NULL); // timer for time
// messageloop
while( GetMessage(&msg, NULL, 0, 0) )
{
 {
  TranslateMessage( &msg );
  DispatchMessage( &msg );
 }
}
return msg.wParam;
}

// Window Procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
char tempstr[12];

switch( message )
{
case WM_CREATE:
    srand(GetTickCount()); // seed the random numbers
 iTime=30;
 iScore=0;
 ball1=new Ball; ball2=new Ball; // create balls
 break;
 case WM_TIMER:
  switch(wParam)
  {
  case 1: // move balls and draw stuff
  GetClientRect( hwnd, &rt );
  FillRect(backbuffer,&rt,(HBRUSH) GetStockObject(WHITE_BRUSH));
  sprintf(tempstr,"SCORE: %d", iScore);
  TextOut(backbuffer,20,0,tempstr,strlen(tempstr));
  sprintf(tempstr,"Time: %d", iTime);
  TextOut(backbuffer,320,0,tempstr,strlen(tempstr));
  if (game_over) {
   TextOut(backbuffer,160,100,"Game Over",9);
   TextOut(backbuffer,110,120,"Press <SPACE> to restart!",25);}
   else {
    ball1->move(); ball2->move();}
           ball1->draw(backbuffer);
  ball2->draw(backbuffer);
  BitBlt(game, 0, 0, 400, 300, backbuffer, 0, 0, SRCCOPY);
  break;
  case 2: // decrease time
   if (iTime>0) iTime--; else game_over=true;
   break;
  }
 case WM_KEYDOWN:
  if (wParam==VK_ESCAPE) DestroyWindow(hwnd); // Escape=Close Game
  if ((game_over) && (wParam==VK_SPACE)) { // Space=Restart Game
   iTime=30;iScore=0; game_over=false;}
  break;
 case WM_LBUTTONDOWN:
  if (!game_over) { // Check if mouse hits balls
  if (ball1->Collision(LOWORD(lParam),HIWORD(lParam))) {
           iScore++;
  Beep(500,20);
           ball1->SetRandomPos();
           }
  if (ball2->Collision(LOWORD(lParam),HIWORD(lParam))) {
  iScore++;
  Beep(400,20);
     ball2->SetRandomPos();
  }}
  break;
 case WM_PAINT:
  hdc = BeginPaint (hwnd, &ps);
  EndPaint( hwnd, &ps );
  break;
 case WM_DESTROY: // cleanup!
     delete ball1, ball2;
  KillTimer(hwnd,1);
  KillTimer(hwnd,2);
  SelectObject(backbuffer,old_bmp);
  DeleteObject(back_bmp);
  DeleteDC(backbuffer);
  DeleteObject(red_brush);
  PostQuitMessage( 0 );
  break;
 default:
  return DefWindowProc( hwnd, message, wParam, lParam );
  }
  return 0;
}

Dragon - June 26, 2003 10:56 PM (GMT)
Hey, nice! I can understand a lot of the code, but writing it myself is a different story! :(

Xception - June 26, 2003 11:15 PM (GMT)
Now you don't have to code it on your own anymore :D
It's 22kb compiled, with Game Maker it would be about 1,2 MB
But with GM I would need about 5 minutes and with C++ it took me a few hours because it was my first C++ Windows game.

Dragon - June 26, 2003 11:41 PM (GMT)
That was your first? Very nice for a first game. :)

I have a question though. Suppose I have a variable (maybe int i;). How can I give the variable (i) a random value instead of a predefined one?

Xception - June 26, 2003 11:53 PM (GMT)
i=rand()%5;
would assign 0,1,2,3,4 or 5 to i
but you have to use
srand(GetTickCount()); before the assignment
if you don't want to get the same "random" numbers each time you run the program.

Dragon - June 27, 2003 12:00 AM (GMT)
Thanks a lot Xception. I looked at your code again and figured that it had to do with the x=rand()%somevaluehere because that sets the x position of the ball. What do you mean by "if you don't want to get the same "random" numbers each time you run the program?" Does it mean that if I don't use srand(GetTickCount()); I would get the same numbers every time the application starts?

Xception - June 27, 2003 12:21 AM (GMT)
QUOTE

Does it mean that if I don't use srand(GetTickCount()); I would get the same numbers every time the application starts?

Yes, and you can't use a constant value with srand(), you have to use something like GetTickCount(), othrwise you would get again the same numbers, other numbers than without using srand() but still the same numbers sequence each time.

Dragon - June 27, 2003 12:50 AM (GMT)
Okay, I got it.

Shadow of the Moon - June 27, 2003 02:12 AM (GMT)
Show-off! :P

No seriously, that is pretty cool. I wish I could do stuff like that.

x-Kyo - July 5, 2003 01:46 AM (GMT)
sorry but i must need to know this, i heard that to make a game u need to learn direct x first. is it true? and by the way if you refer me a good tutorial site :D


Dragon - July 5, 2003 01:57 AM (GMT)
You should post it in the questions forum. You'll get more answers there. And you don't need DirectX for every type of game (I'm not 100% sure, though).

Xception - July 5, 2003 11:59 AM (GMT)
You don't need to learn DirectX first. I used GDI in this game, but it's slow and only recommended for games like board games or other game types where speed is not needed. You could also use OpenGL, it's fast and easier to learn than DirectX. Or you could learn/use a game/graphics library like Allegro, much easier than learning DirectX but fast.

dr voodoo - July 5, 2003 07:12 PM (GMT)
Xception I don't understand one thing of what use is this code:
CODE
case WM_PAINT:
 hdc = BeginPaint (hwnd, &ps);
 EndPaint( hwnd, &ps );
 break;


Gamer09 - July 14, 2003 10:07 PM (GMT)
QUOTE
Xception I don't understand one thing of what use is this code:

CODE
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
EndPaint( hwnd, &ps );
break;


I think it is supposed to draw everything.

Dragon - July 14, 2003 11:09 PM (GMT)
No, it's not. It does draw things, but not everything in the window. For example, the main window is not "drawn" using that.

dr voodoo - July 16, 2003 07:44 AM (GMT)
QUOTE (Gamer09 @ Jul 14 2003, 10:07 PM)
QUOTE
Xception I don't understand one thing of what use is this code:

CODE
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
EndPaint( hwnd, &ps );
break;


I think it is supposed to draw everything.

Wrong it doesn't draw anything!
First you get your HDC and the next thing you do is give it back. He draws using Timers and the GetDC() and ReleaseDC() function

EDIT: That is he should but I think he forgot about ReleaseDC()


I beleave Xception tryed to draw in there but it simply isn't the right spott in a game so he did it elsewhere and simply forgot to remove it.

XReciP - January 29, 2004 04:13 AM (GMT)
I dunno why, but I copied and pasted your code to see it work and I got the following errors when trying to build:

QUOTE
LIBCD.lib(crt0.obj) : error LNK2001: unresolved external symbol _main
Debug/Hit_the_Ball.exe :
fatal error LNK1120: 1 unresolved externals


How do I fix and why are they there?

Dragon - January 29, 2004 04:35 AM (GMT)
Did you compile it as a Win32 API application?

J-Swift - January 29, 2004 04:56 AM (GMT)
You might have inadvertantly messed up on the paste. I got an unresolved external the other day because I spelled 'Calculation' as 'Calclulatoin.

XReciP - January 29, 2004 05:09 AM (GMT)
Yea, I compiled it as a win32 application. Could it have to do with that I'm using VC++ and maybe he was using a different C++ compiler??




* Hosted for free by InvisionFree