|
This thread is locked; no one can reply to it. |
1
2
|
Using rest() |
Ron Rider
Member #8,208
January 2007
|
I have read a tutorial on using timers and creating a timer variable and function that increments that variable. But using this method has not been efficient in my game. I have found out that the speed differs on different computers (because of processor speed, I guess?). So, I have tried using the function rest(25) to limit the player's speed. This has worked fine so far, but I have a question. Is this a good idea? Because I read that using it in a game loop is not. If I should not be doing this, is there another way of limiting the player's/game's speed? |
kazzmir
Member #1,786
December 2001
|
Goalie Ca
Member #2,579
July 2002
|
The correct way is to yield the cpu without relying on "rests". Unfortunately the code i posted in that section is not "portable across operating systems".. meaning you need to do something different on windows. Same concept.. but different function names. ------------- |
Tobias Dammers
Member #2,604
August 2002
|
The basic idea is to have a clock that runs more or less independently from your main program, and at the same time, while the main loop queries the timer whenever it needs to know what time it is. Once you have such a timer, your main loop now does: --- |
Edgar Reynaldo
Major Reynaldo
May 2007
|
- Tobias - clock : cppreference.com said:
#include <time.h> The clock() function returns the processor time since the program started, or -1 if that information is unavailable. To convert the return value to seconds, divide it by CLOCKS_PER_SEC. (Note: if your compiler is POSIX compliant, then CLOCKS_PER_SEC is always defined as 1000000.)
Clock type is 4 bytes large on my system , what does it do if it overruns a 4 byte unsigned integer? (Just guessing that's what a clock_t really is) - actually since the function can return -1 then a clock_t can't be unsigned. So then assuming it is a signed int then : Programs often run longer than thirty five minutes , what happens then? My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
torhu
Member #2,727
September 2002
|
According to the linux man page, clock() wraps around every 72 minutes on 32 bit systems. To detect that, just compare with the previous value of clock, and if needed, compensate by doing 'new_clock = ULONG_MAX - (unsigned long)old_clock + (unsigned long)new_clock + 1'. Something like that should work for 32 and 64 bit systems, because the wraparound will never happen on 64 bits anyway. You should probably try Allegro timers first. |
Thomas Fjellstrom
Member #476
June 2000
|
clock is defined to be some arbitrary representation of the CPU "ticks" that have passed, even though its defined to tick N times a second, no matter the cpu speed. its rather quite silly. -- |
Audric
Member #907
January 2001
|
To answer Ron Rider's question ("is it a good idea"), this is why it fails: Note: The Allegro timer method should have worked, and give the same average frequency on all computers. If you still have the code for that older version, we can try to find the error. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
I wrote a short clock() tester. (Testing if / how well clock_t overflows) It's kind of pathetic though , since CLOCKS_PER_SEC is only 1000 for me. Not the 1000000 I was expecting. Is MinGW not POSIX compliant then? Oh , and that means it wouldn't overflow for me until 35791 minutes had passed. That's too long to wait. From time.h (MinGW 3.1) /* * Number of clock ticks per second. A clock tick is the unit by which * processor time is measured and is returned by 'clock'. */ #define CLOCKS_PER_SEC ((clock_t)1000) #define CLK_TCK CLOCKS_PER_SEC I've added something in to determine the max size of clock_t and estimate how long it will take until clock_t overflows and restarts at zero. If anyone would be kind enough to compile/run this and show me the first thirty lines or so of the text log I'd appreciate it. I want to know if my counters will handle the clock_t overflow properly. If it says the clock_t will overflow in a reasonable amount of time please let it run that long plus a few minutes and send me the log. Don't worry , an hour and 23 minutes of run time only produces a 23KB log. I like to open the text log in a web browser while it is running and refresh it every once in a while. mingw32-g++ -Wall -ggdb -Wshadow -mconsole -o ClockTest.exe ClockTest.cpp -lalld Here it is if you'd like to see it. The [url http://www.allegro.cc/files/attachment/593651]source[/url] is attached. 1
2
3#include <time.h>
4#include <fstream>
5#include <iostream>
6
7#define ALLEGRO_USE_CONSOLE
8
9#include <allegro.h>
10#include <limits.h>
11
12using std::endl;
13using std::ofstream;
14using std::ios;
15using std::cout;
16
17ofstream text_log(".\\clock_test_log.txt" , ios::out);
18
19#define MAX_NUM_CLOCK_FAILURES 100
20
21int main() {
22
23 if (!text_log) {return 0;}
24
25 time_t start_time , finish_time;
26 clock_t clocks = clock();
27 time(&start_time);
28
29 if (allegro_init() != 0) {
30 text_log << "Allegro initialization failed. Ending program." << endl;
31 return 0;
32 }
33 if (install_keyboard() != 0) {
34 text_log << "Allegro Keyboard initialization failed. Ending program." << endl;
35 return 0;
36 }
37 if (install_timer() != 0) {
38 text_log << "Allegro Timer initialization failed. Ending program." << endl;
39 return 0;
40 }
41
42 cout << "ClockTest in progress , writing to .\\clock_test_log.txt , press ESC to quit at anytime." << endl;
43
44
45 clock_t last_clock = 0;
46 clock_t last_clock_displayed = 0;
47 clock_t clocks_passed = 0;
48 clock_t max_clocks_so_far = 0;
49
50 bool clock_fail = false;
51 int clock_fail_count = 0;
52 bool output_tracked_time = false;
53 int second_counter = 0;
54 int minute_counter = 0;
55 int hour_counter = 0;
56 int day_counter = 0;
57 int week_counter = 0;
58 int year_counter = 0;// Why would you let this program run an entire year?
59
60 const int SECS_PER_MIN = 60;
61 const int MINS_PER_HOUR = 60;
62 const int HRS_PER_DAY = 24;
63 const int DAYS_PER_WEEK = 7;
64 const int WKS_PER_YEAR = 52;
65
66 const int SECS_PER_HOUR = SECS_PER_MIN*MINS_PER_HOUR;
67 const int SECS_PER_DAY = SECS_PER_HOUR*HRS_PER_DAY;
68 const int SECS_PER_WEEK = SECS_PER_DAY*DAYS_PER_WEEK;
69 const int SECS_PER_YEAR = SECS_PER_WEEK*WKS_PER_YEAR;
70
71 const int clock_t_size = sizeof(clock_t);
72 const int clock_t_size_bits = clock_t_size*8;
73 long long int estimated_clock_t_max = 1;
74 for (int x = 1 ; x < clock_t_size_bits ; x++) {
75 estimated_clock_t_max *= 2;
76 }
77 estimated_clock_t_max -= 1;
78
79 bool use_estimated_clock_t_max = false;
80
81 long long int num_secs_to_overflow = 0;
82
83 if (sizeof(clock_t) != sizeof(long)) {
84 use_estimated_clock_t_max = true;
85 num_secs_to_overflow = LONG_MAX / CLOCKS_PER_SEC;
86 if ((LONG_MAX%CLOCKS_PER_SEC) != 0) {
87 num_secs_to_overflow += 1;
88 }
89 } else {
90 num_secs_to_overflow = estimated_clock_t_max / CLOCKS_PER_SEC;
91 if ((estimated_clock_t_max%CLOCKS_PER_SEC) != 0) {
92 num_secs_to_overflow += 1;
93 }
94 }
95
96 int num_yrs_to_overflow = num_secs_to_overflow / SECS_PER_YEAR;
97 num_secs_to_overflow -= num_yrs_to_overflow*SECS_PER_YEAR;
98
99 int num_wks_to_overflow = num_secs_to_overflow / SECS_PER_WEEK;
100 num_secs_to_overflow -= num_wks_to_overflow*SECS_PER_WEEK;
101
102 int num_days_to_overflow = num_secs_to_overflow / SECS_PER_DAY;
103 num_secs_to_overflow -= num_days_to_overflow*SECS_PER_DAY;
104
105 int num_hrs_to_overflow = num_secs_to_overflow / SECS_PER_HOUR;
106 num_secs_to_overflow -= num_hrs_to_overflow*SECS_PER_HOUR;
107
108 int num_mins_to_overflow = num_secs_to_overflow / SECS_PER_MIN;
109 num_secs_to_overflow -= num_mins_to_overflow*SECS_PER_MIN;
110
111// double elapsed_seconds = 0.0;
112
113
114
115
116 text_log << "----------------------------------------------------------------------------" << endl;
117 text_log << endl;
118 text_log << "Starting Clock Test using the c function clock() :" << endl;
119 text_log << " Allegro initialization and keyboard initialization successful." << endl;
120 text_log << " Test began at " << ctime(&start_time) << endl;
121 text_log << endl;
122 text_log << " Sizeof(clock_t) = " << sizeof(clock_t) << " , Sizeof(long) = " << sizeof(long) << endl;
123 text_log << " Estimated_clock_t_max = " << estimated_clock_t_max << " , LONG_MAX = " << LONG_MAX << endl;
124 text_log << endl;
125 text_log << " CLOCKS_PER_SEC is defined as [" << CLOCKS_PER_SEC << "]" << endl;
126 text_log << " LONG_MAX is defined as [" << LONG_MAX << "]" << endl;
127 text_log << " At start of main , clock() returned [" << clocks << "]" << endl;
128 text_log << endl;
129 text_log << "Estimated time to clock_t overflow is :" << endl;
130 text_log << " " << num_yrs_to_overflow << " Years , " << num_wks_to_overflow << " weeks , " << num_days_to_overflow << " days , ";
131 text_log << num_hrs_to_overflow << " hours , " << num_mins_to_overflow << " minutes , " << num_secs_to_overflow << " seconds." << endl;
132 text_log << endl;
133 text_log << "----------------------------------------------------------------------------" << endl;
134
135 while (!(key[KEY_ESC]) ) {
136
137 if (!clock_fail) {
138 last_clock = clocks;
139 }
140 clocks = clock();
141
142 if (clocks != -1) {
143 clock_fail = false;
144 if (clocks > max_clocks_so_far) {max_clocks_so_far = clocks;}
145
146 if (clocks < last_clock) {// clock_t overflowed and started over
147 // reset last_clock to zero , !!!$$$ this will miss Actual_max_clocks - max_clocks_so_far
148 // unless there is some kind of clock_t_MAX , clock_t is a typedef for long in time.h (mingw 3.1)
149 // so what is long_MAX then - okay , limits.h (mingw 3.1) #defines LONG_MAX as 2147483647L
150 /// Okay , so assign clocks_passed to clocks_passed + (LONG_MAX - last_clock) + clocks
151 text_log << endl;
152 text_log << "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl;
153 text_log << "$$$###!!! Clock() overflowed clock_t (long) << last_clock = " << last_clock;
154 text_log << " , clocks = " << clocks << " !!!###$$$" << endl;
155 text_log << "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" << endl;
156 text_log << endl;
157 if (use_estimated_clock_t_max) {
158 clocks_passed += (estimated_clock_t_max - last_clock) + clocks;
159 } else {
160 clocks_passed += (LONG_MAX - last_clock) + clocks;
161 }
162 } else {
163 clocks_passed += (clocks - last_clock);
164 }
165
166 while (clocks_passed >= CLOCKS_PER_SEC) {
167
168 clocks_passed -= CLOCKS_PER_SEC;
169 second_counter = (second_counter + 1)%60;
170 if (second_counter != 0) {
171 text_log << second_counter << " ";
172 text_log.flush();
173 output_tracked_time = false;
174 } else {
175 output_tracked_time = true;
176 }
177 if (second_counter == 0) {
178 minute_counter = (minute_counter + 1)%60;
179 if (minute_counter == 0) {
180 hour_counter = (hour_counter + 1)%24;
181 if (hour_counter == 0) {
182 day_counter = (day_counter + 1)%7;
183 if (day_counter == 0) {
184 week_counter = (week_counter + 1)%52;
185 if (week_counter == 0) {
186 year_counter = year_counter + 1;// You can count the centuries on your own.
187 }
188 }
189 }
190 }
191 }
192 if (output_tracked_time) {
193 text_log << endl;
194 text_log << minute_counter << " mins , " << hour_counter << " hrs , " << day_counter << " days , ";
195 text_log << week_counter << " wks , and " << year_counter << " yrs since this program began running. clocks = [";
196 text_log << clocks << "]" << endl;
197 text_log << second_counter << " ";
198 text_log.flush();
199 }
200 }
201 } else {
202 clock_fail = true;
203 clock_fail_count++;
204 text_log << endl;
205 text_log << "### Clock() returned -1 , clocks passed since program start unavailable" << endl;
206 }
207
208 if (clock_fail_count >= MAX_NUM_CLOCK_FAILURES) {
209 text_log << "!!!###$$$ Too many clock failures , fail count = " << clock_fail_count << endl;
210 break;
211 }
212 rest(1);
213 }
214
215 time(&finish_time);
216
217
218 text_log << endl;
219 text_log << endl;
220 text_log << "$$$### The highest number of clocks reached was [" << max_clocks_so_far << "] ###$$$" << endl;
221 text_log << " Test started at " << ctime(&start_time);
222 text_log << " Test completed at " << ctime(&finish_time) << endl;
223
224 return 0;
225}
226END_OF_MAIN()
My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Elias
Member #358
May 2000
|
In Linux, clock() measures CPU time not real time - so you can't use it. The result will depend on how much CPU processing is done between two calls of clock - and not how much time passes. clock() is perfect for timing different algorithms, as it won't matter if you have some other programs running in the back which take up real time. clock() in that case will just return how much time your process was taking. But for timing the game, you want it to run smooth in real time, so you need to measure real time. (And Allegro's timer usually is more than enough for that, especially if you are just using a fixed amount, e.g. 60, logic ticks per second, without interpolating your graphics to vsyncs.) -- |
Ron Rider
Member #8,208
January 2007
|
Thanks for all your input guys. I'll try and work the Allegro timer method back into my game, and see if I can work with that a little. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
- Elias - I fixed a bug so the appropriate value for clock_t max would be used if/when it overflows clock_t. Here's the new Source code. Thanks. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Elias
Member #358
May 2000
|
Result is below. I had to fix two things, \ can't be used in paths under Linux like you do, and keyboard input only works once you create a window with set_gfx_mode. And I think you have some bug in your overflow formula..
-- |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Okay , I fixed the .// to .\ and it still works on Windows. I changed it from a console program to a nice 480 X 360 windowed program with relevant data shown on the screen. The main portion of the screen is updated every CLOCKS_PER_SEC so if clock() doesn't measure actual time on the platform/compiler combo this will be reflected in the main portion of screen output data not changing. However , the second counter in the lower left and the rest count in the bottom center of the screen will be updated every time rest(1) is called. The second counter in the lower left is based off of clock() seconds elapsed. It should be pretty obvious whether clock() is counting cpu_time or real_time. For an even further confirmation of this wave the window around quickly for several seconds. This should cause enough processing time to pass the CLOCKS_PER_SEC update threshold and there should be an obvious discrepancy between the current system time reported in the middle of the screen and the cumulative time based on clock() just below it. - Ron Rider - Maybe I'll try working in allegro timers in to the program , but that is a task for a different day. - Elias - My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Evert
Member #794
November 2000
|
Quote: BTW , do you know if any of the Allegro Developers have taken a look at the Tester for set_gfx_mode post that I made? I've seen it, but seeing how its a Windows issue I didn't have a closer look. Quote: There are several specific reproducible errors I have with using set_gfx_mode to change from a non-desktop sized fullscreen mode to a windowed mode that is smaller. ( It only happens when the monitor physically changes resolution ) I was hoping that the examples I posted would help track down what is wrong. I'm sure they would. Quote: I'm willing to help track it down and fix it too , but the vtable and system drivers kind of make my head spin.
It's not so bad once you get used to it. The function names are usually quite logical, but from what I remember the Windows driver was particularly messy. Ok, maybe not as messy as the X11 driver, but messy in a different way. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Thank you Evert for the response. I assume that I will need to get familiar with DirectDraw and DirectX to some basic degree , do you have any good references? I guess I'll just find a buddy to download it and burn me a copy of it. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
Evert
Member #794
November 2000
|
Quote: I assume that I will need to get familiar with DirectDraw and DirectX to some basic degree , do you have any good references? MSDN and/or tutorials on the internet accesible through google. I'm not really the right person to ask, not knowing a thing about DirectX. On the upside, I've made contributions to Allegro's Windows port in the past, so knowing DirectX is not a prerequisite. Quote: I looked at the DirectX Downloads Page [msdn2.microsoft.com] at Microsoft , but it looks like the SDK's have started leaving out older versions. I have the .Net 2.0 framework SDK and the Win Platform SDK installed , but they don't have a DirectX reference do they? No , I can't find anything for DX in those. I guess I have to download the DX SDK but I only have dialup and I can't find a link to order a CD with the SDK on it. If you can compile Allegro from source, you already have the SDK you need and you don't need to download anything. Quote: Allegro 4.2.2 works with DirectX 7 doesn't it? DirectX 3, unless something changed lately. |
Ron Rider
Member #8,208
January 2007
|
I'm having trouble getting the game to compile when adding the timer. The line: if( install_int_ex(t_game_speed_counter, BPS_TO_TIMER(60)) ) return false; But when I try to compile I get this message: Quote: error C2664: 'install_int_ex' : cannot convert parameter 1 from 'volatile long' to 'void (__cdecl *)(void)' I've create the timer variable and function, and locked them both. I have not had this problem before, does anyone know what is wrong here? |
Jonatan Hedborg
Member #4,886
July 2004
|
That's because you are giving it the counter, not the function.
|
Ron Rider
Member #8,208
January 2007
|
Thanks. Man do I feel stupid. |
aj5555
Member #9,033
September 2007
|
if anyone is calling rest(>1) then you have a design problem. rest(0) or rest(1) any other values are in-appropriate. if you dont know why, then you have to follow this rule, until you do know why, and if you do know why, then you obviously smart enough to not have to follow this rule. |
Elias
Member #358
May 2000
|
rest(1) waits one millisecond (plus any time it takes the kernel to re-schedule your app - so a few years ago that might actually have been 10-20 ms). But usually, if you have a game running at 60 FPS, then rest(1000.0 / 60 - time_used_for_logic_and_rendering) is more appropriate than rest(1). -- |
Audric
Member #907
January 2001
|
During game, I see rest(1) as the smallest tradeoff of performance (as usually visible in scrolling smoothness) in favor of CPU economy. Laptop computers will thank you: CPU time = heating, noisy fans, low battery life. That being said, I've played enough with the Allegro timers, now I'm going to try the other methods. |
Tobias Dammers
Member #2,604
August 2002
|
If your main loop is designed well enough, then rest(1) will push your program from checking a single value whenever it gets a chance to checking a single value no more than one thousand times per second. While a millisecond sounds like a tiny interval, reducing the number checks from "as many times as possible" to "no more than one thousand times per second" has a dramatic effect in most cases, far more dramatic than reducing from 1000 times to 100 - simply because "as many times as possible" means "a couple hundred million times per second". --- |
Vanneto
Member #8,643
May 2007
|
Quote: If your main loop is designed well enough, Could you show us a well designed main loop? In capitalist America bank robs you. |
|
1
2
|