This seriesArticleWritten by zhmxy555. For details, refer to the source. Http://blog.csdn.net/zhmxy555/article/details/7355377
Author: Mao yunxing mailbox: happylifemxy@qq.com welcome mail exchange programming experience
InIn note 7, we explained how to use a timer to produce an animation. The timer is easy to use, but in fact this method is only suitable for displaying simple animations and small games.Program. In general, the game itself needs to display a smooth game screen, so that players do not feel the status of delay. The basic game screen must be updated at least 25 times in one second. During this second, the program must perform operations such as message processing, a large number of mathematical operations, and even sound output. The use of timer messages to drive these operations often fails to meet the required standards, otherwise there will be a situation where the screen is not smooth and the game response time is too long.
Here we propose the concept of a game loop. The game loop is to modify the message loop in the original program by checking whether there are messages to be processed in the content, if yes, the image is processed. Otherwise, the image is re-painted at the specified interval. The following is the game loop ProgramCode:
// Game loop while (msg. message! = Wm_quit) // annotation 1 (for details, see below) {If (peekmessage (& MSG, null, pm_remove) // annotation 2 (for details, see below) {translatemessage (& MSG); dispatchmessage (& MSG) ;}else {tnow = gettickcount (); // comment 3if (tnow-tpre> = 100) // annotation 4 mypaint (HDC );}}
Let's explain several key points in the loop fragment of the game.
<1> Note 1: When the MSG is received. if the message is not the window End message wm_quit, it continues to run the loop. MSG is a message structure of MSG, and its structure member message is a message type code.
<2> NOTE 2: Use the peekmessage () function to check whether there are currently any messages to be processed. If a message (including wm_quit messages) is detected) A non-"0" value is returned; otherwise, "0" is returned ". Therefore, if a message is detected in a game loop, the message is processed; otherwise, the program code after the else statement is run. Here, we should note that the peekmessage () function cannot be replaced by the original message loop condition getmessage (), because getmessage () the function returns "0" Only when obtaining the wm_quit message. Otherwise, it returns a non-"0" value or "-1" (when an error occurs)
<3> NOTE 3: The gettickcount () function obtains the time elapsed since the system started running, in milliseconds (milliseconds ). I understood it wrong before. Here, I would like to thank worldy for pointing out my mistake.
DWORD gettickcount () // obtain the time when the system starts to pass through
The purpose of obtaining the time here is to match the following sequence to adjust the running speed of the game, so that the game will not run too fast or too slowly because of the speed of running the computer.
<4> NOTE 4: In the if condition, "tpre" records the time of the previous drawing, while "tnow-trre" calculates the time difference between the last drawing and the current loop operation. If the difference is set to more than 40 units of time, the plotting operation is performed again. The speed of game operation can be adjusted through the control of this value. The reason for setting 40 units of time (microseconds) is that, because the Drawing operation is performed every 40 units, the re-painting window 1000/40 = 25 times in one second can meet the expected value.
Because the cycle runs much faster than the timer sends a time signal, the game loop can more accurately control the running speed and increase the number of screen repainting times per second.
After learning about the basic concepts of game loop usage, the following example uses the game loop method to continuously map Windows to make more precise game animation effects.
# include "stdafx. H "# include
// global variable declaration hinstance hinst; hbitmap MAN [7]; HDC, MDC; hwndhwnd; dwordtpre, tnow, tcheck; // declare three functions to record the time, tpre records the last drawing time, tnow records the drawing preparation time, tcheck records the start time of the second int num, frame, FPS; // num is used to record the graph number, frame is used to accumulate the number of screen updates. FPS is used to record the number of screen updates per second. // The global function declaration atom myregisterclass (hinstance); bool initinstance (hinstance, INT); lresult callbackwndproc (Hwnd, uint, wparam, lparam); void mypaint (HDC); // *** winmain function, program entry point function ************************************* * int apientry winmain (hinstance, hinstance hprevinstance, lpstr lpcmdline, int ncmdshow) {MSG; myregisterclass (hinstance); // run the initialization function if (! Initinstance (hinstance, ncmdshow) {return false ;}
Getmessage (& MSG, null); // thanks to the reminder from xiaoxiangp, MSG needs to be initialized before entering the message loop to avoid the possibility of an endless loop. // Game loop while (msg. message! = Wm_quit) {If (peekmessage (& MSG, null, 0,0, pm_remove) {translatemessage (& MSG); dispatchmessage (& MSG) ;} else {tnow = gettickcount (); if (tnow-tpre> = 100) // re-paint mypaint (HDC) when the cycle is 0.1 seconds different from the previous drawing time;} return MSG. wparam;} // ***** design a window class, which is similar to a blank question, use the window struct ************************ atom myregisterclass (hinstance) {wndclassex wcex; wcex. cbsize = sizeof (wndclassex); wcex. style = cs_hredraw | cs_v Redraw; wcex. lpfnwndproc = (wndproc) wndproc; wcex. cbclsextra = 0; wcex. cbwndextra = 0; wcex. hinstance = hinstance; wcex. hicon = NULL; wcex. hcursor = NULL; wcex. hcursor = loadcursor (null, idc_arrow); wcex. hbrbackground = (hbrush) (color_window + 1); wcex. lpszmenuname = NULL; wcex. lpszclassname = "canvas"; wcex. hiconsm = NULL; return registerclassex (& wcex );} ******************************** * *** // load the bitmap boo from the file L initinstance (hinstance, int ncmdshow) {char filename [20] = ""; int I; hinst = hinstance; hwnd = createwindow ("canvas", "animation demo ", ws_overlappedwindow, cw_usedefault, 0, cw_usedefault, 0, null, null, hinstance, null); If (! Hwnd) {return false;} movewindow (hwnd, 10, 10, 600,450, true); showwindow (hwnd, ncmdshow); updatewindow (hwnd); HDC = getdc (hwnd ); MDC = createcompatibledc (HDC); // load the bitmap of each character for (I = 0; I <7; I ++) {sprintf (filename, "manw.d.bmp", I ); MAN [I] = (hbitmap) LoadImage (null, filename, image_bitmap, 640,480, lr_loadfromfile);} num = 0; frame = 0; mypaint (HDC); Return true ;} ****************************** * ** // 1. calculates and displays the number of screen updates per second // 2. perform the window Paster void mypaint (HDC) {char STR [40] = ""; if (num = 7) num = 0; frame ++ according to the sequence of graph numbers; // increase the number of screen updates by 1if (tnow-tcheck> = 1000) // you can determine whether the drawing time has reached the interval of 1 second from the previous second. If yes, the current 'framework' value is assigned to "FPS", indicating the number of screen updates in the second, and then the "frame" value is returned to 0, reset the start time of the next screen count per second "icheck ". {FPS = frame; frame = 0; tcheck = tnow;} SelectObject (MDC, MAN [num]); // select the pattern to be updated to MDC, then output the string that shows the number of screen updates per second to MDC, and finally paste the MDC content to the window. Sprintf (STR, "% d screenshots per second", FPS); textout (MDC, 600,450, STR, strlen (STR); bitblt (HDC, MDC,, srccopy); tpre = gettickcount (); // record the drawing time for you to determine whether the screen update interval has been reached in the next game loop. Num ++ ;} ***************************** * *** lresult callback wndproc (hwnd, uint message, wparam, lparam) {int I; Switch (Message) {Case wm_destroy: // window End message deletedc (MDC); for (I = 0; I <7; I ++) deleteobject (MAN [I]); releasedc (hwnd, HDC); postquitmessage (0); break; default: // other messages return defwindowproc (hwnd, message, wparam, lparam);} return 0 ;}
The running result of the program is as follows:
Of course, to get the above animation, we need to put several bitmap files under the project folder.
In this example, the screen update interval is set to 0.1 seconds, so a maximum of 10 screen updates per second. However, if you run other programs while running this example, the CPU must immediately process the other programs enabled, which may slightly reduce the number of screen updates per second.
Note 8 ends here.
This sectionSource codeClick here to download: [visual c ++] code_note_8
Please stay tuned[Visual c ++] Game Development notesSeries.
I very much hope to communicate with you and learn and make progress together.
Finally, thank you for your support ~~~
The end