1 / 38

3D Game Programming

3D Game Programming. CIS 488/588 Bruce R. Maxim UM-Dearborn. Recommended Tools - 1. C/C++ Compilers Visual C++ produces fastest .exe code 2D Bitmap Art Paintshop Pro or Adobe Photoshop 2D Vector Art Adobe Illustrator Postproduction Image Processing Adobe Photoshop or Corel Photo-Paint.

tarellano
Download Presentation

3D Game Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 3D Game Programming CIS 488/588 Bruce R. Maxim UM-Dearborn

  2. Recommended Tools - 1 • C/C++ Compilers • Visual C++ produces fastest .exe code • 2D Bitmap Art • Paintshop Pro or Adobe Photoshop • 2D Vector Art • Adobe Illustrator • Postproduction Image Processing • Adobe Photoshop or Corel Photo-Paint

  3. Recommended Tools - 2 • Sound Processing • Sound Forge or Cool Edit Pro • 3D Modelers • Caligari trueSpace or 3D Studio Max • 3D Level Editors • Warcraft Level Editor or equivalent • Midi Sequencing • Cakewalk

  4. Using Visual C++ • DirectX 9.0 SDK is required • Plan on building Win32 .exe application programs (not .dll or console application) • Use debug .exe files during development and release .exe files when finished • Use “add files” option to add source files to the project node itself • Include search paths for DirectX header files and .lib using “directory” option in main menu

  5. LaMothe 3D Example

  6. Raiders 3D • Change into graphics mode using DirectX • Draw colored lines, pixels, and text strings • Get keyboard input • Play .wav file from disk • Play mid from from disk • Timing functions to synchronize game loop • Copy double buffer to display screen

  7. RAIDERS.CPP T3DLIB1.CPP T3DLIB2.CPP T3DLIB3.CPP DDRAW.LIB DINPUT.LIB DINPUT8.LIB DSOUND.LIB DXGUID.LIB DINPUT.DLL DINPUT8.DLL DDRAW.DLL DSOUND.DLL DMUSIC.DLL 3D Resources Needed

  8. #include <windows.h> #include <windowsx.h> #include <mmsystem.h> #include <iostream.h> #include <conio.h> #include <stdlib.h> #include <malloc.h> #include <memory.h> #include <string.h> #include <stdarg.h> #include <stdio.h> #include <math.h> #include <io.h> #include <fcntl.h> #include <ddraw.h> #include <dsound.h> #include <dmksctrl.h> #include <dmusici.h> #include <dmusicc.h> #include <dmusicf.h> #include <dinput.h> #include "T3DLIB1.h" // game library includes #include "T3DLIB2.h" #include "T3DLIB3.h" Include Files

  9. WinMain - 1 int WINAPI WinMain( HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { WNDCLASS winclass; // our windows class HWND hwnd; // generic window handle MSG msg; // generic message HDC hdc; // generic dc PAINTSTRUCT ps; // generic paintstruct

  10. WinMain - 2 // first fill in the window class stucture winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; winclass.lpfnWndProc = WindowProc; winclass.cbClsExtra = 0; winclass.cbWndExtra = 0; winclass.hInstance = hinstance; winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); winclass.hCursor = LoadCursor(NULL, IDC_ARROW); winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); winclass.lpszMenuName = NULL; winclass.lpszClassName = WINDOW_CLASS_NAME;

  11. WinMain - 3 // register the window class if (!RegisterClass(&winclass))return(0); if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, WINDOW_TITLE, (WINDOWED_APP ? (WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION) : (WS_POPUP | WS_VISIBLE)), 0,0, // x,y, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, // handle to parent NULL, // handle to menu hinstance, // instance NULL))) // creation parms return(0);

  12. WinMain - 4 // save the window handle and instance in a global main_window_handle = hwnd; main_instance = hinstance; // resize the window so client is really width x height if (WINDOWED_APP) { RECT window_rect = {0,0,WINDOW_WIDTH-1,WINDOW_HEIGHT-1}; AdjustWindowRectEx(&window_rect, GetWindowStyle(main_window_handle), GetMenu(main_window_handle) != NULL, GetWindowExStyle(main_window_handle));

  13. WinMain - 5 // save the global client offsets, they are needed in DDraw_Flip() window_client_x0 = -window_rect.left; window_client_y0 = -window_rect.top; // now resize the window MoveWindow(main_window_handle, 0, // x position 0, // y position window_rect.right - window_rect.left, // width window_rect.bottom - window_rect.top, // height FALSE); // show window, so there's no garbage on first render ShowWindow(main_window_handle, SW_SHOW); } // end if windowed

  14. WinMain - 6 Game_Init(); // disable CTRL-ALT_DEL, ALT_TAB, comment this line out SystemParametersInfo(SPI_SCREENSAVERRUNNING, TRUE, NULL, 0); // enter main event loop while(1) { if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { if (msg.message == WM_QUIT)break; TranslateMessage(&msg); // translate accelerator keys DispatchMessage(&msg); } // end if Game_Main();  } // end while

  15. WinMain - 7 // shutdown game and release all resources Game_Shutdown();  // enable CTRL-ALT_DEL, ALT_TAB, comment this line out SystemParametersInfo(SPI_SCREENSAVERRUNNING, FALSE, NULL, 0); // return to Windows return(msg.wParam); } // end WinMain

  16. Callback Function - 1 LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { // this is the main message handler of the system PAINTSTRUCT ps; // used in WM_PAINT HDC hdc; // handle to a device context switch(msg) { case WM_CREATE: { return(0); } break;

  17. Callback Function - 2 case WM_PAINT: { hdc = BeginPaint(hwnd,&ps); EndPaint(hwnd,&ps); return(0); } break; case WM_DESTROY: { PostQuitMessage(0); return(0); } break; default:break; } // end switch  return (DefWindowProc(hwnd, msg, wparam, lparam)); } // end WinProc

  18. Game_Init - 1 int Game_Init(void *parms) {  int index; // used for looping Open_Error_File("error.txt"); // start up DirectDraw (replace the parms as you desire) DDraw_Init (WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_BPP, WINDOWED_APP); DInput_Init(); DInput_Init_Keyboard(); // acquire the keyboard DSound_Init(); // load in sound fx explosion_id = DSound_Load_WAV("exp1.wav"); laser_id = DSound_Load_WAV("shocker.wav"); DMusic_Init();

  19. Game_Init - 2 // load and start main music track main_track_id = DMusic_Load_MIDI("midifile2.mid"); DMusic_Play(main_track_id); // add calls to acquire other directinput devices here... if (!WINDOWED_APP)ShowCursor(FALSE); // hide the mouse srand(Start_Clock()); // seed random // all your initialization code goes here... // create system colors rgb_green = RGB16Bit(0,255,0); rgb_white = RGB16Bit(255,255,255); rgb_blue = RGB16Bit(0,0,255); rgb_red = RGB16Bit(255,0,0);

  20. Game_Init - 3 // create the starfield for (index=0; index < NUM_STARS; index++) { stars[index].x = -WINDOW_WIDTH/2 + rand()%WINDOW_WIDTH; stars[index].y = -WINDOW_HEIGHT/2 + rand()%WINDOW_HEIGHT; stars[index].z = NEAR_Z + rand()%(FAR_Z - NEAR_Z); stars[index].color = rgb_white; } // end for index

  21. Game_Init - 4 // the vertex list for the tie fighter POINT3D temp_tie_vlist[NUM_TIE_VERTS] = // color, x,y,z { {rgb_white,-40,40,0}, // p0 {rgb_white,-40,0,0}, // p1 {rgb_white,-40,-40,0}, // p2 {rgb_white,-10,0,0}, // p3 {rgb_white,0,20,0}, // p4 {rgb_white,10,0,0}, // p5 {rgb_white,0,-20,0}, // p6 {rgb_white,40,40,0}, // p7 {rgb_white,40,0,0}, // p8 {rgb_white,40,-40,0}}; // p9

  22. Game_Init - 5 // copy the model into the real global arrays for (index=0; index<NUM_TIE_VERTS; index++) tie_vlist[index] = temp_tie_vlist[index]; // the edge list for the tie fighter LINE3D temp_tie_shape[NUM_TIE_EDGES] = // color, vertex 1, vertex 2 { {rgb_green,0,2 }, // l0 {rgb_green,1,3 }, // l1 {rgb_green,3,4 }, // l2 {rgb_green,4,5 }, // l3 {rgb_green,5,6 }, // l4 {rgb_green,6,3 }, // l5 {rgb_green,5,8 }, // l6 {rgb_green,7,9 } }; // l7 

  23. Game_Init - 6 // copy the model into the real global arrays for (index=0; index<NUM_TIE_EDGES; index++) tie_shape[index] = temp_tie_shape[index]; // initialize position of each tie fighter and it's velocity for (index=0; index<NUM_TIES; index++) { Init_Tie(index); } // end for index return(1); } // end Game_Init

  24. Game_Main - 1 int Game_Main(void *parms) { // all the calls for your game go here! int index; // looping var  Start_Clock(); // start the timing clock // clear the drawing surface DDraw_Fill_Surface(lpddsback, 0); DInput_Read_Keyboard(); // game logic here...

  25. Game_Main - 2 if (game_state==GAME_RUNNING) { // move players crosshair if (keyboard_state[DIK_RIGHT]) { // move cross hair to right cross_x+=CROSS_VEL;  // test for wraparound if (cross_x > WINDOW_WIDTH/2) cross_x = -WINDOW_WIDTH/2; } // end if // repeat for left, up, down

  26. Game_Main - 2 // speed of ship controls if (keyboard_state[DIK_A]) player_z_vel++; else if (keyboard_state[DIK_S]) player_z_vel--; if (keyboard_state[DIK_SPACE] && cannon_state==0) { cannon_state = 1; // fire the cannon cannon_count = 0; target_x_screen = cross_x_screen; // last target position target_y_screen = cross_y_screen; DSound_Play(laser_id); } // end if } // end if game running

  27. Game_Main - 3 // process cannon, simple FSM ready->firing->cool // firing phase if (cannon_state == 1) if (++cannon_count > 15) cannon_state = 2; // cool down phase if (cannon_state == 2) if (++cannon_count > 20) cannon_state = 0; Move_Starfield(); Process_Ties(); // move and perform ai for ties Process_Explosions();

  28. Game_Main - 4 // lock the back buffer and obtain pointer and width DDraw_Lock_Back_Surface(); Draw_Starfield(); Draw_Ties(); Draw_Explosions(); // draw the crosshairs // first compute screen coords of crosshair // note inversion of y-axis cross_x_screen = WINDOW_WIDTH/2 + cross_x; cross_y_screen = WINDOW_HEIGHT/2 - cross_y;

  29. Game_Main - 4 // draw the crosshair in screen coords Draw_Clip_Line16(cross_x_screen-16,cross_y_screen, cross_x_screen+16,cross_y_screen, rgb_red,back_buffer,back_lpitch); Draw_Clip_Line16(cross_x_screen,cross_y_screen-16, cross_x_screen,cross_y_screen+16, rgb_red,back_buffer,back_lpitch); Draw_Clip_Line16(cross_x_screen-16,cross_y_screen-4, cross_x_screen-16,cross_y_screen+4, rgb_red,back_buffer,back_lpitch); Draw_Clip_Line16(cross_x_screen+16,cross_y_screen-4, cross_x_screen+16,cross_y_screen+4, rgb_red,back_buffer,back_lpitch);

  30. Game_Main - 5 if (cannon_state == 1) // draw the laser beams { if ((rand()%2 == 1)) // right beam { Draw_Clip_Line16(WINDOW_WIDTH-1, WINDOW_HEIGHT-1, -4+rand()%8+target_x_screen,4+rand()%8+target_y_screen, RGB16Bit(0,0,rand()),back_buffer,back_lpitch); } // end if else // left beam { Draw_Clip_Line16(0, WINDOW_HEIGHT-1, -4+rand()%8+target_x_screen,-4+rand()%8+target_y_screen, RGB16Bit(0,0,rand()),back_buffer,back_lpitch); } // end if } // end if

  31. Game_Main - 6 // done rendering, unlock back buffer surface DDraw_Unlock_Back_Surface(); // draw the informtion sprintf(buffer, "Score %d Kills %d Escaped %d", score, hits, misses); Draw_Text_GDI(buffer, 0,0,RGB(0,255,0), lpddsback); if (game_state==GAME_OVER) Draw_Text_GDI("G A M E O V E R", WINDOW_WIDTH/2-8*10, WINDOW_HEIGHT/2,RGB(255,255,255), lpddsback); // check if the music has finished, if so restart if (DMusic_Status_MIDI(main_track_id)==MIDI_STOPPED) DMusic_Play(main_track_id);

  32. Game_Main - 7 DDraw_Flip(); // flip the surfaces Wait_Clock(30); // sync to 30ish fps // check for game state switch if (misses > 4*NUM_TIES) game_state = GAME_OVER; // check of user is trying to exit if (KEY_DOWN(VK_ESCAPE) || keyboard_state[DIK_ESCAPE]) { PostMessage(main_window_handle, WM_DESTROY,0,0); } // end if return(1); } // end Game_Main

  33. Game_Shutdown int Game_Shutdown(void *parms) { DSound_Stop_All_Sounds(); DSound_Shutdown(); DMusic_Delete_All_MIDI(); DMusic_Shutdown(); DInput_Shutdown(); DDraw_Shutdown(); return(1); } // end Game_Shutdown

  34. Enemy AI • Ship generated at random position beyond viewport • Ship follows fixed trajectory until it collides with player view point • No evasion is attempted

  35. 3D Projection • Orthographic projection Xproj = X Yproj = Y • Perspective projection (more realistic) Xper = zd * X/Z Yper = zd * Y/Z • The Z information can also be used to determine the brightness as Ties fighters get closer to gunner

  36. Collision Detection • Laser cannon are simply two projected lines that converge on on cross-hair cursor • If Tie fighter bounding box intersects these lines a hit is scored

  37. Explosions • When hit the Tie fighter 3D line segments are copied to a secondary data structure • The line segments are then randomly moved apart (similar to particle explosion) • After a couple of seconds of movement the line segments vanish and the explosion terminates

More Related