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

  1. // PROG14_3_16b.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.       USHORT scan_start, USHORT 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.                USHORT scan_start, USHORT 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. USHORT *scan_buffer2 = (USHORT *)scan_buffer;
  227.  
  228. // x coords first    
  229. if (x1 >= screen_width)
  230.    x1=screen_width-1;
  231. else
  232. if (x1 < 0)
  233.    x1=0;
  234.  
  235. if (x2 >= screen_width)
  236.    x2=screen_width-1;
  237. else
  238. if (x2 < 0)
  239.    x2=0;
  240.  
  241. // now y-coords
  242. if (y1 >= screen_height)
  243.    y1=screen_height-1;
  244. else
  245. if (y1 < 0)
  246.    y1=0;
  247.  
  248. if (y2 >= screen_height)
  249.    y2=screen_height-1;
  250. else
  251. if (y2 < 0)
  252.    y2=0;
  253.  
  254. // scan the region
  255. scan_buffer2 +=y1*(scan_lpitch >> 1);
  256.  
  257. for (int scan_y=y1; scan_y<=y2; scan_y++)
  258.     {
  259.     for (int scan_x=x1; scan_x<=x2; scan_x++)
  260.         {
  261.         if (scan_buffer2[scan_x] >= scan_start && scan_buffer2[scan_x] <= scan_end )
  262.             return(1);
  263.         } // end for x
  264.  
  265.     // move down a line
  266.     scan_buffer2+=(scan_lpitch >> 1);
  267.  
  268.     } // end for y
  269.  
  270. // return failure
  271. return(0);
  272.  
  273. } // end Color_Scan
  274.  
  275. // WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  276.  
  277. BOOL CALLBACK DI_Enum_Joysticks(LPCDIDEVICEINSTANCE lpddi,
  278.                                 LPVOID guid_ptr) 
  279. {
  280. // this function enumerates the joysticks, but
  281. // stops at the first one and returns the
  282. // instance guid of it, so we can create it
  283.  
  284. *(GUID*)guid_ptr = lpddi->guidInstance; 
  285.  
  286. // copy name into global
  287. strcpy(joyname, (char *)lpddi->tszProductName);
  288.  
  289. // stop enumeration after one iteration
  290. return(DIENUM_STOP);
  291.  
  292. } // end DI_Enum_Joysticks
  293.  
  294. ///////////////////////////////////////////////////////////
  295.  
  296. int Start_Missile(void)
  297. {
  298. // this function starts the missle, if it is currently off
  299.  
  300. if (missile_state==0)
  301.     {
  302.     // enable missile
  303.     missile_state = 1;
  304.  
  305.     // computer position of missile
  306.     missile_x = blaster.x + 16;
  307.     missile_y = blaster.y-4;
  308.  
  309.     // return success
  310.     return(1);
  311.     } // end if
  312.  
  313. // couldn't start missile
  314. return(0);
  315.  
  316. } // end Start_Missile
  317.  
  318. ///////////////////////////////////////////////////////////
  319.  
  320. int Move_Missile(void)
  321. {
  322. // this function moves the missle 
  323.  
  324. // test if missile is alive
  325. if (missile_state==1)
  326.    {
  327.    // move the missile upward
  328.    if ((missile_y-=10) < 0)
  329.       {
  330.       missile_state = 0;
  331.       return(1);
  332.       } // end if
  333.  
  334.    // lock secondary buffer
  335.    DD_Lock_Back_Surface();
  336.  
  337.    // test if missile has hit anything
  338.    if (Color_Scan(missile_x-1, missile_y+4,
  339.                   missile_x+1, missile_y+12,
  340.                   1,65535, back_buffer,back_lpitch))
  341.       {
  342.       // kill missile
  343.       missile_state = 0;
  344.  
  345.       // cause some damage
  346.       for (int index=0; index<25; index++)
  347.           {
  348.           Draw_Pixel16(missile_x-4+rand()%8,missile_y-2+rand()%12,_RGB16BIT565(0,0,0),
  349.                        playfield.buffer, playfield.width*2);
  350.  
  351.           } // end for index
  352.  
  353.       } // end if
  354.  
  355.    // unlock surface
  356.    DD_Unlock_Back_Surface();
  357.  
  358.    // return success
  359.    return(1);
  360.  
  361.    } // end if
  362.  
  363. // return failure
  364. return(0);
  365.  
  366. } // end Move_Missle
  367.  
  368. ///////////////////////////////////////////////////////////
  369.  
  370. int Draw_Missile(void)
  371. {
  372. // this function draws the missile 
  373.  
  374. // test if missile is alive
  375. if (missile_state==1)
  376.    {
  377.    // lock secondary buffer
  378.    DD_Lock_Back_Surface();
  379.  
  380.    // draw the missile in green
  381.    Draw_Clip_Line16(missile_x, missile_y, 
  382.                   missile_x, missile_y+6,
  383.                   _RGB16BIT565(0,63,0) ,back_buffer, back_lpitch);
  384.  
  385.    // unlock surface
  386.    DD_Unlock_Back_Surface();
  387.  
  388.    // return success
  389.    return(1);
  390.  
  391.    } // end if
  392.  
  393. // return failure
  394. return(0);
  395.  
  396. } // end Draw_Missle
  397.  
  398. ///////////////////////////////////////////////////////////
  399.  
  400. int Game_Init(void *parms)
  401. {
  402. // this function is where you do all the initialization 
  403. // for your game
  404.  
  405. int index;         // looping var
  406. char filename[80]; // used to build up files names
  407.  
  408. // set up screen dimensions
  409. screen_width  = 640;
  410. screen_height = 480;
  411. screen_bpp    = 16;
  412.  
  413. // initialize directdraw
  414. DD_Init(screen_width, screen_height, screen_bpp);
  415.  
  416. // joystick creation section ////////////////////////////////
  417.  
  418. // first create the direct input object
  419. if (DirectInput8Create(main_instance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&lpdi,NULL)!=DI_OK)
  420.    return(0);
  421.  
  422. // first find the fucking GUID of your particular joystick
  423. lpdi->EnumDevices(DI8DEVCLASS_GAMECTRL, 
  424.                   DI_Enum_Joysticks, 
  425.                   &joystickGUID, 
  426.                   DIEDFL_ATTACHEDONLY); 
  427.  
  428. if (lpdi->CreateDevice(joystickGUID, &lpdijoy, NULL)!=DI_OK)
  429.    return(0);
  430.  
  431. // set cooperation level
  432. if (lpdijoy->SetCooperativeLevel(main_window_handle, 
  433.                      DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)!=DI_OK)
  434.    return(0);
  435.  
  436. // set data format
  437. if (lpdijoy->SetDataFormat(&c_dfDIJoystick)!=DI_OK)
  438.    return(0);
  439.  
  440. // set the range of the joystick
  441. DIPROPRANGE joy_axis_range;
  442.  
  443. // first x axis
  444. joy_axis_range.lMin = -24;
  445. joy_axis_range.lMax = 24;
  446.  
  447. joy_axis_range.diph.dwSize       = sizeof(DIPROPRANGE); 
  448. joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  449. joy_axis_range.diph.dwObj        = DIJOFS_X;
  450. joy_axis_range.diph.dwHow        = DIPH_BYOFFSET;
  451.  
  452. lpdijoy->SetProperty(DIPROP_RANGE,&joy_axis_range.diph);
  453.  
  454. // now y-axis
  455. joy_axis_range.lMin = -24;
  456. joy_axis_range.lMax = 24;
  457.  
  458. joy_axis_range.diph.dwSize       = sizeof(DIPROPRANGE); 
  459. joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  460. joy_axis_range.diph.dwObj        = DIJOFS_Y;
  461. joy_axis_range.diph.dwHow        = DIPH_BYOFFSET;
  462.  
  463. lpdijoy->SetProperty(DIPROP_RANGE,&joy_axis_range.diph);
  464.  
  465. // acquire the joystick
  466. if (lpdijoy->Acquire()!=DI_OK)
  467.    return(0);
  468.  
  469. ///////////////////////////////////////////////////////////
  470.  
  471. // load the background
  472. Load_Bitmap_File(&bitmap8bit, "MUSH16.BMP");
  473.  
  474.  
  475. // load in the four frames of the mushroom
  476. for (index=0; index<4; index++)
  477.     {
  478.     // create mushroom bitmaps
  479.     Create_Bitmap16(&mushrooms[index],0,0,32,32);
  480.     Load_Image_Bitmap16(&mushrooms[index],&bitmap8bit,index,0,BITMAP_EXTRACT_MODE_CELL);  
  481.     } // end for index
  482.  
  483. // now create the bug blaster bob
  484. Create_BOB16(&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_BOB16(&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_BOB16(&blaster,0,5,blaster_anim);
  497.  
  498. // set up stating state of bug blaster
  499. Set_Pos_BOB16(&blaster,320, 400);
  500. Set_Anim_Speed_BOB16(&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_Bitmap16(&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*2);
  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_Bitmap16(&mushrooms[mush], playfield.buffer, playfield.width*2,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_BOB16(&blaster);
  549.  
  550. // kill the mushroom maker
  551. for (int index=0; index<4; index++)
  552.     Destroy_Bitmap16(&mushrooms[index]);
  553.  
  554. // kill the playfield bitmap
  555. Destroy_Bitmap16(&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_Bitmap16(&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_BOB16(&blaster,0);
  631.  
  632. // draw blaster
  633. Animate_BOB16(&blaster);
  634. Draw_BOB16(&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. //////////////////////////////////////////////////////////