Published at the request of my friend, if you like the article, you can send him an invite.
Soap I will tell in PM or I can write here. :)In this article I want to tell you how I started writing the game engine, I ran into the problem of writing the exact timer and how I solved it. I am sure that almost everyone sooner or later faces such a problem, so my article will be useful to those who are in the process of creating a timer or only think about it. I do not claim either for the purity of the code, nor for the ideality of the decisions taken under these conditions. And now we will finish with personal pronouns and move on to the actual problem.
The goal: to write an exact timer for use in the game engine (and this means that in addition to measuring time intervals, we need to ensure the operation of events that occur after a specified time).
First you need to decide what to use to measure time segments in general. The most logical solution for the accuracy of time measurement is the use of QueryPerformanceCounter / QueryPerformanceFrequency functions. The meaning of time measurement is to memorize the beginning of the time interval, then check the current time and return the result - the difference between the two measurements. But we need to make a "long" time, i.e., we will need to know in advance when it will pass, for example, exactly 3 seconds from the current point in time.
')
To ensure this way of working the timer, you can do the following: store “events” along with the amount of time before they start in the event manager class and, constantly measuring time periods (beginning of the next = end of the current), add time segments to the variable initially equal to 0, and as soon as in any of the events the value of the variable becomes greater than or equal to the amount of time before the start of the event, execute the event.
The amount of time before an event begins is called its duration, since an event does not always logically mean the execution of an action after the lapse of time before its start, and sometimes the execution of actions or the preservation of a status while “waiting for it to begin”. For example, in my engine, events are used to ensure the exact number of shots per second (after each shot, shooting is prohibited and allowed after a specified time, so it turns out that the event serves to save the "prohibited shooting" status).
It remains to think only about how to actually check-memorize these time periods so that it is consistent and continuous. The logical solution here would be to use a frame rate and measure the length of time in each frame. Since the QueryPerformanceCounter / QueryPerformanceFrequency functions heavily load the processor, it makes sense to limit the frame rate by performing Sleep after each of them. The coarseness of the Sleep function does not matter here, since the time will be measured continuously, that is, there will be no intervals between the measured segments.
Now a bit of code to demonstrate the above:
Full timer class:
de_timer.h:
Copy Source | Copy HTML<br/> #ifndef __DE_TIMER_H<br/> #define __DE_TIMER_H<br/> <br/> #include <windows. h ><br/> <br/> // <br/> class deTimer <br/>{<br/> LARGE_INTEGER start; // <br/> double frequency; // <br/> double tickLength; // <br/> double currentCheckTime; // <br/> double lastCheckTime; // <br/> // <br/> void init();<br/> // <br/> double getFrequency();<br/> // ( ) <br/> double readTimer();<br/> public :<br/> // <br/> void startTimer();<br/> // <br/> void updateTimer();<br/> // <br/> // : , <br/> // <br/> double getTimeInterval() { return currentCheckTime - lastCheckTime;}<br/>};<br/> <br/> #endif <br/> <br/>
de_timer.cpp:
Copy Source | Copy HTML<br/> #include "de_timer.h" <br/> <br/> // <br/> void deTimer::init()<br/>{<br/> // <br/> frequency = getFrequency();<br/> tickLength = 1 . 0 / frequency;<br/>}<br/> <br/> // <br/> double deTimer::getFrequency()<br/>{<br/> LARGE_INTEGER freq;<br/> <br/> if (!QueryPerformanceFrequency(&freq))<br/> return 0 ;<br/> return ( double )freq.QuadPart;<br/>}<br/> <br/> // ( ) <br/> double deTimer::readTimer()<br/>{<br/> // <br/> DWORD_PTR oldMask = SetThreadAffinityMask(GetCurrentThread(), 0 );<br/> // <br/> LARGE_INTEGER currentTime;<br/> QueryPerformanceCounter(¤tTime);<br/> // <br/> SetThreadAffinityMask(GetCurrentThread(), oldMask);<br/> // <br/> return (currentTime.QuadPart - start.QuadPart) * tickLength;<br/>}<br/> <br/> // <br/> void deTimer::startTimer()<br/>{<br/> // <br/> init();<br/> // <br/> DWORD_PTR oldMask = SetThreadAffinityMask(GetCurrentThread(), 0 );<br/> // <br/> QueryPerformanceCounter(&start);<br/> // <br/> SetThreadAffinityMask(GetCurrentThread(), oldMask);<br/> // <br/> lastCheckTime = currentCheckTime = readTimer();<br/> // ( ) <br/> srand(( int )start.QuadPart);<br/>}<br/> <br/> // <br/> void deTimer::updateTimer()<br/>{<br/> // <br/> lastCheckTime = currentCheckTime;<br/> // <br/> currentCheckTime = readTimer();<br/>}<br/> <br/>
You can look at the rest of the engine code in its current state on
sourceforge.net/projects/dustengineThe code for the timer and event manager is in the files:
de_timer.h, de_timer.cpp, de_event.h, de_event_manager.h, de_event_manager.cpp
Version of the engine at the time of writing: 0.1
At once I will make a reservation that the code was written by me, despite the comments in English (I make a habit of using English in projects).
UPD. The executable on sf.net is only for win7 (!) (It will probably also work on whist), on winXP it works when installing compatibility with win98 (strange, but true). All this was compiled on win7 and under win7.