home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / Source / GPCHAP14 / PROG14_3.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2002-04-29  |  16.6 KB  |  662 lines

  1. // PROG14_3.CPP - DirectInput joystick demo
  2. // move the bug blaster around, notice it moves more or
  3. // less depending on how much the stick is moves, hence
  4. // the analog nature of joysticks
  5.  
  6.  
  7. // INCLUDES ///////////////////////////////////////////////
  8.  
  9. #define WIN32_LEAN_AND_MEAN  
  10. #define INITGUID
  11.  
  12. #include <windows.h>   // include important windows stuff
  13. #include <windowsx.h> 
  14. #include <mmsystem.h>
  15. #include <objbase.h>
  16. #include <iostream.h> // include important C/C++ stuff
  17. #include <conio.h>
  18. #include <stdlib.h>
  19. #include <malloc.h>
  20. #include <memory.h>
  21. #include <string.h>
  22. #include <stdarg.h>
  23. #include <stdio.h> 
  24. #include <math.h>
  25. #include <io.h>
  26. #include <fcntl.h>
  27.  
  28. #include <ddraw.h>     // directX includes
  29. #include <dinput.h> 
  30. #include "gpdumb1.h"
  31.  
  32. // DEFINES ////////////////////////////////////////////////
  33.  
  34. // defines for windows 
  35. #define WINDOW_CLASS_NAME "WINXCLASS"  // class name
  36.  
  37. #define WINDOW_WIDTH    64   // size of window
  38. #define WINDOW_HEIGHT   48
  39.  
  40.  
  41. // PROTOTYPES /////////////////////////////////////////////
  42.  
  43. // game console
  44. int Game_Init(void *parms=NULL);
  45. int Game_Shutdown(void *parms=NULL);
  46. int Game_Main(void *parms=NULL);
  47.  
  48. // GLOBALS ////////////////////////////////////////////////
  49.  
  50. HWND main_window_handle = NULL; // save the window handle
  51. HINSTANCE main_instance = NULL; // save the instance
  52. char buffer[80];                // used to print text
  53.  
  54. // directinput globals
  55. LPDIRECTINPUT8       lpdi      = NULL;    // dinput object
  56. LPDIRECTINPUTDEVICE8 lpdikey   = NULL;    // dinput keyboard
  57. LPDIRECTINPUTDEVICE8 lpdimouse = NULL;    // dinput mouse
  58. LPDIRECTINPUTDEVICE8 lpdijoy   = NULL;    // dinput joystick 
  59. GUID                 joystickGUID;        // guid for main joystick
  60. char                 joyname[80];         // name of joystick
  61.  
  62. // these contain the target records for all di input packets
  63. UCHAR keyboard_state[256]; // contains keyboard state table
  64. DIMOUSESTATE mouse_state;  // contains state of mouse
  65. DIJOYSTATE joy_state;      // contains state of joystick
  66.  
  67. BITMAP_IMAGE playfield;       // used to hold playfield
  68. BITMAP_IMAGE mushrooms[4];    // holds mushrooms
  69. BOB          blaster;         // holds bug blaster
  70.  
  71. int blaster_anim[5] = {0,1,2,1,0};  // blinking animation
  72.  
  73. // lets use a line segment for the missle
  74. int missile_x,              // position of missle
  75.     missile_y,            
  76.     missile_state;          // state of missle 0 off, 1 on
  77.  
  78. // PROTOTYPES //////////////////////////////////////////////
  79.  
  80. int Color_Scan(int x1, int y1, int x2, int y2, 
  81.       UCHAR scan_start, UCHAR scan_end, 
  82.       UCHAR *scan_buffer, int scan_lpitch);
  83.  
  84. int Start_Missile(void);
  85. int Move_Missile(void);
  86. int Draw_Missile(void);
  87.  
  88. // FUNCTIONS //////////////////////////////////////////////
  89.  
  90. LRESULT CALLBACK WindowProc(HWND hwnd, 
  91.                             UINT msg, 
  92.                             WPARAM wparam, 
  93.                             LPARAM lparam)
  94. {
  95. // this is the main message handler of the system
  96. PAINTSTRUCT    ps;           // used in WM_PAINT
  97. HDC            hdc;       // handle to a device context
  98.  
  99. // what is the message 
  100. switch(msg)
  101.     {    
  102.     case WM_CREATE: 
  103.         {
  104.         // do initialization stuff here
  105.         return(0);
  106.         } break;
  107.  
  108.     case WM_PAINT:
  109.          {
  110.          // start painting
  111.          hdc = BeginPaint(hwnd,&ps);
  112.  
  113.          // end painting
  114.          EndPaint(hwnd,&ps);
  115.          return(0);
  116.         } break;
  117.  
  118.     case WM_DESTROY: 
  119.         {
  120.         // kill the application            
  121.         PostQuitMessage(0);
  122.         return(0);
  123.         } break;
  124.  
  125.     default:break;
  126.  
  127.     } // end switch
  128.  
  129. // process any messages that we didn't take care of 
  130. return (DefWindowProc(hwnd, msg, wparam, lparam));
  131.  
  132. } // end WinProc
  133.  
  134. // WINMAIN ////////////////////////////////////////////////
  135.  
  136. int WINAPI WinMain(    HINSTANCE hinstance,
  137.                     HINSTANCE hprevinstance,
  138.                     LPSTR lpcmdline,
  139.                     int ncmdshow)
  140. {
  141. // this is the winmain function
  142.  
  143. WNDCLASS winclass;    // this will hold the class we create
  144. HWND     hwnd;        // generic window handle
  145. MSG         msg;        // generic message
  146. HDC      hdc;       // generic dc
  147. PAINTSTRUCT ps;     // generic paintstruct
  148.  
  149. // first fill in the window class stucture
  150. winclass.style            = CS_DBLCLKS | CS_OWNDC | 
  151.                           CS_HREDRAW | CS_VREDRAW;
  152. winclass.lpfnWndProc    = WindowProc;
  153. winclass.cbClsExtra        = 0;
  154. winclass.cbWndExtra        = 0;
  155. winclass.hInstance        = hinstance;
  156. winclass.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
  157. winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  158. winclass.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);
  159. winclass.lpszMenuName    = NULL; 
  160. winclass.lpszClassName    = WINDOW_CLASS_NAME;
  161.  
  162. // register the window class
  163. if (!RegisterClass(&winclass))
  164.     return(0);
  165.  
  166. // create the window, note the use of WS_POPUP
  167. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  168.                           "WinX Game Console",     // title
  169.                           WS_POPUP | WS_VISIBLE,
  170.                            0,0,       // x,y
  171.                           WINDOW_WIDTH,  // width
  172.                           WINDOW_HEIGHT, // height
  173.                           NULL,       // handle to parent 
  174.                           NULL,       // handle to menu
  175.                           hinstance,// instance
  176.                           NULL)))    // creation parms
  177. return(0);
  178.  
  179. // save the window handle and instance in a global
  180. main_window_handle = hwnd;
  181. main_instance      = hinstance;
  182.  
  183. // perform all game console specific initialization
  184. Game_Init();
  185.  
  186. // enter main event loop
  187. while(1)
  188.     {
  189.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  190.         { 
  191.         // test if this is a quit
  192.         if (msg.message == WM_QUIT)
  193.            break;
  194.     
  195.         // translate any accelerator keys
  196.         TranslateMessage(&msg);
  197.  
  198.         // send the message to the window proc
  199.         DispatchMessage(&msg);
  200.         } // end if
  201.     
  202.     // main game processing goes here
  203.     Game_Main();
  204.  
  205.     } // end while
  206.  
  207. // shutdown game and release all resources
  208. Game_Shutdown();
  209.  
  210. // return to Windows like this
  211. return(msg.wParam);
  212.  
  213. } // end WinMain
  214.  
  215. ///////////////////////////////////////////////////////////
  216.  
  217. int Color_Scan(int x1, int y1, int x2, int y2, 
  218.                UCHAR scan_start, UCHAR scan_end,
  219.                UCHAR *scan_buffer, int scan_lpitch)
  220. {
  221. // this function implements a crude collision technique
  222. // based on scanning for a range of colors within a rectangle
  223.  
  224. // clip rectangle
  225.  
  226. // x coords first    
  227. if (x1 >= screen_width)
  228.    x1=screen_width-1;
  229. else
  230. if (x1 < 0)
  231.    x1=0;
  232.  
  233. if (x2 >= screen_width)
  234.    x2=screen_width-1;
  235. else
  236. if (x2 < 0)
  237.    x2=0;
  238.  
  239. // now y-coords
  240. if (y1 >= screen_height)
  241.    y1=screen_height-1;
  242. else
  243. if (y1 < 0)
  244.    y1=0;
  245.  
  246. if (y2 >= screen_height)
  247.    y2=screen_height-1;
  248. else
  249. if (y2 < 0)
  250.    y2=0;
  251.  
  252. // scan the region
  253. scan_buffer +=y1*scan_lpitch;
  254.  
  255. for (int scan_y=y1; scan_y<=y2; scan_y++)
  256.     {
  257.     for (int scan_x=x1; scan_x<=x2; scan_x++)
  258.         {
  259.         if (scan_buffer[scan_x] >= scan_start && scan_buffer[scan_x] <= scan_end )
  260.             return(1);
  261.         } // end for x
  262.  
  263.     // move down a line
  264.     scan_buffer+=scan_lpitch;
  265.  
  266.     } // end for y
  267.  
  268. // return failure
  269. return(0);
  270.  
  271. } // end Color_Scan
  272.  
  273. // WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  274.  
  275. BOOL CALLBACK DI_Enum_Joysticks(LPCDIDEVICEINSTANCE lpddi,
  276.                                 LPVOID guid_ptr) 
  277. {
  278. // this function enumerates the joysticks, but
  279. // stops at the first one and returns the
  280. // instance guid of it, so we can create it
  281.  
  282. *(GUID*)guid_ptr = lpddi->guidInstance; 
  283.  
  284. // copy name into global
  285. strcpy(joyname, (char *)lpddi->tszProductName);
  286.  
  287. // stop enumeration after one iteration
  288. return(DIENUM_STOP);
  289.  
  290. } // end DI_Enum_Joysticks
  291.  
  292. ///////////////////////////////////////////////////////////
  293.  
  294. int Start_Missile(void)
  295. {
  296. // this function starts the missle, if it is currently off
  297.  
  298. if (missile_state==0)
  299.     {
  300.     // enable missile
  301.     missile_state = 1;
  302.  
  303.     // computer position of missile
  304.     missile_x = blaster.x + 16;
  305.     missile_y = blaster.y-4;
  306.  
  307.     // return success
  308.     return(1);
  309.     } // end if
  310.  
  311. // couldn't start missile
  312. return(0);
  313.  
  314. } // end Start_Missile
  315.  
  316. ///////////////////////////////////////////////////////////
  317.  
  318. int Move_Missile(void)
  319. {
  320. // this function moves the missle 
  321.  
  322. // test if missile is alive
  323. if (missile_state==1)
  324.    {
  325.    // move the missile upward
  326.    if ((missile_y-=10) < 0)
  327.       {
  328.       missile_state = 0;
  329.       return(1);
  330.       } // end if
  331.  
  332.    // lock secondary buffer
  333.    DD_Lock_Back_Surface();
  334.  
  335.    // test if missile has hit anything
  336.    if (Color_Scan(missile_x-1, missile_y+4,
  337.                   missile_x+1, missile_y+12,
  338.                   1,255, back_buffer,back_lpitch))
  339.       {
  340.       // kill missile
  341.       missile_state = 0;
  342.  
  343.       // cause some damage
  344.       for (int index=0; index<25; index++)
  345.           {
  346.           Draw_Pixel(missile_x-4+rand()%8,missile_y-2+rand()%12,0,
  347.                       playfield.buffer, playfield.width);
  348.  
  349.           } // end for index
  350.  
  351.       } // end if
  352.  
  353.    // unlock surface
  354.    DD_Unlock_Back_Surface();
  355.  
  356.    // return success
  357.    return(1);
  358.  
  359.    } // end if
  360.  
  361. // return failure
  362. return(0);
  363.  
  364. } // end Move_Missle
  365.  
  366. ///////////////////////////////////////////////////////////
  367.  
  368. int Draw_Missile(void)
  369. {
  370. // this function draws the missile 
  371.  
  372. // test if missile is alive
  373. if (missile_state==1)
  374.    {
  375.    // lock secondary buffer
  376.    DD_Lock_Back_Surface();
  377.  
  378.    // draw the missile in green
  379.    Draw_Clip_Line(missile_x, missile_y, 
  380.                   missile_x, missile_y+6,
  381.                   250,back_buffer, back_lpitch);
  382.  
  383.    // unlock surface
  384.    DD_Unlock_Back_Surface();
  385.  
  386.    // return success
  387.    return(1);
  388.  
  389.    } // end if
  390.  
  391. // return failure
  392. return(0);
  393.  
  394. } // end Draw_Missle
  395.  
  396. ///////////////////////////////////////////////////////////
  397.  
  398. int Game_Init(void *parms)
  399. {
  400. // this function is where you do all the initialization 
  401. // for your game
  402.  
  403. int index;         // looping var
  404. char filename[80]; // used to build up files names
  405.  
  406. // set up screen dimensions
  407. screen_width  = 640;
  408. screen_height = 480;
  409. screen_bpp    = 8;
  410.  
  411. // initialize directdraw
  412. DD_Init(screen_width, screen_height, screen_bpp);
  413.  
  414. // joystick creation section ////////////////////////////////
  415.  
  416. // first create the direct input object
  417. if (DirectInput8Create(main_instance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&lpdi,NULL)!=DI_OK)
  418.    return(0);
  419.  
  420. // first find the fucking GUID of your particular joystick
  421. lpdi->EnumDevices(DI8DEVCLASS_GAMECTRL, 
  422.                   DI_Enum_Joysticks, 
  423.                   &joystickGUID, 
  424.                   DIEDFL_ATTACHEDONLY); 
  425.  
  426. if (lpdi->CreateDevice(joystickGUID, &lpdijoy, NULL)!=DI_OK)
  427.    return(0);
  428.  
  429. // set cooperation level
  430. if (lpdijoy->SetCooperativeLevel(main_window_handle, 
  431.                      DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)!=DI_OK)
  432.    return(0);
  433.  
  434. // set data format
  435. if (lpdijoy->SetDataFormat(&c_dfDIJoystick)!=DI_OK)
  436.    return(0);
  437.  
  438. // set the range of the joystick
  439. DIPROPRANGE joy_axis_range;
  440.  
  441. // first x axis
  442. joy_axis_range.lMin = -24;
  443. joy_axis_range.lMax = 24;
  444.  
  445. joy_axis_range.diph.dwSize       = sizeof(DIPROPRANGE); 
  446. joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  447. joy_axis_range.diph.dwObj        = DIJOFS_X;
  448. joy_axis_range.diph.dwHow        = DIPH_BYOFFSET;
  449.  
  450. lpdijoy->SetProperty(DIPROP_RANGE,&joy_axis_range.diph);
  451.  
  452. // now y-axis
  453. joy_axis_range.lMin = -24;
  454. joy_axis_range.lMax = 24;
  455.  
  456. joy_axis_range.diph.dwSize       = sizeof(DIPROPRANGE); 
  457. joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  458. joy_axis_range.diph.dwObj        = DIJOFS_Y;
  459. joy_axis_range.diph.dwHow        = DIPH_BYOFFSET;
  460.  
  461. lpdijoy->SetProperty(DIPROP_RANGE,&joy_axis_range.diph);
  462.  
  463. // acquire the joystick
  464. if (lpdijoy->Acquire()!=DI_OK)
  465.    return(0);
  466.  
  467. ///////////////////////////////////////////////////////////
  468.  
  469. // load the background
  470. Load_Bitmap_File(&bitmap8bit, "MUSH8.BMP");
  471.  
  472. // set the palette to background image palette
  473. Set_Palette(bitmap8bit.palette);
  474.  
  475. // load in the four frames of the mushroom
  476. for (index=0; index<4; index++)
  477.     {
  478.     // create mushroom bitmaps
  479.     Create_Bitmap(&mushrooms[index],0,0,32,32);
  480.     Load_Image_Bitmap(&mushrooms[index],&bitmap8bit,index,0,BITMAP_EXTRACT_MODE_CELL);  
  481.     } // end for index
  482.  
  483. // now create the bug blaster bob
  484. Create_BOB(&blaster,0,0,32,32,3,
  485.            BOB_ATTR_VISIBLE | BOB_ATTR_MULTI_ANIM | BOB_ATTR_ANIM_ONE_SHOT,
  486.            DDSCAPS_SYSTEMMEMORY);
  487.  
  488. // load in the four frames of the mushroom
  489. for (index=0; index<3; index++)
  490.      Load_Frame_BOB(&blaster,&bitmap8bit,index,index,1,BITMAP_EXTRACT_MODE_CELL);  
  491.  
  492. // unload the bitmap file
  493. Unload_Bitmap_File(&bitmap8bit);
  494.  
  495. // set the animation sequences for bug blaster
  496. Load_Animation_BOB(&blaster,0,5,blaster_anim);
  497.  
  498. // set up stating state of bug blaster
  499. Set_Pos_BOB(&blaster,320, 400);
  500. Set_Anim_Speed_BOB(&blaster,3);
  501.  
  502. // set clipping rectangle to screen extents so objects dont
  503. // mess up at edges
  504. RECT screen_rect = {0,0,screen_width,screen_height};
  505. lpddclipper = DD_Attach_Clipper(lpddsback,1,&screen_rect);
  506.  
  507. // seed random number generator
  508. srand(Start_Clock());
  509.  
  510. // create mushroom playfield bitmap
  511. Create_Bitmap(&playfield,0,0,screen_width,screen_height);
  512. playfield.attr |= BITMAP_ATTR_LOADED;
  513.  
  514. // clear it out
  515. memset(playfield.buffer,0,playfield.width*playfield.height);
  516.  
  517. // create the random mushroom patch
  518. for (index=0; index<50; index++)
  519.     {
  520.     // select a mushroom
  521.     int mush = rand()%4;
  522.  
  523.     // set mushroom to random position
  524.     mushrooms[mush].x = rand()%(screen_width-32);
  525.     mushrooms[mush].y = rand()%(screen_height-128);
  526.  
  527.     // now draw the mushroom into playfield
  528.     Draw_Bitmap(&mushrooms[mush], playfield.buffer, playfield.width,1);
  529.  
  530.     } // end for
  531.  
  532. // hide the mouse
  533. ShowCursor(FALSE);
  534.  
  535. // return success
  536. return(1);
  537.  
  538. } // end Game_Init
  539.  
  540. ///////////////////////////////////////////////////////////
  541.  
  542. int Game_Shutdown(void *parms)
  543. {
  544. // this function is where you shutdown your game and
  545. // release all resources that you allocated
  546.  
  547. // kill the bug blaster
  548. Destroy_BOB(&blaster);
  549.  
  550. // kill the mushroom maker
  551. for (int index=0; index<4; index++)
  552.     Destroy_Bitmap(&mushrooms[index]);
  553.  
  554. // kill the playfield bitmap
  555. Destroy_Bitmap(&playfield);
  556.  
  557. // release joystick
  558. lpdijoy->Unacquire();
  559. lpdijoy->Release();
  560. lpdi->Release();
  561.  
  562. // shutdonw directdraw
  563. DD_Shutdown();
  564.  
  565. // return success
  566. return(1);
  567. } // end Game_Shutdown
  568.  
  569. ///////////////////////////////////////////////////////////
  570.  
  571. int Game_Main(void *parms)
  572. {
  573. // this is the workhorse of your game it will be called
  574. // continuously in real-time this is like main() in C
  575. // all the calls for you game go here!
  576.  
  577. int          index;             // looping var
  578. int          dx,dy;             // general deltas used in collision detection
  579.  
  580. // check of user is trying to exit
  581. if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))
  582.     PostMessage(main_window_handle, WM_DESTROY,0,0);
  583.  
  584. // start the timing clock
  585. Start_Clock();
  586.  
  587. // get joystick data
  588. lpdijoy->Poll(); // this is needed for joysticks only
  589. lpdijoy->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joy_state);
  590.  
  591. // clear the drawing surface
  592. DD_Fill_Surface(lpddsback, 0);
  593.  
  594. // lock the back buffer
  595. DD_Lock_Back_Surface();
  596.  
  597. // draw the background reactor image
  598. Draw_Bitmap(&playfield, back_buffer, back_lpitch, 0);
  599.  
  600. // unlock the back buffer
  601. DD_Unlock_Back_Surface();
  602.  
  603. // is the player moving?
  604. blaster.x+=joy_state.lX;
  605. blaster.y+=joy_state.lY;
  606.  
  607. // test bounds
  608. if (blaster.x > screen_width-32)
  609.     blaster.x = screen_width-32;
  610. else
  611. if (blaster.x < 0)
  612.     blaster.x = 0;
  613.  
  614. if (blaster.y > screen_height-32)
  615.     blaster.y = screen_height-32;
  616. else
  617. if (blaster.y < screen_height-128)
  618.     blaster.y = screen_height-128;
  619.  
  620. // is player firing?
  621. if (joy_state.rgbButtons[0])
  622.    Start_Missile();
  623.  
  624. // move and draw missle
  625. Move_Missile();
  626. Draw_Missile();
  627.  
  628. // is it time to blink eyes
  629. if ((rand()%100)==50)
  630.    Set_Animation_BOB(&blaster,0);
  631.  
  632. // draw blaster
  633. Animate_BOB(&blaster);
  634. Draw_BOB(&blaster,lpddsback);
  635.  
  636. // draw some text
  637. Draw_Text_GDI("Blast Those Mushrooms!",0,0,RGB(0,0,255),lpddsback);
  638.  
  639. // display joystick
  640. sprintf(buffer,"Joystick: X-Axis=%d, Y-Axis=%d, buttons(%d,%d,%d,%d)",joy_state.lX,joy_state.lY,
  641.                                                                       joy_state.rgbButtons[0],
  642.                                                                       joy_state.rgbButtons[1],
  643.                                                                       joy_state.rgbButtons[2],
  644.                                                                       joy_state.rgbButtons[3]);
  645.  
  646. Draw_Text_GDI(buffer,0,screen_height-20,RGB(255,0,0),lpddsback);
  647.  
  648. // print out name of joystick
  649. Draw_Text_GDI(joyname,0,screen_height-40,RGB(255,255,50),lpddsback);
  650.  
  651. // flip the surfaces
  652. DD_Flip();
  653.  
  654. // sync to 40ish fps
  655. Wait_Clock(20);
  656.  
  657. // return success
  658. return(1);
  659.  
  660. } // end Game_Main
  661.  
  662. //////////////////////////////////////////////////////////