Game development basis (6)
Chapter VII Chapter 7 Features Feature 1 Overview: Computer Games can be said to play a very interesting role in the use of computer games. On the one hand, it is not for many people, and it is considered a waste; on the other hand computer game It is one of the most powerful strengths that drive the rapid development of various technologies of the computer. This, can be reflected from the 3D class game to the hardware, the demand for game images on the quality of the game image, the interactivity of the game, and the friendly sexuality of the man-machine interface (of course the game fan's concept of games, Creative requirements are also harsh and endless, but this only rely on your own imagination, we are loved). From the recent development of the game, we can see the development of 3D games, you can see the ancient tombs from doom to the present, Raythene 2, 3D game screen from the hard-working monotonous polygon to today's soft and complicated Scenes, props, monsters, enemies will only come to you by madness to you today, will take the right way to attack you today; games are progressing from hardware support or programming technology. In the process of game development, many technologies have also developed, such as the emergence and development of various graphics acceleration cards, the emergence of DirectX, and various optimization techniques used in each successful game have driven the development of computer technology. The game can be said to be the most advanced hardware technology and the latest programming idea in the computer industry in each period. For example, the recent game is a Windows-based software-oriented programming idea, most of the image requires high game. All require or support the graphics acceleration card. At the same time, there are also basic methods, structures, and theories in the game programming. In this chapter, we will discuss these issues. In this chapter we will discuss the following questions: The program entry is a message that the game gets the external operation, get the means of the next refresh. Like the general SDK Windows application, the portal of the program is WinMain (). Game initialization includes the initialization program required to create a standard Windows program, and initialization programs inside the game, such as the initialization of the game system, the loading of the game graphics, and the loading of the game sound. Game internal loop: The cyclic entry of the game is a function call inside the Windows message loop. The internal circulation of the game includes refreshing the game unit, drawing the game unit two parts. Refreshing the game unit: For each frame of the new game unit, such as changing the state of the game unit, changing the location of the game unit, get external information, etc. Painting game unit: For each frame to draw a game unit on the screen, special processing to increase the speed. Computer artificial intelligence: Mainly used by the behavior control algorithm of the game unit processed by computer, the program part is located in the refresh computer game unit portion. Game Memory Management: This part is very important for high-quality and efficient game software, and improper memory management will lead to a reduction in game performance, and even causing a crash. Game interaction design: Interaction design is the key to playability, friendly interactive interfaces and interactive ways can make the game a lot of color. Game Image Bottom Design: The main processing time of the game software is treated on the processing of images and draws, so the game image under the design of the game is very important for the final effect of the game. Game multimedia design: It mainly includes graphical interface design, game music sound design, game animation design, game image design, and more extensive, including the functional design of all running processes. The title of the second section of the program seems to be difficult to understand, it means that when the game is started, the computer starts running the program. Winmain () functions are generally the program entry on Windows applications. After the game starts, call the WinMain () function, and then call the corresponding function in order of the statement or the received message. From the third chapter of Windows programming, we understand the structure of the winmain () function, run the process, now we discuss the preparation of the Winmain () function on the angle of the game programming.
int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {MSG msg; while (lpCmdLine [0] == '-' || lpCmdLine [0] == '/') {lpCmdLine ; switch (* lpCmdLine ) {CASE 'E': BREAK; CASE 'W': bfullscreen = false; break; case 'f': bfullscreen = true; cserk; case '1': cmdlinebuffercount = 1; Break; Case '2' : Case 'D': cmdlineBuffercount = 2; Break; Case '3': cmdlineBuffercount = 3; Break; Case 's': bstretch = true; Break; Case 's': BWANTSOUND = FALSE; BREAK; CASE 'X': bStress = TRUE; break; case '?': bHelp = TRUE; bFullscreen = FALSE; // give help in windowed modebreak;} while (iS_SPACE (* lpCmdLine)) {lpCmdLine ;}} GameMode.cx = getint (& lpCmdLine, 640 ); Gamemode.cy = getint (& lpcmdline, 480); gamebpp = getint (& lpcmdline, 8); / ** Create Window and other Windows things * / if (! @Stance, ncmdshow) {Return False;} / * * Give user help if asked for ** this is ugly for now Because the whole screen is black * Except for the popup box. This could be fixed with some * work to ge T the window size right means was created instead * of delaying this work. See ddraw.c ** / if (bhelp) {MessageBox (hwndmain, "f12 - quit / n" "Numpad 2 - crouch / n" "Numpad 3 - Apple / N "" NUMPAD 4 - Right / N "" Numpad 5 - stop / n "" Numpad 6 - Left / N "" Numpad 7 - Jump / N "" / N "" Command Line Parameters / N "" / n "" - e use emulator / n "" - s nooid / n "- 1 no backbuffer / n" - 2 three backbuffers / n "" - s use stretch / n " "
-x demo or stress mode / n ",} / ** Initialize for game play * / if (! initgame ()) {Return False;} dwframetime = TimegetTime (); while (1) {IF PeekMessage (& MSG, NULL, 0, 0, PM_NOREMOVE)) {if (! GetMessage (& MSG, NULL, 0, 0) {Break;} TranslateMessage (& MSG); DispatchMessage (& MSG);} else if (! BPaused && bIsActive || bFullscreen)) {ProcessFox (lastInput); lastInput = 0;} else {WaitMessage ();}} if (AveFrameRateCount) {AveFrameRate = AveFrameRate / AveFrameRateCount; Msg (! "Average frame rate:% d", AveFrameRate) } return msg.wparam;} / * Winmain * / We know only one message in the message loop ---- wm_quit can end this loop, exit Windows. So we have to complete all the job before the message loop. Initialization. About initialization This concept will discuss in detail in the next section. In our routines (in the wmain () in the foxbear.c in the CD, we can see the DDINT before the message loop. () Function initialize DirectDraw, detects command line parameters and assigns the relevant parameters and determines the display mode, and performs the initialization of the window, detects the value of BHELP to determine if the help dialog is displayed, and the initialization of the game. In a game In addition to the part of the message loop containing general Windows applications, the message loop should also be called related to detect game unit status locations, refresh game units and heavy pictures and some functions about artificial intelligence. In routines The message loop section contains a call about detecting the location of the game unit, refreshing the game unit and the new graphics function. There are generally two methods in these calls: 1. Directly call the relevant functions directly. For example Each cycle in a rpg game detects whether the position of the protagonist changes. If it changed, he will hear the master in the new location. Figure. 2. By detecting the WM_TIMER message to determine if the relevant functions are called. That is, every time time (several clock cycles), detect once and then determine the call or not of the function. In the two methods above, the first is currently more common, and its disadvantage is that the CPU resource is relatively relatively, but the different models have strong adaptability and more stable. The second is more common in some games that are not high, with a high speed requirement, compared to the first CPU resource relatively small, but in different models, the difference is very large. When talking about WinMain (), the edification of window functions (WinProc) must be said. The window function can be said to connect the function different from the Switch-Case structure to the clues of a complex program. Its basic writing method has been talked in the Windows programming basis. The mainwndproc () function in the careful reading routine believes that it is considerable to you.
/ ** MainWndProc ** Callback for all Windows messages * / long FAR PASCAL MainWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {PAINTSTRUCT ps; HDC hdc; switch (message) {case WM_SIZE: case WM_MOVE: if ( IsIconic (hWnd)) {Msg ( "FoxBear is minimized, pausing"); PauseGame ();} if (bFullscreen) {SetRect (& rcWindow, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN));} else {GetClientRect (HWND, & RCWINDOW); ClientToscreen (HWnd, (LPPOINT) & rcWindow; ClientToscreen (HWnd, (LPPOINT) & rcwindow 1);} MSG ("Window Rect: [% D,% D,% D,% D]", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom); break; case WM_ACTIVATEAPP: bIsActive = (BOOL) wParam && GetForegroundWindow () == hWnd; if (bIsActive) Msg ( "FoxBear is active"); elseMsg ("FoxBear IS Not Active"); //// While We Were Not-Active Sometting Bad Happened That Cause A SURFACE RESTORE FAILING OR We Got A Palette // Changed, Now That We Are Active Try To FIX Things // IF (Bpaused && Bisactive) {IF (Restoregame ()) {unpausegame ();} ELS E {IF (GetForegroundWindow () == hWnd) {/// We are unable to restore, this can happen when // The screen resolution or bitDepth Has Changed // We Just Reload All the Art Ant Again and Re-Create /// The Front and Back Buffers. This is a little // overkill We Could Handle A Screen Res change and back buffers we dont // NEED TO Redo the Art, But this is Way Easier.//IF ( InitGame ()) {UnPauseGame ();}}}} break; case WM_QUERYNEWPALETTE:! //// we are getting the palette focus, select our palette // if (bFullscreen && lpPalette && lpFrontBuffer) {HRESULT ddrval; ddrval = IDirectDrawSurface_SetPalette LPFRONTBUFFER, LPPALETTE
if (ddrval == DDERR_SURFACELOST) {IDirectDrawSurface_Restore (lpFrontBuffer); ddrval = IDirectDrawSurface_SetPalette (lpFrontBuffer, lpPalette); if (ddrval == DDERR_SURFACELOST) {Msg ( "Failed to restore palette after second try");}} //// Restore normal title if palette is ours // if (ddrval == DD_OK) {SetWindowText (hWnd, OUR_APP_NAME);}} break; case WM_PALETTECHANGED: //// if another app changed the palette we dont have full control // of the palette . Note this Only Applies for FoxBear in a window // WHEN WEA FULLSCREEN WE GET All the Palette All of the time.//IF ((hwnd) WPARAM! = HWND) {if (! Bfullscreen) {if (! Bstress) {MSG ("***** palette changed, pausing game"; pausegame (); else {msg ("Lost Palette But Continuing"); setWindowText (hwnd, ou_app_name "- Palette Changed Colors Probably Wrong");} }} break; case WM_DISPLAYCHANGE: break; case WM_CREATE: break; case WM_SETCURSOR: if (bFullscreen && bIsActive) {SetCursor (NULL); return TRUE;} break; case WM_SYSKEYUP: switch (wParam) {// handle ALT ENTER ( Fullscre en) case VK_RETURN: bFullscreen = bFullscreen; ExitGame (); DDDisable (TRUE); // destroy DirectDraw objectGameMode.cx = 320; GameMode.cy = 200; InitGame (); break;} break; case WM_KEYDOWN:! switch (wParam ) {case VK_NUMPAD5: lastInput = KEY_STOP; break; case VK_DOWN: case VK_NUMPAD2: lastInput = KEY_DOWN; break; case VK_LEFT: case VK_NUMPAD4: lastInput = KEY_LEFT; break; case VK_RIGHT: case VK_NUMPAD6: lastInput = KEY_RIGHT; break; case VK_UP: case VK_NUMPAD8: lastInput = KEY_UP; break; case VK_HOME: case VK_NUMPAD7: lastInput = KEY_JUMP; break; case VK_NUMPAD3: lastInput = KEY_THROW; break; case VK_F5: bShowFrameCount = bShowFrameCount; if (bShowFrameCount) {dwFrameCount =!
0; dwframetime = TimegetTime ();} Break; Case VK_F6: {Static I; //// Findur current mode in the mode list //iff (bfullscreen) {for (i = 0; i
} Break; Case WM_Paint: HDC = Beginpaint (HWND, & PS); if (bpaused) {char * SZ = "Game is Paused, this is not a bug."; Textout (ps.hdc, 0, 0, sz, lstrlen (sz));} EndPaint (hWnd, & ps); return 1; case WM_DESTROY: hWndMain = NULL; lastInput = 0; DestroyGame (); // end of gameDDDisable (TRUE); // destroy DirectDraw objectPostQuitMessage (0); break } Return DEFWINDOWPROC (HWND, Message, WPARAM, LPARAM);} / * MainwndProc * / Section 3 Game Initialization Game initialization includes three parts: 1.Windows initialization. 2. Initialization of the game tool. 3. Initialization of the game. In the three parts, the initialization of Windows is also registration, definition, and initialization of the window. We have already talked in the WIN-DOWS programming basis, and it will not be detailed here. Initialization of the game tool refers to the initialization of the tools used in the game program. For a game, we need to use some systems that need to be drawn or played with graphics or sound management for games. These systems are the game tools we are saying (sometimes people also call the game engine). These tools are sometimes provided by some game companies, such as Microsoft DirectX5 SDK, sometimes it is a system that you need to prepare or use the previous works for your game. In this routine, you can initialize DirectDraw and DirectSound, you can understand the original code of Ddinit () and INITSOUND () and the initgame () function and reading the chapter about DirectDraw and DirectSound.
() Code DDInit () and InitSound () function and InitGame: / ** InitGame ** Initializing current game * / BOOL InitGame (void) {ExitGame (); GameSize = GameMode; / ** initialize sound * / InitSound (hWndMain ); / ** Init DirectDraw, Set Mode, ... * Note Gamemode Might Be set to 640x480 ife. * / if (! preinitializegame ()) {Return False;} IF (Bstretch && Bfullscreen ) {GameSize.cx = gamemode.cx / 2; gamesize.cy = gamemode.cy / 2; gamerect.cx; gamerect.cy; gamerect.top = gamemode.cy - gamesis.cy; gamerect.right=Right = GameMode.cx; GameRect.bottom = GameMode.cy; if (lpStretchBuffer) Msg ( "Stretching using a system-memory stretch buffer"); elseMsg ( "Stretching using a VRAM-> VRAM blt");} else {GameRect.left = (GameMode.cx - GameSize.cx) / 2; GAMEMODE.CY - GAMESIZE.CY) / 2; GAMERECT.Right = GameRect.Top GameSize .cy;} / ** setup} / if (gamebpp == 8) {lppalette = readpalfile (null); // Create a 332 Paletteif (lppalette == null) {msg (" Palette create failed "); return FALSE;} IDirectDrawSurface_SetPalette (lpFrontBuffer, lpPalette);} / ** load all the art and things * / if (InitializeGame (.!)) {Return FALSE;} / ** init our code to draw the FPS * / makeFontStuff (); / ** spew some stats * / {DDCAPS ddcaps; ddcaps.dwSize = sizeof (ddcaps); IDirectDraw_GetCaps (lpDD, & ddcaps, NULL); Msg ( "Total =% ld, Free VRAM =% LD ", DDCaps.dwvidMTotal, DDCaps.dwvidMemfree); MSG (" Used =% LD ", DDCaps.dwvidMTotal- Ddcaps.dwvidMemfree;} Return TRUE;
} / * InitGame * // ** InitSound ** Sets up the DirectSound object and loads all sounds into secondary * DirectSound buffers Returns FALSE on error, or TRUE if successful * / BOOL InitSound (HWND hwndOwner) {int idx;. DSBUFFERDESC dsBD ; IDirectSoundBuffer * lpPrimary; DSEnable (hwndOwner); if (lpDS == NULL) return TRUE; / ** Load all sounds - any that can not load for some reason will have NULL * pointers instead of valid SOUNDEFFECT data, and we will know not to * play them later on * / for. (idx = 0; idx } The initialization of the game refers to the image, sound and other resources and the role in the game, the props attributes, the initial position, state, etc., and the image of the initial picture, and the definition of the operation method, The rules of the game, etc. For example, in an RPG game, in the game start, you should load the protagonist image group (such as a few pictures, the map in the Status dialog), status (level, hp, mp, dp, etc. ,, Attribute (gender, occupation, etc.), describe the entire game world, NPC's various properties, the rules of the game (the effect of various attack methods, the experience value required to upgrade), etc. Enter everything in the game you designed. This task is completed in the function initializegame () called in the INITGAME () of the routine. InitializeGame () code: / ** InitializeGame * / BOOL InitializeGame (void) {Splash (); hBitmapList = LoadBitmaps (); if (hBitmapList == NULL) {return FALSE;} InitTiles (& hTileList, hBitmapList, C_TILETOTAL); InitPlane (& hForeground, & hForePosList, "FORELIST", C_FORE_W, C_FORE_H, C_FORE_DENOM); TilePlane (hForeground, hTileList, hForePosList); InitPlane (& hMidground, & hMidPosList, "MIDLIST", C_MID_W, C_MID_H, C_MID_DENOM); TilePlane (hMidground, hTileList, hMidPosList) ; InitPlane (& hBackground, & hBackPosList, "bACKLIST", C_BACK_W, C_BACK_H, C_BACK_DENOM); TilePlane (hBackground, hTileList, hBackPosList); InitSurface (& hSurfaceList, "SURFLIST", C_FORE_W, C_FORE_H); SurfacePlane (hForeground, hSurfaceList); InitFox (& hFox , hbitmaplist; INITBEAR (& HBear, hbitmaplist); INITAPPLE (& happle, hbitmaplist); ddclear (); // Clear all the backbuffers.return true;} / * initializegame * / in most games in most games An integral part is usually stored in a structure or class. For example, in an instant strategic game, various buildings are placed in a class, while the properties of each building are placed in a subclass of such classes; various weapons are placed in a class, each weapon is put in A subclass of the class. Class weapon {weapon_type type; char name; dword id; word defend; Word attack; ...}; section IV game internal cycle game internal cycle includes refreshing game units, drawing game units. Its implementation process is this: detection state, make judgments, plot new map. It is not a loop, right? Yes, the internal cycle of the game is not a real loop, which is actually a looping by the message loop. Let us see how this is achieved from routines! The first ELSE IF statement in the message loop is such an else if (! Bpaused && (bffullscreen)) {processfox (lastinput); LastInput = 0;} The meaning of the expression after IF is: When the game Did not be paused (BPAUSE is displayed) or perform {processfox (LastInput); LastInput = 0; LastInput = 0; LastInput = 0; LastInput = 0;}. The function processfox (lastinput) rents the function of the new game unit and the new map by calling ProcessInput () and NewGameFrame (). (The original code of these three functions is shown in routine foxbear.c and GameProc.c two files). ProcessFox (lastInput): / ** ProcessFox * / BOOL ProcessFox (SHORT sInput) {if ((lpFrontBuffer && IDirectDrawSurface_IsLost (lpFrontBuffer) == DDERR_SURFACELOST) || (lpBackBuffer && IDirectDrawSurface_IsLost (lpBackBuffer) == DDERR_SURFACELOST)) {if (RestoreGame! ()) {PauseGame (); return FALSE;}} ProcessInput (sInput); NewGameFrame (); return TRUE;} / * ProcessFox * / static hFONT hFont; DWORD dwFrameCount; DWORD dwFrameTime; DWORD dwFrames; DWORD dwFramesLast; SIZE sizeFPS; Size sizeInfo; int frameagex; char szfps [] = "fps% 02d"; char szinfo [] = "% DX% DX% D% S F6 = mod f8 = x2 alt enter = window"; char szinfow [] = " % DX% DX% D% S F6 = MODE F8 = X2 Alt Enter = Fullscreen "; char szframerate [128]; char szinfo [128]; colorRef infocolor = RGB (0,152,245); colorref frameratecolor = RGB (255, 255, 0) ; COLORREF BackColor = RGB (255,255,255); / ** initNumSurface * / void initNumSurface (void) {HDC hdc; RECT rc; int len; dwFramesLast = 0; len = wsprintf (szFrameRate, szFPS, 0, 0); if (lpFrameRate && idirectdrawsurface_getdc (lpframerate, & hdc) == DD_OK) {SelectObje CT (HDC, HFONT); SetTextColor (HDC, FramerateColor); SetBkcolor (HDC, BackColor); SetBkmode (HDC, Opaque); SetRect (& RC, 0, 0, 10,000, 10000); EXTTEXTOUT (HDC, 0, 0, ETO_OPAQUE , & rc, szFrameRate, len, NULL); GetTextExtentPoint (hdc, szFrameRate, 4, & sizeFPS); FrameRateX = sizeFPS.cx; GetTextExtentPoint (hdc, szFrameRate, len, & sizeFPS); IDirectDrawSurface_ReleaseDC (lpFrameRate, hdc);} if (bFullscreen) Len = WSPrintf (Szinfo, Szinfo, Gamesize.cx, GameSize.cy, Gamebpp, Bstretch? "x2": ""); elselen = WSPrintf (Szinfo, Szinfow, Gamesize.cx, GameSize.cy, GameBPP, BSTRETCH? "x2 " : ""); If (lpInfo && IDirectDrawSurface_GetDC (lpInfo, & hdc) == DD_OK) {SelectObject (hdc, hFont); SetTextColor (hdc, InfoColor); SetBkColor (hdc, BackColor); SetBkMode (hdc, OPAQUE); SetRect ( & rc, 0, 0, 10,000, 10000); EXTTEXTOUT (HDC, 0, 0, ETO_OPAQUE, & RC, SZINFO, LEN, NULL); GettextExtentPoint (HDC, Szinfo, Len, & SizeInfo); iDirectdrawSurface_releaseDC (LPInfo, HDC);} / * initNumSurface * / NewGameFrame (): / ** NewGameFrame * / int NewGameFrame (void) {SetSpriteX (hFox, 0, P_AUTOMATIC); SetSpriteY (hFox, 0, P_AUTOMATIC); SetPlaneVelX (hBackground, GetSpriteVelX (hFox), P_ABSOLUTE) ; SetPlaneVelX (hMidground, GetSpriteVelX (hFox), P_ABSOLUTE); SetPlaneVelX (hForeground, GetSpriteVelX (hFox), P_ABSOLUTE); SetPlaneX (hBackground, 0, P_AUTOMATIC); SetPlaneX (hMidground, 0, P_AUTOMATIC); SetPlaneX (hForeground, 0, P_AUTOMATIC ); Setspritex (hbear, 0, p_automatic); setspritex (HAPPLE, 0, P_AUTOMATIC); setspritey (happle, 0, p_automatic); / ** Once All Sprites Are Processed, Display THEM ** IF WE Are USING DESTINATION transparency instead of source * transparency, we need to paint the background with the color key * and then paint our sprites and planes in reverse order. ** Since destination transparency will allow you to only write pixels * on the destination if the transparent color is present, reversing * the order (so that the topmost bitmaps are drawn first instead of * list) causes everything to come out ok * / if (bTransDest) {gfxFillBack (dwColorKey);. DisplayFrameRate (); DisplaySprite (hBuffer, hApple, GetPlaneX (hForeground)); DisplaySprite (hBuffer, hBear, GetPlaneX (hForeground)); DisplaySprite (hBuffer, hFox, GetPlaneX (hForeground)); DisplayPlane (hBuffer, hForeground); DisplayPlane (hBuffer, hMidground); DisplayPlane (hBuffer, hBackground);} else {DisplayPlane (hBuffer, hBackground); DisplayPlane (hBuffer, hMidground); DisplayPlane (hBuffer, hForeground); DisplaySprite (hBuffer, hFox, GetPlaneX (hForeground)); DisplaySprite (hBuffer, hBear, GetPlaneX (hForeground); DisplaySprite (HFEFER, HAPPLE, GETPLANEX (HForeground); DisplayFramerate ();} gfxswapBuffers (); return 0;} / * newgameframe * / fifth refresh game unit refresh game unit's role is in every Brush the status of the new game unit. Please read the part of the ProcessInput () function below, then look at the following two examples. The ProcessInput () function is part of the code: / ** ProcessInput * / BOOL ProcessInput (SHORT input) {static BOOL fBearPlaying = FALSE; LONG foxSpeedX; LONG foxSpeedY; LONG foxX; LONG foxY; LONG bearX; LONG bearY; LONG appleX; LONG appleY ; ACTION foxAction; DIRECTION foxDir; BOOL cont = TRUE; foxSpeedX = GetSpriteVelX (hFox); foxAction = GetSpriteAction (hFox); foxDir = GetSpriteDirection (hFox); if ((GetSpriteActive (hFox) == FALSE) && (input = 4209! )) {INPUT = 0;} Switch (input) {case key_down: if (foxAction == stop) {Break;} else == still) {setspriteAction (hfox, cach, same);} elseiff == walk) {setspriteAction (hfox, crouchwalk, same);} Break; case key_left: if (foxAction == stop) {Break;} else if (foxspeedX == 0) {if (foxAction == still) {ix (foxAction == still) {IF foxDir == RIGHT) {ChangeSpriteDirection (hFox); SetPlaneSlideX (hForeground, -C_BOUNDDIF, P_RELATIVE); SetPlaneSlideX (hMidground, -C_BOUNDDIF, P_RELATIVE); SetPlaneSlideX (hBackground, -C_BOUNDDIF, P_RELATIVE); SetPlaneIncremX (hForeground, C_BOUNDINCREM, P_ABSOL UTE); SetPlaneIncremX (hBackground, C_BOUNDINCREM, P_ABSOLUTE); SetPlaneIncremX (hMidground, C_BOUNDINCREM, P_ABSOLUTE);} else {SetSpriteAction (hFox, WALK, LEFT); SetSpriteSwitch (hFox, C_FOX_WALKSWITCH, P_ABSOLUTE); SetSpriteVelX (hFox, -C_FOX_XMOVE, P_RELATIVE );}} else if (foxAction == CROUCH) {if (foxDir == RIGHT) {ChangeSpriteDirection (hFox); SetPlaneSlideX (hForeground, -C_BOUNDDIF, P_RELATIVE); SetPlaneSlideX (hMidground, -C_BOUNDDIF, P_RELATIVE); SetPlaneSlideX (hBackground, -C_bounddif, p_relative); SetPlaneIncremx (HForeground, c_boundincrem, p_absolute); setPlaneIncremx (HBackground, c_boundincrem, p_absolute); SetPlaneIncremX (hMidground, C_BOUNDINCREM, P_ABSOLUTE);} else {SetSpriteAction (hFox, CROUCHWALK, LEFT); SetSpriteSwitch (hFox, C_FOX_WALKSWITCH, P_ABSOLUTE); SetSpriteVelX (hFox, -C_FOX_XMOVE, P_RELATIVE);}} else {SetSpriteVelX (hFox, -C_FOX_XMOVE , P_RELATIVE);}} else {setspritevelX (hfox, -c_fox_xmove, p_relative);} Break; case key_right: ... case key_stop: if (foxAction == stop) {Break;} else f ((FoxAction == Run) || (foxAction == BLURR)) {SetSpriteAction (hFox, STOP, SAME); SetSpriteAccX (hFox, -foxSpeedX / 25, P_ABSOLUTE); SoundPlayEffect (SOUND_STOP);} else {SetSpriteVelX (hFox, 0, P_ABSOLUTE);} break Case key_up: if (foxAction == stop) {Break;} else if (foxAction == crouch) {setspriteAction (hfox, still, same);} else if (foxAction == crouchwalk) {setspriteAction (hfox, walk, same );} Break; case key_jump: if (foxAction == stop) {Break;} elseif ((FoxAction == STILL) || (FoxAction == Walk) || (FoxAction == Run) || (FoxAction == Crouch ) || (FoxAction == Crouchwalk) {setspriteAction (Hfox, J UMP, SAME); SetSpriteSwitchType (hFox, TIME); SetSpriteSwitch (hFox, C_FOX_JUMPSWITCH, P_ABSOLUTE); SetSpriteVelY (hFox, -C_FOX_JUMPMOVE, P_ABSOLUTE); SetSpriteAccY (hFox, C_UNIT / 2, P_ABSOLUTE); SoundPlayEffect (SOUND_JUMP);} break; Case key_throw: if (foxAction == stop) {breaf;} else if ((foxAction == still) || (FoxAction == Walk) || (FoxAction == Run) || (FoxAction == Crouch) || foxAction == CROUCHWALK)) {SetSpriteAction (hFox, THROW, SAME); SetSpriteSwitch (hFox, C_FOX_THROWSWITCH, P_ABSOLUTE); SetSpriteVelX (hFox, 0, P_ABSOLUTE); SetSpriteSwitchType (hFox, TIME);} else if (foxAction == JUMP) {SetSpriteAccY (hFox, 0, P_ABSOLUTE); SetSpriteSwitch (hFox, C_FOX_THROWSWITCH, P_ABSOLUTE); SetSpriteAction (hFox, JUMPTHROW, SAME); SetSpriteVelY (hFox, 0, P_ABSOLUTE); SetSpriteSwitchDone (hFox, FALSE); SetSpriteSwitchForward (hFox, True);} Break; default: Break;} / ** fox Actions Follow ... * / if (getSpriteActive (hfox) == false) {goto bearactions;} if (ABS (getSpritevelX (HFOX)) SetSpriteAccX (hFox, -foxSpeedX / 25, P_ABSOLUTE); // SetSurface (hForeground, hFox); SoundPlayEffect (SOUND_STOP);} break; case CROUCHWALK: if (foxSpeedX == 0) {SetSpriteAction (hFox, CROUCH, SAME);} else if (foxSpeedX> C_FOX_WALKMOVE) {SetSpriteVelX (hFox, C_FOX_WALKMOVE, P_ABSOLUTE);} else if (foxSpeedX <-C_FOX_WALKMOVE) {SetSpriteVelX (hFox, -C_FOX_WALKMOVE, P_ABSOLUTE);} break; case STOP: if (foxSpeedX == 0) {SetSpriteAction (hFox, STILL, SAME); SetSpriteAccX (hFox, 0, P_ABSOLUTE);} break; case RUN: if ((foxSpeedX -C_FOX_WALKTORUN)) {SetSpriteAction (hFox, RUN, LEFT); SetSpriteSwitch (hFox, C_FOX_RUNSWITCH, P_ABSOLUTE);} break; case JUMPTHROW:! If (GetSpriteSwitchDone (hFox) == FALSE) {SetSpriteSwitchForward (hFox, FALSE); SetSpriteAction ( hFox, JUMP, SAME); SetSpriteSwitch (hFox, C_FOX_JUMPSWITCH, P_ABSOLUTE); SetSpriteSwitchDone (hFox, FALSE); SetSpriteAccY (hFox, C_UNIT / 2, P_ABSOLUTE); SoundPlayEffect (SOUND_THROW);} elseif ((GetSpriteBitmap (hFox) == 1 ) && (GetSpriteDirection (hFox) == RIGHT)) {SetSpriteActive (hApple, TRUE); SetSpriteX (hApple, GetSpriteX (hFox) 60 * C_UNIT, P_ABSOLUTE); SetSpriteY (hApple, GetSpriteY (hFox) 30 * C_UNIT, P_ABSOLUTE ); SetSpriteVelX (hApple, 8 * C_UNIT, P_ABSOLUTE); SetSpriteVelY (hApple, -4 * C_UNIT, P_ABSOLUTE); SetSpriteAccX (hApple, 0, P_ABSOLUTE); SetSpriteAccY (hApple, C_UNIT / 4, P_ABSOLUTE);} else if (( GetSpriteBitmap (HFOX) == 1) && (getSpriteDirection (HFOX) == LEFT) {setspriteActive (HAPPLE, TRUE); setspritex (happle, getspritex (hfox) 15 * c_unit, p_ ABSOLUTE); SetSpriteY (hApple, GetSpriteY (hFox) 30 * C_UNIT, P_ABSOLUTE); SetSpriteVelX (hApple, -8 * C_UNIT, P_ABSOLUTE); SetSpriteVelY (hApple, -4 * C_UNIT, P_ABSOLUTE); SetSpriteAccX (hApple, 0, P_ABSOLUTE ); SetSpriteAccY (hApple, C_UNIT / 4, P_ABSOLUTE);} break; case THROW:! if (GetSpriteSwitchDone (hFox) == FALSE) {SetSpriteAction (hFox, STILL, SAME); SetSpriteSwitchType (hFox, HOR); SetSpriteSwitch (hFox , 0, P_ABSOLUTE); SetSpriteSwitchDone (hFox, FALSE); SoundPlayEffect (SOUND_THROW);} else if ((GetSpriteBitmap (hFox) == 1) && (GetSpriteDirection (hFox) == RIGHT)) {SetSpriteActive (hApple, TRUE); SetSpriteX (hApple, GetSpriteX (hFox) 60 * C_UNIT, P_ABSOLUTE); SetSpriteY (hApple, GetSpriteY (hFox) 50 * C_UNIT, P_ABSOLUTE); SetSpriteVelX (hApple, 8 * C_UNIT, P_ABSOLUTE); SetSpriteVelY (hApple, -4 * C_UNIT, P_ABSOLUTE); SetSpriteAccX (hApple, 0, P_ABSOLUTE); SetSpriteAccY (hApple, C_UNIT / 4, P_ABSOLUTE);} else if ((GetSpriteBitmap (hFox) == 1) && (GetSpriteDirection (hFox) == LEFT)) { SetSpriteActive (hApple, TRUE); SetSpriteX (hApple, GetSpriteX (hFox) 20 * C_UNIT, P_ABSOLUTE); SetSpriteY (hApple, GetSpriteY (hFox) 50 * C_UNIT, P_ABSOLUTE); SetSpriteVelX (hApple, -8 * C_UNIT, P_ABSOLUTE) Setspritevely (happle, -4 * c_unit, p_absolute); setspriteAccx (happle, 0, p_absolute); setspriteAccy (happle, c_unit / 4, p_absolute);} Break; Case Jump: IF ((foxSpeedy> = 0) && (! GetSpriteSwitchForward (hFox) == FALSE)) {SetSpriteSwitchForward (hFox, FALSE);}! else if (GetSpriteSwitchForward (hFox) == FALSE) {if ((GetSurface (hForeground, hFox) == FALSE) || (GetSurface (! HForeground, Hfox) = = FALSE)) {if (foxSpeedX> = C_FOX_RUNMOVE) {SetSpriteAction (hFox, RUN, SAME); SetSpriteSwitch (hFox, C_FOX_RUNSWITCH, P_ABSOLUTE);} else if (foxSpeedX == 0) {SetSpriteAction (hFox, STILL, SAME); SetSpriteSwitch (hFox, C_FOX_WALKSWITCH, P_ABSOLUTE);} else {SetSpriteAction (hFox, WALK, SAME); SetSpriteSwitch (hFox, C_FOX_WALKSWITCH, P_ABSOLUTE);} SetSpriteAccY (hFox, 0, P_ABSOLUTE); SetSpriteVelY (hFox, 0, P_ABSOLUTE); SetSpriteSwitchType (HFOX, HOR); SETSPRITESWITCHFORWARD (HFOX, TRUE); // setsurface (hforeground, hfox); setspriteswitchdone (HFOX, FALSE);}} Break;} / ** bear actions * / bearactions: foxx = getspritex (hfox); Foxy = GetSpriteY (hFox); bearX = GetSpriteX (hBear); bearY = GetSpriteY (hBear); appleX = GetSpriteX (hApple); appleY = GetSpriteY (hApple); switch (GetSpriteAction (hBear)) {case STRIKE: if (GetSpriteBitmap (hBear) == 2) {IF ((Bearx> Foxx - C_Unit * 30) && (Bearx SetSpriteVelX (hBear, 0, P_ABSOLUTE); SetSpriteSwitchType (hBear, TIME); SetSpriteSwitch (hBear, C_BEAR_STRIKESWITCH, P_ABSOLUTE); SetSpriteSwitchDone (hBear, FALSE);} break; case CHEW: chewCount; if (chewCount> = 200) { SetSpriteAction (hBear, STRIKE, SAME); SetSpriteSwitch (hBear, C_BEAR_STRIKESWITCH, P_ABSOLUTE); SetSpriteVelX (hBear, 0, P_ABSOLUTE); SetSpriteSwitchDone (hBear, FALSE); if (GetSpriteDirection (hFox) == RIGHT) {SetPlaneSlideX (hForeground, - C_BOUNDDIF, P_RELATIVE); SetPlaneSlideX (hMidground, -C_BOUNDDIF, P_RELATIVE); SetPlaneSlideX (hBackground, -C_BOUNDDIF, P_RELATIVE);} chewDif = GetSpriteX (hFox); SetSpriteActive (hFox, TRUE); SetSpriteAction (hFox, sTUNNED, LEFT); SetSpriteX (hFox, GetSpriteX (hBear), P_ABSOLUTE); SetSpriteY (hFox, GetSpriteY (hBear), P_ABSOLUTE); SetSpriteAccX (hFox, 0, P_ABSOLUTE); SetSpriteAccY (hFox, C_UNIT / 2, P_ABSOLUTE); SetSpriteVelX (hFox, -8 * C_Unit, p_absolute; setspritevely (hfox, -10 * c_unit, p_absolute); setspriteswitch (hfox, 0, p_abs OLUTE); SoundPlayEffect (SOUND_STUNNED); chewDif - = GetSpriteX (hFox); SetPlaneSlideX (hForeground, -chewDif, P_RELATIVE); SetPlaneSlideX (hMidground, -chewDif, P_RELATIVE); SetPlaneSlideX (hBackground, -chewDif, P_RELATIVE); SetPlaneIncremX (hForeground, C_BOUNDINCREM, P_ABSOLUTE); SetPlaneIncremX (hMidground, C_BOUNDINCREM, P_ABSOLUTE); SetPlaneIncremX (hBackground, C_BOUNDINCREM, P_ABSOLUTE);} break;!} / ** Apple actions ... * / if ((GetSpriteVelY (hApple) = 0) && ( GetSpriteY (hApple)> = 420 * C_UNIT)) {SetSpriteX (hApple, 0, P_ABSOLUTE); SetSpriteY (hApple, 0, P_ABSOLUTE); SetSpriteAccX (hApple, 0, P_ABSOLUTE); SetSpriteAccY (hApple, 0, P_ABSOLUTE); SetSpriteVelX ( Happle, 0, p_absolute; Setspritevely (HAPPLE, 0, P_ABSOLUTE); setspriteActive (HAPPLE, FALSE);} Return Cont;} / * processInput * / Transmitted bullets in the shooting game, each frame is detected by the position A of the bullets when the previous frame is Determine the position B of the current frame bullet and then pass the position to the portion of the heavy drawing game unit, and the image of the bullet at the position of the current frame B. Even if the two military in the strategic game, the program is based on the position of each of the combat units in each frame and the purpose of the combat unit, and a certain path algorithm in the position of the combat unit. Determine the new location of the battle unit in the current frame; there is also a health value and intensity of the combat unit when the previous frame is taken, to determine the health of the battle unit. By reading the code of the ProcessInput () function, I think you must understand the concept of refreshing the game unit. From the above two examples, you must also find that the method of the routine is difficult to achieve the requirements of these two types of games. We can't operate every bullet, every combat unit, and we don't know how many bullets will make the player will make how many combat units will make the player. What should we do? Considering that each combat unit (or each bullet) has similar (or the same) attributes, we can use structural arrays to store the location and status of each combat unit. This method is like feasible! But think about it, we have encountered problems mentioned above. We don't know how many bullets will be launched once. I don't know how many combat units will make players. Of course, we can use Age of Empire --- the number of units (I don't say that Age of Empire uses this). But what does this mean! It means that if we limit the number of 50, only one soldier is only a soldier, but the computer needs to assign 50 times the memory for this soldier! And the player still does not necessarily create 50 soldiers. Obviously this is not a good way! What should we do? Link list! The linked list can meet our requirements. Class node {// The pointer of the two-way linked list. Node * next; node * pre; // node data. Node_data data; ...}; linked list is a collection of structures. Each of the structs in the chain contains an element or a pointer, which points to another structure in the linked list. This pointer is used as a connection between two structures. This concept is similar to the array, but it allows the dynamic growth of the linked list. Nowadays, there is generally used linked lists. For more information on the linked list, please read the relevant information. The effect of the sixth segment game unit drawing game unit is to draw the image of the game unit on each of the screen. This is the main function of the game unit in this routine: / ** newgameframe * / int newgameframe (void) {// This is the location of the game unit: setspritex (hfox, 0, p_automatic); setspritey (hfox, 0, P_AUTOMATIC); SetPlaneVelX (hBackground, GetSpriteVelX (hFox), P_ABSOLUTE); SetPlaneVelX (hMidground, GetSpriteVelX (hFox), P_ABSOLUTE); SetPlaneVelX (hForeground, GetSpriteVelX (hFox), P_ABSOLUTE); SetPlaneX (hBackground, 0, P_AUTOMATIC); SetPlaneX ( Hmidground, 0, p_automatic; setPlanex (HForeground, 0, p_automatic); setspritex (hbear, 0, p_automatic); setspritex (happle, 0, p_automatic); setspritey (happle, 0, p_automatic); // Put the graphic of the game unit affixed to BackBuffer: if (bTransDest) {gfxFillBack (dwColorKey); DisplayFrameRate (); DisplaySprite (hBuffer, hApple, GetPlaneX (hForeground)); DisplaySprite (hBuffer, hBear, GetPlaneX (hForeground)); DisplaySprite (hBuffer, hFox, GetPlaneX (hForeground)); DisplayPlane (hBuffer, hForeground); DisplayPlane (hBuffer, hMidground); DisplayPlane (hBuffer, hBackground);} else {DisplayPlane (hBuffer, hBackground); DisplayPlane (hBuffer, hMidground ); DisplayPlane (hBuffer, hForeground); DisplaySprite (hBuffer, hFox, GetPlaneX (hForeground)); DisplaySprite (hBuffer, hBear, GetPlaneX (hForeground)); DisplaySprite (hBuffer, hApple, GetPlaneX (hForeground)); DisplayFrameRate ();} // Update Prospect: gfxswapBuffers (); Return 0;} / * NewGameFrame * / The order of the game unit is: 1. BackBuffer clear; it is clear BackBuffer function: / ** gfxFillBack * / void gfxFillBack (DWORD dwColor) {DDBLTFX ddbltfx; ddbltfx.dwSize = sizeof (ddbltfx); ddbltfx.dwFillColor = dwColor; IDirectDrawSurface_Blt (lpBackBuffer, // dest surfaceNULL, // DEST RectNull, // src surfacenull, // src reccTDBLT_COLORFILL | DDBLT_WAIT, & DDBLTFX);} / * gfxfillback * / 2. Check if the Surface of the game unit graph is lost; this is a function that checks if the Surface of the game unit graph is lost: / ** gfxrestoreAll ** restore the Art when one or more surfaces are Lost * / BOOL GFXRESTORL () {GFX_bitmap * Curr; hwnd hwndF = GetForegroundWindow (); Splash (); for (curr = lpVRAM;! curr = NULL; curr = curr-> link) {if (curr-> lpSurface && (fForceRestore || IDirectDrawSurface_IsLost (curr-> lpSurface) == DDERR_SURFACELOST )) {IF ("gfxrestoreall: *****************************); return false;}}} DdClear (); fforcerestore = false; Return True;} / * gfxrestoreAll * / 3. Painting the graphic of the game unit into the backbuffer; this is one of the functions of the game unit graphic: / ** DISPLAYPLANE * / BOOL DisplayPlane (GFX_HBM HBuffer, HPLANE * HPLANE) {ushort n; ushort i; ushort j; usort x1; Ushort y1; ushort x2; ushort y2; usort xmod; ushort ymod; point src; rect dst; x1 = (hplane-> x >> 16) / c_tile_w; y1 = (HPLANE-> Y >> 16) / c_tile_h; x2 = X1 C_SCREEN_W / C_TILE_W; Y2 = Y1 C_SCREEN_H / C_TILE_H; XMOD = (HPLANE-> X >> 16)% C_TILE_W; YMOD = (HPLANE-> Y >> 16)% c_tile_h; for (j = Y1; J The BackBuffer and FrontBuffer inversion; this is the page turning function in the full-screen mode: / ** gfxFlip * / BOOL gfxFlip (void) {HRESULT ddrval; ddrval = IDirectDrawSurface_Flip (lpFrontBuffer, NULL, DDFLIP_WAIT); if (ddrval = DD_OK! ) {MSG ("Flip Failed, RC =% 08LX", DDRVAL); RETURN FALSE;} Return true;} / * gfxflip * / This is the page flip function in window mode: / ** gfxupdateWindow * / bool gfxupdateWindow () {HRESULT ddrval; ddrval = IDirectDrawSurface_Blt (lpFrontBuffer, // dest surface & rcWindow, // dest rectlpBackBuffer, // src surfaceNULL, // src rect (all of it) DDBLT_WAIT, NULL); return ddrval == DD_OK;} / * gfxUpdateWindow * / Section 7 Computer artificial intelligent computer artificial intelligence remember? In the fifth refresh game unit, we talked to the new location of the game unit after the position of the game unit was talked, and then the new location of the game unit was again determined after obtaining the position of the game unit. Parts containing these algorithms is part of the game to realize manual intelligence. For artificial intelligence in the game, I compare the following definition: A non-player controlled object is made by the true people when decision behavior based on various complex factors, which is completed by using a decision algorithm. This decision algorithm is processed according to the rules determined by the designer and the information provided to the program. The following ways to be used in most games are mainly: retrieving many artificial intelligence algorithms involving all possibilities. The implementation of this algorithm is like this, first of all, you should let your program column a list of options, such as all possible paths between the soldiers to the purpose. Then use other artificial intelligence technology such as exclusion, etc. to find an optimal choice. Sort Sort and search are basic artificial intelligence technology, you can use sort to determine the best decision order. For example, the computer opponent in the strategic game continues to modify the priority of the current environment. Expert System Expert System refers to a logical expression using the "if Then" statement to represent all basic rules, and then the computer makes intelligent decisions based on these rules. For example, when making a football game, you can ask a football expert to write down his football experience. He will explain that in all situations, he takes the way to play. Based on this information, establish a set of rule libraries, and computer can make decisions in the game. Other ways include: Machine learning and neural network systems, the effects of these two ways are quite good. But it is not easy to master, and we will not be detailed here. Section 8 Game Memory Management Game Memory Management This part is very important for high-quality and efficient game software, and improper memory management causes the performance of the game performance, even causing a crash. Nowadays, many games use a lot of images and complex rules that require a lot of memory. This requires us to carefully allocate and organize the memory of the player's machine. First, we should investigate how much the current mainstream model is, and then weigh between the amount of memory required to achieve the design objective of the game, then determine a rough allocation scheme. This program can generally be specified: 1. This game can be divided into several parts from the plot. Turn the information shared by each part at the beginning, and then the memory occupied by this part according to the development of the plot. Release the data unique to the part. For example, it can be divided into several "world" maps in the RPG game can be divided into several scenes. Then then the corresponding image or corresponding information is then transferred in a player to a certain level or enter a certain scene. 2. There are many not commonly used in each portion and there is no strict speed limit when called, and there is no need to be used for information (usually 1 second or right), and can be called when used. For example, the role walks into a city from a large map, and information such as image and game rules of this city can be transferred when walking into this city. After completing this scenario, we have completed the planning of data exchange between memory and hard drives, and then consider the management within the runtime memory. In this step, you should pay attention to two problems: 1. Quickly release the memory of the invalid data; for example: describing the GameWorld's pointer TEMP allocates memory space when initialization. GameWorld * Temp = New gameWorld (Init Value) ;. . . Release memory space at the end of the program. Delete Temp; 2. It is strictly forbidden to use an empty pointer (this will cause system errors, even crazy). There is nothing here, only relying on your own serious and careful. For example, when Temp has been released in the program; the following call may cause a crash: TEMP-> Function (); these two problems have the solution to: GameWorld * Temp = New gameWorld (Init value); ... IF (TEMP) DELETE TEMP; TEMP = NULL; ... IF (TEMP) {TEMP-> Function (); ...} else {prompt TEMP is an empty pointer. } The 9th game interactive design game interaction design interaction design, actually what you want to make the player to manipulate the development of the game. It is said that simple interaction design is how the player can control the role of the game, in the routine settings to the keyboard - the "456237" on the small built-in "456237" control fox is a simple interaction design. It's complicated! That is, what kind of way you provide a game into the game into a game - he is a height of the game, he is a swordsman, he is the promotion of the game, the general of the world ... this It is an important element of a good game - good interactivity. Interactive is a designer's creation of a story that is induced by a game that provides a story of a story, emotional infection, real sound and other creative media. The purpose of interacting design is to let the player enter the "illusion state". The illusion is a term in the game industry. It means that the player's consciousness is integrated into the game world, so that he or she is not playing games, and It is to experience another world. How do you do this? As a programmer, consider: The first step is to consider the input device problem, the device is the means of controlling the game, that is, the selection and setting of the input device. In this step, it should be considered to choose a keyboard, mouse, jam rod, or several ways, or other types of input devices. Then set the meaning representative of various operations ("4" in the like, "4" representing the left row, "5" representative stop, etc., or the mouse click, double-click the meaning of a certain area and dragging These settings are mainly to consider the convenience of operation. typedef enum enum_ACTION {NONE, STILL, WALK, RUN, JUMP, THROW, CROUCH, STOP, STUNNED, JUMPTHROW, CROUCHWALK, BLURR, STRIKE, MISS, CHEW,} ACTION; WinMainProc in: case WM_KEYDOWN: switch (wParam) {case VK_NUMPAD5 : lastInput = KEY_STOP; break; case VK_DOWN: case VK_NUMPAD2: lastInput = KEY_DOWN; break; case VK_LEFT: case VK_NUMPAD4: lastInput = KEY_LEFT; break; case VK_RIGHT: case VK_NUMPAD6: lastInput = KEY_RIGHT; break; case VK_UP: case VK_NUMPAD8: lastInput = KEY_UP; break; case VK_HOME: case VK_NUMPAD7: lastInput = KEY_JUMP; break; case VK_NUMPAD3: lastInput = KEY_THROW; break; case VK_F5:! bShowFrameCount = bShowFrameCount; if (bShowFrameCount) {dwFrameCount = 0; dwFrameTime = timeGetTime ();} Break; Second steps Consider the problem returned by information, which is mainly an interface for an interface. This issue we have already discussed in the interface design of the first chapter, sixth game, which is not detailed here. Section 10 Game Graphics Bottom Design In the game, the computer mainly spends time on processing images and draws, so we should try our best to make these operations for hardware levels of mainstream models or minimize system resources, this is game graphics. The purpose of the underlying design. Direct 3d in the DirectDraw and DirectX5 SDK, are the bottom layer of the graphics, and the Quake C provided after the quake release is also a nice graphic underlayer. Building a set of game graphics requires a lot of knowledge about graphic programming and a lot of time energy, and the effect is not necessarily good, and there are also many graphics underground at the same time. So for a general game developer, as long as the image used by the game does not make the computer irresistible or not using the existing underlying, I suggest it or use the existing underlying.