raiders3d.cpp
上传用户:husern
上传日期:2018-01-20
资源大小:42486k
文件大小:30k
源码类别:

游戏

开发平台:

Visual C++

  1. // Raiders3D - RAIDERS3D.CPP -- our first 3D game
  2. // READ THIS!
  3. // To compile make sure to include DDRAW.LIB, DSOUND.LIB,
  4. // DINPUT.LIB, WINMM.LIB in the project link list, and of course 
  5. // the C++ source modules T3DLIB1.CPP,T3DLIB2.CPP, and T3DLIB3.CPP
  6. // in the project!!! And the T3DLIB1.H,T3DLIB2.H, and T3DLIB3.H
  7. // header files in the working directory, so the compiler
  8. // can find them
  9. // to run the game make sure that your desktop is in 16bit
  10. // color mode with a resolution of 640x480 or higher
  11. // INCLUDES ///////////////////////////////////////////////
  12. #define INITGUID       // make sure al the COM interfaces are available
  13.                        // instead of this you can include the .LIB file
  14.                        // DXGUID.LIB
  15. #define WIN32_LEAN_AND_MEAN  
  16. #include <windows.h>   // include important windows stuff
  17. #include <windowsx.h> 
  18. #include <mmsystem.h>
  19. #include <iostream.h> // include important C/C++ stuff
  20. #include <conio.h>
  21. #include <stdlib.h>
  22. #include <malloc.h>
  23. #include <memory.h>
  24. #include <string.h>
  25. #include <stdarg.h>
  26. #include <stdio.h> 
  27. #include <math.h>
  28. #include <io.h>
  29. #include <fcntl.h>
  30. #include <ddraw.h>  // directX includes
  31. #include <dsound.h>
  32. #include <dmksctrl.h>
  33. #include <dmusici.h>
  34. #include <dmusicc.h>
  35. #include <dmusicf.h>
  36. #include <dinput.h>
  37. #include "T3DLIB1.h" // game library includes
  38. #include "T3DLIB2.h"
  39. #include "T3DLIB3.h"
  40. // DEFINES ////////////////////////////////////////////////
  41. // defines for windows interface
  42. #define WINDOW_CLASS_NAME "WIN3DCLASS"  // class name
  43. #define WINDOW_TITLE      "T3D Graphics Console Ver 2.0"
  44. #define WINDOW_WIDTH      640   // size of window
  45. #define WINDOW_HEIGHT     480
  46. #define WINDOW_BPP        16   // bitdepth of window (8,16,24 etc.)
  47.                                 // note: if windowed and not
  48.                                 // fullscreen then bitdepth must
  49.                                 // be same as system bitdepth
  50.                                 // also if 8-bit the a pallete
  51.                                 // is created and attached
  52. #define WINDOWED_APP      1     // 0 not windowed, 1 windowed
  53. ////////////////////////////////////////////////////////////
  54. #define NUM_STARS    512  // number of stars in sim
  55. #define NUM_TIES     32   // number of tie fighters in sim
  56. // 3D engine constants
  57. #define NEAR_Z          10   // the near clipping plane
  58. #define FAR_Z           2000 // the far clipping plane    
  59. #define VIEW_DISTANCE   320  // viewing distance from viewpoint 
  60.                              // this gives a field of view of 90 degrees
  61.                              // when projected on a window of 640 wide
  62. // player constants
  63. #define CROSS_VEL       8  // speed that the cross hair moves
  64. #define PLAYER_Z_VEL    8  // virtual z velocity that player is moving
  65.                            // to simulate motion without moving
  66. // tie fighter model constants
  67. #define NUM_TIE_VERTS     10
  68. #define NUM_TIE_EDGES     8
  69. // explosiond
  70. #define NUM_EXPLOSIONS    (NUM_TIES) // total number of explosions
  71. // game states
  72. #define GAME_RUNNING      1
  73. #define GAME_OVER         0
  74. // TYPES ///////////////////////////////////////////////////
  75. // this a 3D point
  76. typedef struct POINT3D_TYP
  77.         {
  78.         USHORT color;     // color of point 16-bit
  79.         float x,y,z;      // coordinates of point in 3D
  80.         } POINT3D, *POINT3D_PTR;
  81. // this is a 3D line, nothing more than two indices into a vertex list
  82. typedef struct LINE3D_TYP
  83.         {
  84.         USHORT color;  // color of line 16-bit
  85.         int v1,v2;     // indices to endpoints of line in vertex list
  86.        
  87.         } LINE3D, *LINE3D_PTR;
  88. // a tie fighter
  89. typedef struct TIE_TYP
  90.         {
  91.         int state;      // state of the tie, 0=dead, 1=alive
  92.         float x, y, z;  // position of the tie
  93.         float xv,yv,zv; // velocity of the tie
  94.         } TIE, *TIE_PTR;
  95. // a basic 3D vector used for velocity
  96. typedef struct VEC3D_TYP
  97.         {
  98.         float x,y,z; // coords of vector
  99.         } VEC3D, *VEC3D_PTR;
  100. // a wireframe explosion
  101. typedef struct EXPL_TYP
  102.        {
  103.        int state;       // state of explosion
  104.        int counter;     // counter for explosion 
  105.        USHORT color;    // color of explosion
  106.        // an explosion is a collection of edges/lines
  107.        // based on the 3D model of the tie that is exploding
  108.        POINT3D p1[NUM_TIE_EDGES];  // start point of edge n
  109.        POINT3D p2[NUM_TIE_EDGES];  // end point of edge n
  110.          
  111.        VEC3D   vel[NUM_TIE_EDGES]; // velocity of shrapnel
  112.        } EXPL, *EXPL_PTR;
  113. // PROTOTYPES /////////////////////////////////////////////
  114. // game console
  115. int Game_Init(void *parms=NULL);
  116. int Game_Shutdown(void *parms=NULL);
  117. int Game_Main(void *parms=NULL);
  118. // game functions
  119. void Init_Tie(int index);
  120. // GLOBALS ////////////////////////////////////////////////
  121. HWND main_window_handle           = NULL; // save the window handle
  122. HINSTANCE main_instance           = NULL; // save the instance
  123. char buffer[256];                         // used to print text
  124. // the tie fighter is a collection of vertices connected by
  125. // lines that make up the shape. only one tie fighter see if 
  126. // you can replicate it?
  127. POINT3D tie_vlist[NUM_TIE_VERTS]; // vertex list for the tie fighter model
  128. LINE3D  tie_shape[NUM_TIE_EDGES]; // edge list for the tie fighter model
  129. TIE     ties[NUM_TIES];           // tie fighters
  130. POINT3D stars[NUM_STARS]; // the starfield
  131. // some colors, note we can't build them until we know the bit
  132. // depth format 5.5.5 or 5.6.5, so we wait a minute and do it in the
  133. // Game_Init() function
  134. USHORT rgb_green,  
  135.        rgb_white,
  136.        rgb_red,
  137.        rgb_blue;
  138. // player vars
  139. float cross_x = 0, // cross hairs
  140.       cross_y = 0; 
  141. int cross_x_screen  = WINDOW_WIDTH/2,   // used for cross hair
  142.     cross_y_screen  = WINDOW_HEIGHT/2, 
  143.     target_x_screen = WINDOW_WIDTH/2,   // used for targeter
  144.     target_y_screen = WINDOW_HEIGHT/2;
  145. int player_z_vel = 4; // virtual speed of viewpoint/ship
  146. int cannon_state = 0; // state of laser cannon
  147. int cannon_count = 0; // laster cannon counter
  148. EXPL explosions[NUM_EXPLOSIONS]; // the explosiions
  149. int misses = 0; // tracks number of missed ships
  150. int hits   = 0; // tracks number of hits
  151. int score  = 0; // take a guess :)
  152. // music and sound stuff
  153. int main_track_id = -1, // main music track id
  154.     laser_id      = -1, // sound of laser pulse
  155.     explosion_id  = -1, // sound of explosion
  156.     flyby_id      = -1; // sound of tie fighter flying by
  157. int game_state = GAME_RUNNING; // state of game
  158. // FUNCTIONS //////////////////////////////////////////////
  159. LRESULT CALLBACK WindowProc(HWND hwnd, 
  160.     UINT msg, 
  161.                             WPARAM wparam, 
  162.                             LPARAM lparam)
  163. {
  164. // this is the main message handler of the system
  165. PAINTSTRUCT ps;    // used in WM_PAINT
  166. HDC hdc;    // handle to a device context
  167. // what is the message 
  168. switch(msg)
  169. {
  170. case WM_CREATE: 
  171.         {
  172. // do initialization stuff here
  173. return(0);
  174. } break;
  175.     case WM_PAINT:
  176.          {
  177.          // start painting
  178.          hdc = BeginPaint(hwnd,&ps);
  179.          // end painting
  180.          EndPaint(hwnd,&ps);
  181.          return(0);
  182.         } break;
  183. case WM_DESTROY: 
  184. {
  185. // kill the application
  186. PostQuitMessage(0);
  187. return(0);
  188. } break;
  189. default:break;
  190.     } // end switch
  191. // process any messages that we didn't take care of 
  192. return (DefWindowProc(hwnd, msg, wparam, lparam));
  193. } // end WinProc
  194. // WINMAIN ////////////////////////////////////////////////
  195. int WINAPI WinMain( HINSTANCE hinstance,
  196. HINSTANCE hprevinstance,
  197. LPSTR lpcmdline,
  198. int ncmdshow)
  199. {
  200. // this is the winmain function
  201. WNDCLASS winclass; // this will hold the class we create
  202. HWND  hwnd; // generic window handle
  203. MSG  msg; // generic message
  204. HDC      hdc;       // generic dc
  205. PAINTSTRUCT ps;     // generic paintstruct
  206. // first fill in the window class stucture
  207. winclass.style = CS_DBLCLKS | CS_OWNDC | 
  208.                           CS_HREDRAW | CS_VREDRAW;
  209. winclass.lpfnWndProc = WindowProc;
  210. winclass.cbClsExtra = 0;
  211. winclass.cbWndExtra = 0;
  212. winclass.hInstance = hinstance;
  213. winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  214. winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  215. winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
  216. winclass.lpszMenuName = NULL; 
  217. winclass.lpszClassName = WINDOW_CLASS_NAME;
  218. // register the window class
  219. if (!RegisterClass(&winclass))
  220. return(0);
  221. // create the window, note the test to see if WINDOWED_APP is
  222. // true to select the appropriate window flags
  223. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  224.   WINDOW_TITLE,  // title
  225.   (WINDOWED_APP ? (WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION) : (WS_POPUP | WS_VISIBLE)),
  226.     0,0,    // x,y
  227.   WINDOW_WIDTH,  // width
  228.                           WINDOW_HEIGHT, // height
  229.   NULL,    // handle to parent 
  230.   NULL,    // handle to menu
  231.   hinstance,// instance
  232.   NULL))) // creation parms
  233. return(0);
  234. // save the window handle and instance in a global
  235. main_window_handle = hwnd;
  236. main_instance      = hinstance;
  237. // resize the window so that client is really width x height
  238. if (WINDOWED_APP)
  239. {
  240. // now resize the window, so the client area is the actual size requested
  241. // since there may be borders and controls if this is going to be a windowed app
  242. // if the app is not windowed then it won't matter
  243. RECT window_rect = {0,0,WINDOW_WIDTH-1,WINDOW_HEIGHT-1};
  244. // make the call to adjust window_rect
  245. AdjustWindowRectEx(&window_rect,
  246.      GetWindowStyle(main_window_handle),
  247.      GetMenu(main_window_handle) != NULL,
  248.      GetWindowExStyle(main_window_handle));
  249. // save the global client offsets, they are needed in DDraw_Flip()
  250. window_client_x0 = -window_rect.left;
  251. window_client_y0 = -window_rect.top;
  252. // now resize the window with a call to MoveWindow()
  253. MoveWindow(main_window_handle,
  254.            0, // x position
  255.            0, // y position
  256.            window_rect.right - window_rect.left, // width
  257.            window_rect.bottom - window_rect.top, // height
  258.            FALSE);
  259. // show the window, so there's no garbage on first render
  260. ShowWindow(main_window_handle, SW_SHOW);
  261. } // end if windowed
  262. // perform all game console specific initialization
  263. Game_Init();
  264. // disable CTRL-ALT_DEL, ALT_TAB, comment this line out 
  265. // if it causes your system to crash
  266. SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, NULL, 0);
  267. // enter main event loop
  268. while(1)
  269. {
  270. if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  271. // test if this is a quit
  272.         if (msg.message == WM_QUIT)
  273.            break;
  274. // translate any accelerator keys
  275. TranslateMessage(&msg);
  276. // send the message to the window proc
  277. DispatchMessage(&msg);
  278. } // end if
  279.     
  280.     // main game processing goes here
  281.     Game_Main();
  282. } // end while
  283. // shutdown game and release all resources
  284. Game_Shutdown();
  285. // enable CTRL-ALT_DEL, ALT_TAB, comment this line out 
  286. // if it causes your system to crash
  287. SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, NULL, 0);
  288. // return to Windows like this
  289. return(msg.wParam);
  290. } // end WinMain
  291. // T3D II GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  292. int Game_Init(void *parms)
  293. {
  294. // this function is where you do all the initialization 
  295. // for your game
  296. int index; // used for looping
  297. Open_Error_File("error.txt");
  298. // start up DirectDraw (replace the parms as you desire)
  299. DDraw_Init(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, WINDOWED_APP);
  300. // initialize directinput
  301. DInput_Init();
  302. // acquire the keyboard 
  303. DInput_Init_Keyboard();
  304. // initialize directsound
  305. DSound_Init();
  306. // load in sound fx
  307. explosion_id = DSound_Load_WAV("exp1.wav");
  308. laser_id     = DSound_Load_WAV("shocker.wav");
  309. // initialize directmusic
  310. DMusic_Init();
  311. // load and start main music track
  312. main_track_id = DMusic_Load_MIDI("midifile2.mid");
  313. DMusic_Play(main_track_id);
  314. // add calls to acquire other directinput devices here...
  315. // hide the mouse
  316. if (!WINDOWED_APP)
  317.    ShowCursor(FALSE);
  318. // seed random number generator
  319. srand(Start_Clock());
  320. // all your initialization code goes here...
  321. // create system colors
  322. rgb_green = RGB16Bit(0,255,0);
  323. rgb_white = RGB16Bit(255,255,255);
  324. rgb_blue  = RGB16Bit(0,0,255);
  325. rgb_red   = RGB16Bit(255,0,0);
  326. // create the starfield
  327. for (index=0; index < NUM_STARS; index++)
  328.     {
  329.     // randomly position stars in an elongated cylinder stretching from
  330.     // the viewpoint 0,0,-d to the yon clipping plane 0,0,far_z
  331.     stars[index].x = -WINDOW_WIDTH/2  + rand()%WINDOW_WIDTH;
  332.     stars[index].y = -WINDOW_HEIGHT/2 + rand()%WINDOW_HEIGHT;
  333.     stars[index].z = NEAR_Z + rand()%(FAR_Z - NEAR_Z);
  334.     // set color of stars
  335.     stars[index].color = rgb_white;
  336.     } // end for index
  337. // create the tie fighter model
  338. // the vertex list for the tie fighter
  339. POINT3D temp_tie_vlist[NUM_TIE_VERTS] = 
  340. // color, x,y,z
  341. { {rgb_white,-40,40,0},    // p0
  342.   {rgb_white,-40,0,0},    // p1
  343.   {rgb_white,-40,-40,0},   // p2
  344.   {rgb_white,-10,0,0},    // p3
  345.   {rgb_white,0,20,0},     // p4
  346.   {rgb_white,10,0,0},     // p5
  347.   {rgb_white,0,-20,0},    // p6
  348.   {rgb_white,40,40,0},     // p7
  349.   {rgb_white,40,0,0},     // p8
  350.   {rgb_white,40,-40,0}};   // p9
  351. // copy the model into the real global arrays
  352. for (index=0; index<NUM_TIE_VERTS; index++)
  353.      tie_vlist[index] = temp_tie_vlist[index];
  354.   
  355. // the edge list for the tie fighter
  356. LINE3D temp_tie_shape[NUM_TIE_EDGES] = 
  357. // color, vertex 1, vertex 2
  358. { {rgb_green,0,2      },    // l0
  359.   {rgb_green,1,3      },    // l1
  360.   {rgb_green,3,4      },    // l2
  361.   {rgb_green,4,5      },    // l3
  362.   {rgb_green,5,6      },    // l4
  363.   {rgb_green,6,3      },    // l5
  364.   {rgb_green,5,8      },    // l6
  365.   {rgb_green,7,9      } };  // l7
  366. // copy the model into the real global arrays
  367. for (index=0; index<NUM_TIE_EDGES; index++)
  368.      tie_shape[index] = temp_tie_shape[index];
  369. // initialize the position of each tie fighter and it's velocity
  370. for (index=0; index<NUM_TIES; index++)
  371.     {
  372.     // initialize this tie fighter
  373.     Init_Tie(index);
  374.     } // end for index
  375. // return success
  376. return(1);
  377. } // end Game_Init
  378. ///////////////////////////////////////////////////////////
  379. int Game_Shutdown(void *parms)
  380. {
  381. // this function is where you shutdown your game and
  382. // release all resources that you allocated
  383. // shut everything down
  384. // release all your resources created for the game here....
  385. // now directsound
  386. DSound_Stop_All_Sounds();
  387. DSound_Shutdown();
  388. // directmusic
  389. DMusic_Delete_All_MIDI();
  390. DMusic_Shutdown();
  391. // shut down directinput
  392. DInput_Shutdown();
  393. // shutdown directdraw last
  394. DDraw_Shutdown();
  395. // return success
  396. return(1);
  397. } // end Game_Shutdown
  398. //////////////////////////////////////////////////////////
  399. void Start_Explosion(int tie)
  400. {
  401. // this starts an explosion based on the sent tie fighter
  402. // first hunt and see if an explosion is free
  403. for (int index=0; index < NUM_EXPLOSIONS; index++)
  404.     {
  405.     if (explosions[index].state==0)
  406.        {
  407.        // start this explosion up using the properties
  408.        // if the tie figther index sent
  409.        explosions[index].state   = 1; // enable state of explosion
  410.        explosions[index].counter = 0; // reset counter for explosion 
  411.        // set color of explosion
  412.        explosions[index].color = rgb_green;
  413.        // make copy of of edge list, so we can blow it up
  414.        for (int edge=0; edge < NUM_TIE_EDGES; edge++)
  415.            {
  416.            // start point of edge
  417.            explosions[index].p1[edge].x = ties[tie].x+tie_vlist[tie_shape[edge].v1].x;
  418.            explosions[index].p1[edge].y = ties[tie].y+tie_vlist[tie_shape[edge].v1].y;
  419.            explosions[index].p1[edge].z = ties[tie].z+tie_vlist[tie_shape[edge].v1].z;
  420.  
  421.            // end point of edge
  422.            explosions[index].p2[edge].x = ties[tie].x+tie_vlist[tie_shape[edge].v2].x;
  423.            explosions[index].p2[edge].y = ties[tie].y+tie_vlist[tie_shape[edge].v2].y;
  424.            explosions[index].p2[edge].z = ties[tie].z+tie_vlist[tie_shape[edge].v2].z;
  425.            // compute trajectory vector for edges
  426.            explosions[index].vel[edge].x = ties[tie].xv - 8+rand()%16;
  427.            explosions[index].vel[edge].y = ties[tie].yv - 8+rand()%16;
  428.            explosions[index].vel[edge].z = -3+rand()%4;
  429.            } // end for edge
  430.      
  431.        // done, so return
  432.        return;
  433.        } // end if found
  434.     } // end for index
  435. } // end Start_Explosion
  436. ///////////////////////////////////////////////////////////
  437. void Process_Explosions(void)
  438. {
  439. // this processes all the explosions
  440. // loop thro all the explosions and render them
  441. for (int index=0; index<NUM_EXPLOSIONS; index++)
  442.     {
  443.     // test if this explosion is active?
  444.     if (explosions[index].state==0)
  445.        continue;
  446.     for (int edge=0; edge<NUM_TIE_EDGES; edge++)
  447.         {
  448.         // must be exploding, update edges (shrapel)
  449.         explosions[index].p1[edge].x+=explosions[index].vel[edge].x;
  450.         explosions[index].p1[edge].y+=explosions[index].vel[edge].y;
  451.         explosions[index].p1[edge].z+=explosions[index].vel[edge].z;
  452.         explosions[index].p2[edge].x+=explosions[index].vel[edge].x;
  453.         explosions[index].p2[edge].y+=explosions[index].vel[edge].y;
  454.         explosions[index].p2[edge].z+=explosions[index].vel[edge].z;
  455.         } // end for edge
  456.     // test for terminatation of explosion?
  457.     if (++explosions[index].counter > 100)
  458.        explosions[index].state = explosions[index].counter = 0;            
  459.     } // end for index
  460. } // end Process_Explosions
  461. ///////////////////////////////////////////////////////////
  462. void Draw_Explosions(void)
  463. {
  464. // this draws all the explosions
  465. // loop thro all the explosions and render them
  466. for (int index=0; index<NUM_EXPLOSIONS; index++)
  467.     {
  468.     // test if this explosion is active?
  469.     if (explosions[index].state==0)
  470.        continue;
  471.     // render this explosion
  472.     // each explosion is made of a number of edges
  473.     for (int edge=0; edge < NUM_TIE_EDGES; edge++)
  474.     {
  475.     POINT3D p1_per, p2_per; // used to hold perspective endpoints
  476.     
  477.     // test if edge if beyond near clipping plane
  478.     if (explosions[index].p1[edge].z < NEAR_Z && 
  479.         explosions[index].p2[edge].z < NEAR_Z)
  480.        continue;
  481.    
  482.     // step 1: perspective transform each end point
  483.     p1_per.x = VIEW_DISTANCE*explosions[index].p1[edge].x/explosions[index].p1[edge].z;
  484.     p1_per.y = VIEW_DISTANCE*explosions[index].p1[edge].y/explosions[index].p1[edge].z;
  485.     p2_per.x = VIEW_DISTANCE*explosions[index].p2[edge].x/explosions[index].p2[edge].z;
  486.     p2_per.y = VIEW_DISTANCE*explosions[index].p2[edge].y/explosions[index].p2[edge].z;
  487.     // step 2: compute screen coords
  488.     int p1_screen_x = WINDOW_WIDTH/2  + p1_per.x;
  489.     int p1_screen_y = WINDOW_HEIGHT/2 - p1_per.y;
  490.     int p2_screen_x = WINDOW_WIDTH/2  + p2_per.x;
  491.     int p2_screen_y = WINDOW_HEIGHT/2 - p2_per.y;
  492.     // step 3: draw the edge
  493.     Draw_Clip_Line16(p1_screen_x, p1_screen_y, p2_screen_x, p2_screen_y,
  494.                      explosions[index].color,back_buffer, back_lpitch);    
  495.     } // end for edge
  496.     } // end for index
  497. } // end Draw_Explosions
  498. //////////////////////////////////////////////////////////
  499. void Move_Starfield(void)
  500. {
  501. // move the stars
  502. int index; // looping var
  503. // the stars are technically stationary,but we are going
  504. // to move them to simulate motion of the viewpoint
  505. for (index=0; index<NUM_STARS; index++)
  506.     {
  507.     // move the next star
  508.     stars[index].z-=player_z_vel;
  509.     // test for past near clipping plane
  510.     if (stars[index].z <= NEAR_Z)
  511.         stars[index].z = FAR_Z;
  512.     } // end for index
  513. } // end Move_Starfield
  514. /////////////////////////////////////////////////////////
  515. void Draw_Starfield(void)
  516. {
  517. // draw the stars in 3D using perspective transform
  518. int index; // looping var
  519. for (index=0; index<NUM_STARS; index++)
  520.     {
  521.     // draw the next star
  522.     // step 1: perspective transform
  523.     float x_per = VIEW_DISTANCE*stars[index].x/stars[index].z;
  524.     float y_per = VIEW_DISTANCE*stars[index].y/stars[index].z;
  525.     
  526.     // step 2: compute screen coords
  527.     int x_screen = WINDOW_WIDTH/2  + x_per;
  528.     int y_screen = WINDOW_HEIGHT/2 - y_per;
  529.     // clip to screen coords
  530.     if (x_screen>=WINDOW_WIDTH || x_screen < 0 || 
  531.         y_screen >= WINDOW_HEIGHT || y_screen < 0)
  532.        {
  533.        // continue to next star
  534.        continue; 
  535.        } // end if
  536.     else
  537.        {
  538.        // else render to buffer
  539.        ((USHORT *)back_buffer)[x_screen + y_screen*(back_lpitch >> 1)] 
  540.                               = stars[index].color;
  541.        } // end else
  542.     } // end for index
  543. }  // Draw_Starfield
  544. /////////////////////////////////////////////////////////
  545. void Init_Tie(int index)
  546. {
  547. // this function starts a tie fighter up at the far end
  548. // of the universe and sends it our way!
  549. // position each tie in the viewing volume
  550. ties[index].x = -WINDOW_WIDTH  + rand()%(2*WINDOW_WIDTH);
  551. ties[index].y = -WINDOW_HEIGHT + rand()%(2*WINDOW_HEIGHT);
  552. ties[index].z =  4*FAR_Z;
  553. // initialize velocity of tie fighter
  554. ties[index].xv = -4+rand()%8;
  555. ties[index].yv = -4+rand()%8;
  556. ties[index].zv = -4-rand()%64;
  557. // turn the tie fighter on
  558. ties[index].state = 1;
  559. } // end Init_Tie
  560. /////////////////////////////////////////////////////////
  561. void Process_Ties(void)
  562. {
  563. // process the tie fighters and do AI (what there is of it!)
  564. int index; // looping var
  565. // move each tie fighter toward the viewpoint
  566. for (index=0; index<NUM_TIES; index++)
  567.     {
  568.     // is this one dead?
  569.     if (ties[index].state==0)
  570.        continue;
  571.     // move the next star
  572.     ties[index].z+=ties[index].zv;
  573.     ties[index].x+=ties[index].xv;
  574.     ties[index].y+=ties[index].yv;
  575.     // test for past near clipping plane
  576.     if (ties[index].z <= NEAR_Z)
  577.        {
  578.        // reset this tie
  579.        Init_Tie(index);
  580.        // another got away
  581.        misses++;
  582.        } // reset tie
  583.     } // end for index
  584. }  // Process_Ties
  585. //////////////////////////////////////////////////////////
  586. void Draw_Ties(void)
  587. {
  588. // draw the tie fighters in 3D wireframe with perspective
  589. int index; // looping var
  590. // used to compute the bounding box of tie fighter
  591. // for collision detection
  592. int bmin_x, bmin_y, bmax_x, bmax_y; 
  593. // draw each tie fighter
  594. for (index=0; index < NUM_TIES; index++)
  595.     {
  596.     // draw the next tie fighter
  597.     // is this one dead?
  598.     if (ties[index].state==0)
  599.        continue;
  600.     // reset the bounding box to impossible values
  601.     bmin_x =  100000;
  602.     bmax_x = -100000;
  603.     bmin_y =  100000;
  604.     bmax_y = -100000;
  605.     // based on z-distance shade tie fighter
  606.     // normalize the distance from 0 to max_z then
  607.     // scale it to 255, so the closer the brighter
  608.     USHORT rgb_tie_color = RGB16Bit(0,(255-255*(ties[index].z/(4*FAR_Z))),0);
  609.     // each tie fighter is made of a number of edges
  610.     for (int edge=0; edge < NUM_TIE_EDGES; edge++)
  611.     {
  612.     POINT3D p1_per, p2_per; // used to hold perspective endpoints
  613.       
  614.     // step 1: perspective transform each end point
  615.     // note the translation of each point to the position of the tie fighter
  616.     // that is the model is relative to the position of each tie fighter -- IMPORTANT
  617.     p1_per.x = 
  618.             VIEW_DISTANCE*(ties[index].x+tie_vlist[tie_shape[edge].v1].x)/
  619.             (tie_vlist[tie_shape[edge].v1].z+ties[index].z);
  620.         
  621.     p1_per.y = VIEW_DISTANCE*(ties[index].y+tie_vlist[tie_shape[edge].v1].y)/
  622.                (tie_vlist[tie_shape[edge].v1].z+ties[index].z);
  623.     p2_per.x = VIEW_DISTANCE*(ties[index].x+tie_vlist[tie_shape[edge].v2].x)/
  624.                (tie_vlist[tie_shape[edge].v2].z+ties[index].z);
  625.         
  626.     p2_per.y = VIEW_DISTANCE*(ties[index].y+tie_vlist[tie_shape[edge].v2].y)/
  627.                (tie_vlist[tie_shape[edge].v2].z+ties[index].z);
  628.     // step 2: compute screen coords
  629.     int p1_screen_x = WINDOW_WIDTH/2  + p1_per.x;
  630.     int p1_screen_y = WINDOW_HEIGHT/2 - p1_per.y;
  631.     int p2_screen_x = WINDOW_WIDTH/2  + p2_per.x;
  632.     int p2_screen_y = WINDOW_HEIGHT/2 - p2_per.y;
  633.     // step 3: draw the edge
  634.     Draw_Clip_Line16(p1_screen_x, p1_screen_y, p2_screen_x, p2_screen_y,
  635.                      rgb_tie_color,back_buffer, back_lpitch);
  636.     // update bounding box with next edge
  637.     int min_x = min(p1_screen_x, p2_screen_x);
  638.     int max_x = max(p1_screen_x, p2_screen_x);
  639.     int min_y = min(p1_screen_y, p2_screen_y);
  640.     int max_y = max(p1_screen_y, p2_screen_y);
  641.     bmin_x = min(bmin_x, min_x);
  642.     bmin_y = min(bmin_y, min_y);
  643.     bmax_x = max(bmax_x, max_x);
  644.     bmax_y = max(bmax_y, max_y);
  645.         
  646.     } // end for edge
  647.     // test if this guy has been hit by lasers???
  648.     if (cannon_state==1)
  649.        {
  650.        // simple test of screen coords of bounding box contain laser target
  651.        if (target_x_screen > bmin_x && target_x_screen < bmax_x &&
  652.            target_y_screen > bmin_y && target_y_screen < bmax_y)
  653.          {
  654.          // this tie is dead meat!
  655.          Start_Explosion(index);
  656.          // start sound
  657.          DSound_Play(explosion_id );
  658.          // increase score
  659.          score+=ties[index].z;
  660.          // add one more hit
  661.          hits++;
  662.          // finally reset this tie figher
  663.          Init_Tie(index);
  664.          
  665.          } // end if
  666.        } // end if
  667.     } // end for index
  668. } // end Draw_Ties
  669. //////////////////////////////////////////////////////////
  670. int Game_Main(void *parms)
  671. {
  672. // this is the workhorse of your game it will be called
  673. // continuously in real-time this is like main() in C
  674. // all the calls for your game go here!
  675. int        index;       // looping var
  676. // start the timing clock
  677. Start_Clock();
  678. // clear the drawing surface 
  679. DDraw_Fill_Surface(lpddsback, 0);
  680. // read keyboard and other devices here
  681. DInput_Read_Keyboard();
  682. // game logic here...
  683. if (game_state==GAME_RUNNING)
  684. {
  685. // move players crosshair
  686. if (keyboard_state[DIK_RIGHT])
  687.    {
  688.    // move cross hair to right
  689.    cross_x+=CROSS_VEL;
  690.    // test for wraparound
  691.    if (cross_x > WINDOW_WIDTH/2)
  692.       cross_x = -WINDOW_WIDTH/2;   
  693.    } // end if
  694. if (keyboard_state[DIK_LEFT])
  695.    {
  696.    // move cross hair to left
  697.    cross_x-=CROSS_VEL;
  698.    // test for wraparound
  699.    if (cross_x < -WINDOW_WIDTH/2)
  700.       cross_x = WINDOW_WIDTH/2;   
  701.    } // end if
  702. if (keyboard_state[DIK_DOWN])
  703.    {
  704.    // move cross hair up
  705.    cross_y-=CROSS_VEL;
  706.    // test for wraparound
  707.    if (cross_y < -WINDOW_HEIGHT/2)
  708.       cross_y = WINDOW_HEIGHT/2;   
  709.    } // end if
  710. if (keyboard_state[DIK_UP])
  711.    {
  712.    // move cross hair up
  713.    cross_y+=CROSS_VEL;
  714.    // test for wraparound
  715.    if (cross_y > WINDOW_HEIGHT/2)
  716.       cross_y = -WINDOW_HEIGHT/2;   
  717.    } // end if
  718. // speed of ship controls
  719. if (keyboard_state[DIK_A])
  720.    player_z_vel++;
  721. else
  722. if (keyboard_state[DIK_S])
  723.    player_z_vel--;
  724. // test if player is firing laser cannon
  725. if (keyboard_state[DIK_SPACE] && cannon_state==0)
  726.    {
  727.    // fire the cannon
  728.    cannon_state = 1;
  729.    cannon_count = 0;
  730.    // save last position of targeter
  731.    target_x_screen = cross_x_screen;
  732.    target_y_screen = cross_y_screen;
  733.    // make sound
  734.    DSound_Play(laser_id);
  735.    } // end if   
  736. } // end if game running
  737. // process cannon, simple FSM ready->firing->cool
  738. // firing phase
  739. if (cannon_state == 1)
  740.    if (++cannon_count > 15)
  741.       cannon_state = 2;
  742. // cool down phase
  743. if (cannon_state == 2)
  744.    if (++cannon_count > 20)
  745.       cannon_state = 0;
  746. // move the starfield
  747. Move_Starfield();
  748. // move and perform ai for ties
  749. Process_Ties();
  750. // Process the explosions
  751. Process_Explosions();
  752. // lock the back buffer and obtain pointer and width
  753. DDraw_Lock_Back_Surface();
  754. // draw the starfield
  755. Draw_Starfield();
  756. // draw the tie fighters
  757. Draw_Ties();
  758. // draw the explosions
  759. Draw_Explosions();
  760. // draw the crosshairs 
  761. // first compute screen coords of crosshair
  762. // note inversion of y-axis
  763. cross_x_screen = WINDOW_WIDTH/2  + cross_x;
  764. cross_y_screen = WINDOW_HEIGHT/2 - cross_y;
  765. // draw the crosshair in screen coords
  766. Draw_Clip_Line16(cross_x_screen-16,cross_y_screen,
  767.                  cross_x_screen+16,cross_y_screen,
  768.                  rgb_red,back_buffer,back_lpitch);
  769. Draw_Clip_Line16(cross_x_screen,cross_y_screen-16,
  770.                  cross_x_screen,cross_y_screen+16,
  771.                  rgb_red,back_buffer,back_lpitch);
  772. Draw_Clip_Line16(cross_x_screen-16,cross_y_screen-4,
  773.                  cross_x_screen-16,cross_y_screen+4,
  774.                  rgb_red,back_buffer,back_lpitch);
  775. Draw_Clip_Line16(cross_x_screen+16,cross_y_screen-4,
  776.                  cross_x_screen+16,cross_y_screen+4,
  777.                  rgb_red,back_buffer,back_lpitch);
  778. // draw the laser beams
  779. if (cannon_state == 1)
  780.    {
  781.    if ((rand()%2 == 1))
  782.       { 
  783.       // right beam
  784.       Draw_Clip_Line16(WINDOW_WIDTH-1, WINDOW_HEIGHT-1,
  785.              -4+rand()%8+target_x_screen,-4+rand()%8+target_y_screen,
  786.              RGB16Bit(0,0,rand()),back_buffer,back_lpitch);
  787.       } // end if    
  788.    else
  789.       {
  790.       // left beam
  791.       Draw_Clip_Line16(0, WINDOW_HEIGHT-1,
  792.              -4+rand()%8+target_x_screen,-4+rand()%8+target_y_screen,
  793.              RGB16Bit(0,0,rand()),back_buffer,back_lpitch);
  794.       } // end if
  795.    } // end if
  796. // done rendering, unlock back buffer surface
  797. DDraw_Unlock_Back_Surface();
  798. // draw the informtion
  799. sprintf(buffer, "Score %d     Kills %d      Escaped %d", score, hits, misses);
  800. Draw_Text_GDI(buffer, 0,0,RGB(0,255,0), lpddsback);
  801. if (game_state==GAME_OVER)
  802.     Draw_Text_GDI("G A M E  O V E R", WINDOW_WIDTH/2-8*10,WINDOW_HEIGHT/2,RGB(255,255,255), lpddsback);
  803. // check if the music has finished, if so restart
  804. if (DMusic_Status_MIDI(main_track_id)==MIDI_STOPPED)
  805.     DMusic_Play(main_track_id);
  806. // flip the surfaces
  807. DDraw_Flip();
  808. // sync to 30ish fps
  809. Wait_Clock(30);
  810. // check for game state switch
  811. if (misses > 4*NUM_TIES)
  812.    game_state = GAME_OVER;
  813. // check of user is trying to exit
  814. if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE])
  815.     {
  816.     PostMessage(main_window_handle, WM_DESTROY,0,0);
  817.     } // end if
  818. // return success
  819. return(1);
  820.  
  821. } // end Game_Main
  822. //////////////////////////////////////////////////////////