demoII3_2.cpp
Upload User: husern
Upload Date: 2018-01-20
Package Size: 42486k
Code Size: 22k
Category:

Game Program

Development Platform:

Visual C++

  1. // DEMOII3_2.CPP - full screen 256 color demo
  2. // based on 2D collision response demo from Volume I
  3. // system based on 
  4. // conservation of momentum and kinetic energy
  5. // to compile make sure to include DDRAW.LIB, DSOUND.LIB,
  6. // DINPUT.LIB, DINPUT8.LIB, WINMM.LIB, and of course the T3DLIB files
  7. // INCLUDES ///////////////////////////////////////////////
  8. #define INITGUID       // make sure al the COM interfaces are available
  9.                        // instead of this you can include the .LIB file
  10.                        // DXGUID.LIB
  11. #define WIN32_LEAN_AND_MEAN  
  12. #include <windows.h>   // include important windows stuff
  13. #include <windowsx.h> 
  14. #include <mmsystem.h>
  15. #include <iostream.h> // include important C/C++ stuff
  16. #include <conio.h>
  17. #include <stdlib.h>
  18. #include <malloc.h>
  19. #include <memory.h>
  20. #include <string.h>
  21. #include <stdarg.h>
  22. #include <stdio.h> 
  23. #include <math.h>
  24. #include <io.h>
  25. #include <fcntl.h>
  26. #include <ddraw.h>  // directX includes
  27. #include <dsound.h>
  28. #include <dmksctrl.h>
  29. #include <dmusici.h>
  30. #include <dmusicc.h>
  31. #include <dmusicf.h>
  32. #include <dinput.h>
  33. #include "T3DLIB1.h" // game library includes
  34. #include "T3DLIB2.h"
  35. #include "T3DLIB3.h"
  36. // DEFINES ////////////////////////////////////////////////
  37. // defines for windows interface
  38. #define WINDOW_CLASS_NAME "WIN3DCLASS"  // class name
  39. #define WINDOW_TITLE      "T3D Graphics Console Ver 2.0"
  40. #define WINDOW_WIDTH      640   // size of window
  41. #define WINDOW_HEIGHT     480
  42. #define WINDOW_BPP        8   // bitdepth of window (8,16,24 etc.)
  43.                                 // note: if windowed and not
  44.                                 // fullscreen then bitdepth must
  45.                                 // be same as system bitdepth
  46.                                 // also if 8-bit the a pallete
  47.                                 // is created and attached
  48. #define WINDOWED_APP      0     // 0 not windowed, 1 windowed
  49. // physics demo defines
  50. #define NUM_BALLS       10   // number of pool balls
  51. #define BALL_RADIUS     12   // radius of ball
  52. // extents of table
  53. #define TABLE_MIN_X     100
  54. #define TABLE_MAX_X     500
  55. #define TABLE_MIN_Y     50
  56. #define TABLE_MAX_Y     450
  57. // variable lookup indices
  58. #define INDEX_X               0 
  59. #define INDEX_Y               1  
  60. #define INDEX_XV              2 
  61. #define INDEX_YV              3  
  62. #define INDEX_MASS            4
  63. // MACROS ///////////////////////////////////////////////
  64. #define RAND_RANGE(x,y) ( (x) + (rand()%((y)-(x)+1)))
  65. #define DOT_PRODUCT(ux,uy,vx,vy) ((ux)*(vx) + (uy)*(vy))
  66. // PROTOTYPES /////////////////////////////////////////////
  67. // game console
  68. int Game_Init(void *parms=NULL);
  69. int Game_Shutdown(void *parms=NULL);
  70. int Game_Main(void *parms=NULL);
  71. // GLOBALS ////////////////////////////////////////////////
  72. HWND main_window_handle           = NULL; // save the window handle
  73. HINSTANCE main_instance           = NULL; // save the instance
  74. char buffer[256];                          // used to print text
  75. BITMAP_IMAGE background_bmp;      // holds the background
  76. BOB          balls[NUM_BALLS];    // the balls
  77. int ball_ids[8];                  // sound ids for balls
  78. float cof_E  =    1.0;  // coefficient of restitution, < 1 makes them loose energy
  79.                         // during the collision modeling friction, heat, deformation
  80.                         // etc. > 1 is impossible, but makes them gain energy!
  81. // FUNCTIONS //////////////////////////////////////////////
  82. LRESULT CALLBACK WindowProc(HWND hwnd, 
  83.     UINT msg, 
  84.                             WPARAM wparam, 
  85.                             LPARAM lparam)
  86. {
  87. // this is the main message handler of the system
  88. PAINTSTRUCT ps;    // used in WM_PAINT
  89. HDC hdc;    // handle to a device context
  90. // what is the message 
  91. switch(msg)
  92. {
  93. case WM_CREATE: 
  94.         {
  95. // do initialization stuff here
  96. return(0);
  97. } break;
  98.     case WM_PAINT:
  99.          {
  100.          // start painting
  101.          hdc = BeginPaint(hwnd,&ps);
  102.          // end painting
  103.          EndPaint(hwnd,&ps);
  104.          return(0);
  105.         } break;
  106. case WM_DESTROY: 
  107. {
  108. // kill the application
  109. PostQuitMessage(0);
  110. return(0);
  111. } break;
  112. default:break;
  113.     } // end switch
  114. // process any messages that we didn't take care of 
  115. return (DefWindowProc(hwnd, msg, wparam, lparam));
  116. } // end WinProc
  117. // WINMAIN ////////////////////////////////////////////////
  118. int WINAPI WinMain( HINSTANCE hinstance,
  119. HINSTANCE hprevinstance,
  120. LPSTR lpcmdline,
  121. int ncmdshow)
  122. {
  123. // this is the winmain function
  124. WNDCLASS winclass; // this will hold the class we create
  125. HWND  hwnd; // generic window handle
  126. MSG  msg; // generic message
  127. HDC      hdc;       // generic dc
  128. PAINTSTRUCT ps;     // generic paintstruct
  129. // first fill in the window class stucture
  130. winclass.style = CS_DBLCLKS | CS_OWNDC | 
  131.                           CS_HREDRAW | CS_VREDRAW;
  132. winclass.lpfnWndProc = WindowProc;
  133. winclass.cbClsExtra = 0;
  134. winclass.cbWndExtra = 0;
  135. winclass.hInstance = hinstance;
  136. winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  137. winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  138. winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  139. winclass.lpszMenuName = NULL; 
  140. winclass.lpszClassName = WINDOW_CLASS_NAME;
  141. // register the window class
  142. if (!RegisterClass(&winclass))
  143. return(0);
  144. // create the window, note the test to see if WINDOWED_APP is
  145. // true to select the appropriate window flags
  146. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  147.   WINDOW_TITLE,  // title
  148.   (WINDOWED_APP ? (WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION) : (WS_POPUP | WS_VISIBLE)),
  149.     0,0,    // x,y
  150.   WINDOW_WIDTH,  // width
  151.                           WINDOW_HEIGHT, // height
  152.   NULL,    // handle to parent 
  153.   NULL,    // handle to menu
  154.   hinstance,// instance
  155.   NULL))) // creation parms
  156. return(0);
  157. // save the window handle and instance in a global
  158. main_window_handle = hwnd;
  159. main_instance      = hinstance;
  160. // resize the window so that client is really width x height
  161. if (WINDOWED_APP)
  162. {
  163. // now resize the window, so the client area is the actual size requested
  164. // since there may be borders and controls if this is going to be a windowed app
  165. // if the app is not windowed then it won't matter
  166. RECT window_rect = {0,0,WINDOW_WIDTH-1,WINDOW_HEIGHT-1};
  167. // make the call to adjust window_rect
  168. AdjustWindowRectEx(&window_rect,
  169.      GetWindowStyle(main_window_handle),
  170.      GetMenu(main_window_handle) != NULL,
  171.      GetWindowExStyle(main_window_handle));
  172. // save the global client offsets, they are needed in DDraw_Flip()
  173. window_client_x0 = -window_rect.left;
  174. window_client_y0 = -window_rect.top;
  175. // now resize the window with a call to MoveWindow()
  176. MoveWindow(main_window_handle,
  177.            0, // x position
  178.            0, // y position
  179.            window_rect.right - window_rect.left, // width
  180.            window_rect.bottom - window_rect.top, // height
  181.            FALSE);
  182. // show the window, so there's no garbage on first render
  183. ShowWindow(main_window_handle, SW_SHOW);
  184. } // end if windowed
  185. // perform all game console specific initialization
  186. Game_Init();
  187. // disable CTRL-ALT_DEL, ALT_TAB, comment this line out 
  188. // if it causes your system to crash
  189. SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, NULL, 0);
  190. // enter main event loop
  191. while(1)
  192. {
  193. if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  194. // test if this is a quit
  195.         if (msg.message == WM_QUIT)
  196.            break;
  197. // translate any accelerator keys
  198. TranslateMessage(&msg);
  199. // send the message to the window proc
  200. DispatchMessage(&msg);
  201. } // end if
  202.     
  203.     // main game processing goes here
  204.     Game_Main();
  205. } // end while
  206. // shutdown game and release all resources
  207. Game_Shutdown();
  208. // enable CTRL-ALT_DEL, ALT_TAB, comment this line out 
  209. // if it causes your system to crash
  210. SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, NULL, 0);
  211. // return to Windows like this
  212. return(msg.wParam);
  213. } // end WinMain
  214. // T3D II GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  215. int Game_Init(void *parms)
  216. {
  217. // this function is where you do all the initialization 
  218. // for your game
  219. int index; // looping varsIable
  220. char filename[80]; // used to build up filenames
  221. // seed random number generate
  222. srand(Start_Clock());
  223. // start up DirectDraw (replace the parms as you desire)
  224. DDraw_Init(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, WINDOWED_APP);
  225. // load background image
  226. Load_Bitmap_File(&bitmap8bit, "GREENGRID.BMP");
  227. Create_Bitmap(&background_bmp,0,0,640,480);
  228. Load_Image_Bitmap(&background_bmp, &bitmap8bit,0,0,BITMAP_EXTRACT_MODE_ABS);
  229. Set_Palette(bitmap8bit.palette);
  230. Unload_Bitmap_File(&bitmap8bit);
  231. // load the bitmaps
  232. Load_Bitmap_File(&bitmap8bit, "BALLS8.BMP");
  233. // create master ball
  234. Create_BOB(&balls[0],0,0,24,24,6,BOB_ATTR_MULTI_FRAME | BOB_ATTR_VISIBLE, DDSCAPS_SYSTEMMEMORY);
  235. // load the imagery in
  236. for (index=0; index < 6; index++)
  237.     Load_Frame_BOB(&balls[0], &bitmap8bit, index, index,0,BITMAP_EXTRACT_MODE_CELL);
  238. // create all the clones
  239. for (index=1; index < NUM_BALLS; index++)
  240.     Clone_BOB(&balls[0], &balls[index]);
  241. // now set the initial conditions of all the balls
  242. for (index=0; index < NUM_BALLS; index++)
  243.     {
  244.     // set position randomly
  245.     balls[index].varsF[INDEX_X] = RAND_RANGE(TABLE_MIN_X+20,TABLE_MAX_X-20);
  246.     balls[index].varsF[INDEX_Y] = RAND_RANGE(TABLE_MIN_Y+20,TABLE_MAX_Y-20);
  247.     // set initial velocity
  248.     balls[index].varsF[INDEX_XV] = RAND_RANGE(-100, 100)/15;
  249.     balls[index].varsF[INDEX_YV] = RAND_RANGE(-100, 100)/15;
  250.     // set mass of ball in virtual kgs :)
  251.     balls[index].varsF[INDEX_MASS] = 1; // 1 for now
  252.     // set ball color
  253.     balls[index].curr_frame = rand()%6;
  254.     } // end for index
  255. // unload bitmap image
  256. Unload_Bitmap_File(&bitmap8bit);
  257. // hide the mouse
  258. if (!WINDOWED_APP)
  259. ShowCursor(FALSE);
  260. // initialize directinput
  261. DInput_Init();
  262. // acquire the keyboard only
  263. DInput_Init_Keyboard();
  264. // initilize DirectSound
  265. DSound_Init();
  266. // load background sounds
  267. ball_ids[0] = DSound_Load_WAV("PBALL.WAV");
  268. // clone sounds
  269. for (index=1; index<8; index++)
  270.     ball_ids[index] = DSound_Replicate_Sound(ball_ids[0]);
  271. // set clipping rectangle to screen extents so objects dont
  272. // mess up at edges
  273. RECT screen_rect = {0,0,screen_width,screen_height};
  274. lpddclipper = DDraw_Attach_Clipper(lpddsback,1,&screen_rect);
  275. // set clipping region
  276. min_clip_x = TABLE_MIN_X;
  277. min_clip_y = TABLE_MIN_Y;
  278. max_clip_x = TABLE_MAX_X;
  279. max_clip_y = TABLE_MAX_Y;
  280. // return success
  281. return(1);
  282. } // end Game_Init
  283. ///////////////////////////////////////////////////////////
  284. int Game_Shutdown(void *parms)
  285. {
  286. // this function is where you shutdown your game and
  287. // release all resources that you allocated
  288. // shut everything down
  289. // release all your resources created for the game here....
  290. // kill all the bobs
  291. for (int index=0; index<NUM_BALLS; index++)
  292.     Destroy_BOB(&balls[index]);
  293. // now directsound
  294. DSound_Stop_All_Sounds();
  295. DSound_Delete_All_Sounds();
  296. DSound_Shutdown();
  297. // directmusic
  298. DMusic_Delete_All_MIDI();
  299. DMusic_Shutdown();
  300. // shut down directinput
  301. DInput_Shutdown();
  302. // shutdown directdraw last
  303. DDraw_Shutdown();
  304. // return success
  305. return(1);
  306. } // end Game_Shutdown
  307. //////////////////////////////////////////////////////////
  308. void Ball_Sound(void)
  309. {        
  310. // this functions hunts for an open handle to play a collision sound
  311. // start a hit sound
  312. for (int sound_index=0; sound_index < 8; sound_index++)
  313.     {
  314.     // test if this sound is playing
  315.     if (DSound_Status_Sound(ball_ids[sound_index])==0)
  316.        {
  317.        DSound_Play(ball_ids[sound_index]);
  318.        break;
  319.        } // end if
  320.      } // end for 
  321. } // end Ball_Sound
  322. ///////////////////////////////////////////////////////////
  323. void Collision_Response(void)
  324. {
  325. // this function does all the "real" physics to determine if there has
  326. // been a collision between any ball and any other ball, if there is a collision
  327. // the function uses the mass of each ball along with the intial velocities to 
  328. // compute the resulting velocities
  329. // from the book we know that in general 
  330. // va2 = (e+1)*mb*vb1+va1(ma - e*mb)/(ma+mb)
  331. // vb2 = (e+1)*ma*va1+vb1(ma - e*mb)/(ma+mb)
  332. // and the objects will have direction vectors co-linear to the normal
  333. // of the point of collision, but since we are using spheres here as the objects
  334. // we know that the normal to the point of collision is just the vector from the 
  335. // center's of each object, thus the resulting velocity vector of each ball will
  336. // be along this normal vector direction
  337. // step 1: test each object against each other object and test for a collision
  338. // there are better ways to do this other than a double nested loop, but since
  339. // there are a small number of objects this is fine, also we want to somewhat model
  340. // if two or more balls hit simulataneously
  341. for (int ball_a = 0; ball_a < NUM_BALLS; ball_a++)
  342.      {
  343.      for (int ball_b = ball_a+1; ball_b < NUM_BALLS; ball_b++)
  344.          {
  345.          if (ball_a == ball_b) 
  346.             continue;
  347.          // compute the normal vector from a->b
  348.          float nabx = (balls[ball_b].varsF[INDEX_X] - balls[ball_a].varsF[INDEX_X] );
  349.          float naby = (balls[ball_b].varsF[INDEX_Y] - balls[ball_a].varsF[INDEX_Y] );
  350.          float length = sqrt(nabx*nabx + naby*naby);
  351.          // is there a collision?
  352.          if (length <= 2.0*(BALL_RADIUS*.75))
  353.             {
  354.             // the balls have made contact, compute response
  355.             // compute the response coordinate system axes
  356.             // normalize normal vector
  357.             nabx/=length;
  358.             naby/=length;
  359.             // compute the tangential vector perpendicular to normal, simply rotate vector 90
  360.             float tabx =  -naby;
  361.             float taby =  nabx;
  362.             // draw collision
  363.             DDraw_Lock_Primary_Surface();
  364.             // blue is normal
  365.             Draw_Clip_Line(balls[ball_a].varsF[INDEX_X]+0.5, 
  366.                balls[ball_a].varsF[INDEX_Y]+0.5,
  367.                balls[ball_a].varsF[INDEX_X]+20*nabx+0.5,
  368.                balls[ball_a].varsF[INDEX_Y]+20*naby+0.5,
  369.                252, primary_buffer, primary_lpitch); 
  370.             // yellow is tangential
  371.             Draw_Clip_Line(balls[ball_a].varsF[INDEX_X]+0.5, 
  372.                balls[ball_a].varsF[INDEX_Y]+0.5,
  373.                balls[ball_a].varsF[INDEX_X]+20*tabx+0.5,
  374.                balls[ball_a].varsF[INDEX_Y]+20*taby+0.5,
  375.                251, primary_buffer, primary_lpitch); 
  376.              DDraw_Unlock_Primary_Surface();
  377.             // tangential is also normalized since it's just a rotated normal vector
  378.         
  379.             // step 2: compute all the initial velocities
  380.             // notation ball: (a,b) initial: i, final: f, n: normal direction, t: tangential direction
  381.             float vait = DOT_PRODUCT(balls[ball_a].varsF[INDEX_XV], 
  382.                                      balls[ball_a].varsF[INDEX_YV], 
  383.                                      tabx, taby);
  384.             float vain = DOT_PRODUCT(balls[ball_a].varsF[INDEX_XV], 
  385.                                      balls[ball_a].varsF[INDEX_YV], 
  386.                                      nabx, naby);
  387.             float vbit = DOT_PRODUCT(balls[ball_b].varsF[INDEX_XV], 
  388.                                      balls[ball_b].varsF[INDEX_YV], 
  389.                                      tabx, taby);
  390.             float vbin = DOT_PRODUCT(balls[ball_b].varsF[INDEX_XV], 
  391.                                      balls[ball_b].varsF[INDEX_YV], 
  392.                                      nabx, naby);
  393.             // now we have all the initial velocities in terms of the n and t axes
  394.             // step 3: compute final velocities after collision, from book we have
  395.             // note: all this code can be optimized, but I want you to see what's happening :)
  396.             float ma = balls[ball_a].varsF[INDEX_MASS];
  397.             float mb = balls[ball_b].varsF[INDEX_MASS];
  398.  
  399.             float vafn = (mb*vbin*(cof_E+1) + vain*(ma - cof_E*mb)) / (ma + mb);
  400.             float vbfn = (ma*vain*(cof_E+1) - vbin*(ma - cof_E*mb)) / (ma + mb);
  401.             // now luckily the tangential components are the same before and after, so
  402.             float vaft = vait;
  403.             float vbft = vbit;
  404.             // and that's that baby!
  405.             // the velocity vectors are:
  406.             // object a (vafn, vaft)
  407.             // object b (vbfn, vbft)    
  408.  
  409.             // the only problem is that we are in the wrong coordinate system! we need to 
  410.             // translate back to the original x,y coordinate system, basically we need to 
  411.             // compute the sum of the x components relative to the n,t axes and the sum of
  412.             // the y components relative to the n,t axis, since n,t may both have x,y
  413.             // components in the original x,y coordinate system
  414.             
  415.             float xfa = vafn*nabx + vaft*tabx;
  416.             float yfa = vafn*naby + vaft*taby;
  417.             float xfb = vbfn*nabx + vbft*tabx;
  418.             float yfb = vbfn*naby + vbft*taby;
  419.             // store results
  420.             balls[ball_a].varsF[INDEX_XV] = xfa;
  421.             balls[ball_a].varsF[INDEX_YV] = yfa;
  422.             balls[ball_b].varsF[INDEX_XV] = xfb;
  423.             balls[ball_b].varsF[INDEX_YV] = yfb;
  424.             // update position
  425.             balls[ball_a].varsF[INDEX_X]+=balls[ball_a].varsF[INDEX_XV];
  426.             balls[ball_a].varsF[INDEX_Y]+=balls[ball_a].varsF[INDEX_YV];
  427.             balls[ball_b].varsF[INDEX_X]+=balls[ball_b].varsF[INDEX_XV];
  428.             balls[ball_b].varsF[INDEX_Y]+=balls[ball_b].varsF[INDEX_YV];
  429.             } // end if
  430.          } // end for ball2
  431.      } // end for ball1
  432. } // end Collision_Response
  433. //////////////////////////////////////////////////////////
  434. int Game_Main(void *parms)
  435. {
  436. // this is the workhorse of your game it will be called
  437. // continuously in real-time this is like main() in C
  438. // all the calls for you game go here!
  439. int index; // looping var
  440. // start the timing clock
  441. Start_Clock();
  442. // lock back buffer and copy background into it
  443. DDraw_Lock_Back_Surface();
  444. // draw background
  445. Draw_Bitmap(&background_bmp, back_buffer, back_lpitch,0);
  446. // draw table
  447. HLine(TABLE_MIN_X, TABLE_MAX_X, TABLE_MIN_Y, 250, back_buffer, back_lpitch);
  448. HLine(TABLE_MIN_X, TABLE_MAX_X, TABLE_MAX_Y, 250, back_buffer, back_lpitch);
  449. VLine(TABLE_MIN_Y, TABLE_MAX_Y, TABLE_MIN_X, 250, back_buffer, back_lpitch);
  450. VLine(TABLE_MIN_Y, TABLE_MAX_Y, TABLE_MAX_X, 250, back_buffer, back_lpitch);
  451. // unlock back surface
  452. DDraw_Unlock_Back_Surface();
  453. // read keyboard
  454. DInput_Read_Keyboard();
  455. // check for change of e
  456. if (keyboard_state[DIK_RIGHT])
  457.     cof_E+=.01;
  458. else
  459. if (keyboard_state[DIK_LEFT])
  460.     cof_E-=.01;
  461. float total_ke_x = 0, total_ke_y = 0;
  462. // move all the balls and compute system momentum
  463. for (index=0; index < NUM_BALLS; index++)
  464.     {
  465.     // move the ball
  466.     balls[index].varsF[INDEX_X]+=balls[index].varsF[INDEX_XV];
  467.     balls[index].varsF[INDEX_Y]+=balls[index].varsF[INDEX_YV];
  468.     // add x,y contributions to kinetic energy
  469.     total_ke_x+=(balls[index].varsF[INDEX_XV]*balls[index].varsF[INDEX_XV]*balls[index].varsF[INDEX_MASS]);
  470.     total_ke_y+=(balls[index].varsF[INDEX_YV]*balls[index].varsF[INDEX_YV]*balls[index].varsF[INDEX_MASS]);
  471.     } // end fof
  472.     
  473. // test for boundary collision with virtual table edge, no need for collision
  474. // response here, I know what's going to happen :)
  475. for (index=0; index < NUM_BALLS; index++)
  476.     {
  477.     if ((balls[index].varsF[INDEX_X] >= TABLE_MAX_X-BALL_RADIUS) || 
  478.         (balls[index].varsF[INDEX_X] <= TABLE_MIN_X+BALL_RADIUS))
  479.         {
  480.         // invert velocity
  481.         balls[index].varsF[INDEX_XV] = -balls[index].varsF[INDEX_XV];
  482.         balls[index].varsF[INDEX_X]+=balls[index].varsF[INDEX_XV];
  483.         balls[index].varsF[INDEX_Y]+=balls[index].varsF[INDEX_YV];
  484.         // start a hit sound
  485.         Ball_Sound();
  486.         } // end if
  487.     if ((balls[index].varsF[INDEX_Y] >= TABLE_MAX_Y-BALL_RADIUS) || 
  488.         (balls[index].varsF[INDEX_Y] <= TABLE_MIN_Y+BALL_RADIUS))
  489.         {
  490.         // invert velocity
  491.         balls[index].varsF[INDEX_YV] =-balls[index].varsF[INDEX_YV];
  492.         balls[index].varsF[INDEX_X]+=balls[index].varsF[INDEX_XV];
  493.         balls[index].varsF[INDEX_Y]+=balls[index].varsF[INDEX_YV];
  494.         // play sound
  495.         Ball_Sound();
  496.         } // end if
  497.     } // end for index
  498. // draw the balls
  499. for (index=0; index < NUM_BALLS; index++)
  500.     {
  501.     balls[index].x = balls[index].varsF[INDEX_X]+0.5-BALL_RADIUS;
  502.     balls[index].y = balls[index].varsF[INDEX_Y]+0.5-BALL_RADIUS;
  503.     
  504.     Draw_BOB(&balls[index], lpddsback);
  505.     } // end for
  506. // draw the velocity vectors
  507. DDraw_Lock_Back_Surface();
  508. for (index=0; index < NUM_BALLS; index++)
  509.     {
  510.     Draw_Clip_Line(balls[index].varsF[INDEX_X]+0.5, 
  511.               balls[index].varsF[INDEX_Y]+0.5,
  512.               balls[index].varsF[INDEX_X]+2*balls[index].varsF[INDEX_XV]+0.5,
  513.               balls[index].varsF[INDEX_Y]+2*balls[index].varsF[INDEX_YV]+0.5,
  514.               246, back_buffer, back_lpitch); 
  515.     } // end for
  516. DDraw_Unlock_Back_Surface();
  517. // draw the title
  518. Draw_Text_GDI("ELASTIC Object-Object Collision Response DEMO, Press <ESC> to Exit.",10, 10,RGB(255,255,255), lpddsback);
  519. // draw the title
  520. sprintf(buffer,"Coefficient of Restitution e=%f, use <RIGHT>, <LEFT> arrow to change.", cof_E);
  521. Draw_Text_GDI(buffer,10, 30,RGB(255,255,255), lpddsback);
  522. sprintf(buffer,"Total System Kinetic Energy Sum(1/2MiVi^2)=%f ",0.5*sqrt(total_ke_x*total_ke_x+total_ke_y*total_ke_y));
  523. Draw_Text_GDI(buffer,10, 465, RGB(255,255,255), lpddsback);
  524. // flip the surfaces
  525. DDraw_Flip();
  526. // run collision response algorithm here
  527. Collision_Response();
  528. // sync to 30 fps = 1/30sec = 33 ms
  529. Wait_Clock(33);
  530. // check of user is trying to exit
  531. if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE])
  532.     {
  533.     PostMessage(main_window_handle, WM_DESTROY,0,0);
  534.     // stop all sounds
  535.     DSound_Stop_All_Sounds();
  536.     // do a screen transition
  537.     // Screen_Transitions(SCREEN_GREENNESS,NULL,0);
  538.     } // end if
  539. // return success
  540. return(1);
  541. } // end Game_Main
  542. //////////////////////////////////////////////////////////