rubygame 2.4.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS CHANGED
@@ -1,5 +1,103 @@
1
1
  = NEWS
2
2
 
3
+ == Rubygame 2.5.0
4
+
5
+ Release focus: Clock improvements.
6
+
7
+ === Features
8
+
9
+ - New and improved algorithm for calculating framerate.
10
+
11
+ - Better Clock compatibility with multithreaded applications:
12
+
13
+ - Clock.delay and Clock.wait now accept a new argument: +nice+.
14
+ If nice is +true+, these methods try to allow other ruby threads
15
+ to run during the delay. The default behavior is to block other
16
+ threads, as previous versions of Rubygame do.
17
+
18
+ - Added: Clock @nice.
19
+ This instance variable controls the +nice+ value used while
20
+ delaying in #tick (if framerate limiting is active).
21
+
22
+ - Better control over the balance between CPU usage and accuracy
23
+ when using Clock's framerate limiting:
24
+
25
+ - Added: Clock @granularity.
26
+ This instance variable controls the granularity value used while
27
+ delaying in #tick (if framerate limiting is active). Smaller
28
+ values lower CPU usage, but framerate limiting will be less
29
+ accurate if the granularity is lower than the system's actual
30
+ clock granularity. Use Clock#calibrate to find the best value for
31
+ the current system.
32
+
33
+ - Added: Clock#calibrate.
34
+ Call this after you create a Clock instance calibrate the Clock's
35
+ granularity to match the system's actual clock granularity. This
36
+ reduces wasteful CPU usage when using framerate limiting.
37
+
38
+ - New ClockTicked event for use with EventHandlers:
39
+
40
+ - Added: ClockTicked event class.
41
+ If you call Clock#enable_tick_events, Clock#tick will return an
42
+ instance of ClockTicked instead of the raw delay time in milliseconds.
43
+
44
+ - Added: TickTrigger event trigger class.
45
+ Matches ClockTicked events.
46
+
47
+ - HasEventHandler#make_magic_hooks accepts the symbol :tick to create a
48
+ TickTrigger.
49
+
50
+ - Added: Clock#frametime.
51
+ Returns the actual milliseconds per frame recorded by the Clock.
52
+
53
+ - New in-depth Clock tutorial, "Managing Framerate".
54
+ See doc/managing_framerate.rdoc[link:files/doc/managing_framerate_rdoc.html].
55
+ An accompanying code example has also been added, samples/framerate.rb.
56
+
57
+ - A few Screen additions:
58
+
59
+ - Added: Screen.get_resolution. Returns the user's desktop resolution.
60
+ Due to a limitation of SDL, this can ONLY be used when the Rubygame
61
+ window is closed (i.e. before you have called Screen.new, or after
62
+ you have called Screen.close).
63
+
64
+ - Added: Screen.close. Closes the Rubygame window, if it's open.
65
+
66
+ - Added: Screen.open?. True if the Rubygame window is open.
67
+
68
+ - Added: Screen.open (alias of Screen.new).
69
+
70
+ - Added: HasEventHandler#make_magic_hooks_for.
71
+ It's like make_magic_hooks, but the hook's owner will be the
72
+ specified object, instead of the object with the handler.
73
+
74
+ === Other Stuff
75
+
76
+ - Various Clock fixes and improvements:
77
+
78
+ - Clock#tick when called for the first time, no longer considers the
79
+ creation time of the Clock instance to be "the previous tick",
80
+ when checking how much time has passed.
81
+
82
+ - Clock#tick won't do any extra delay if the frame has already taken
83
+ longer than the target.
84
+
85
+ - Clock.delay and Clock.wait handle negative numbers more gracefully.
86
+ Instead of hanging for a long time, they act as if the values were 0.
87
+
88
+ - Deprecation: Screen.set_mode and Screen.instance (both aliases of
89
+ Screen.new) are deprecated and will be removed in Rubygame 3.0.
90
+ Use Screen.new or Screen.open instead.
91
+
92
+ - Deprecation: Ftor is deprecated and will be removed in Rubygame 3.0.
93
+ A mostly-compatible vector class will be provided at or before that time.
94
+
95
+ - Deprecation: MediaBag is deprecated and will be removed in Rubygame 3.0.
96
+ Use the NamedResource functionality of Music, Sound, and Surface instead.
97
+
98
+
99
+
100
+
3
101
  == Rubygame 2.4.1
4
102
 
5
103
  Release focus: Bug fixes; Ruby 1.9 compatibility.
data/ROADMAP CHANGED
@@ -6,19 +6,6 @@ keep in mind that specific details may change over time.
6
6
 
7
7
  == 2.X.0 (_possible_ minor releases before 3.0.0)
8
8
 
9
- === Focus: Clock
10
-
11
- - New Events::ClockTicked class with lots of information
12
- - Time since last frame, in both seconds and milliseconds
13
- - Current time
14
- - Current framerate
15
-
16
- - New clock class
17
- - Based on Ruby's timer (allows multi-threading)
18
- - Better framerate calculation algorithm
19
- - #tick returns an instance of Events::Tick
20
-
21
-
22
9
  === Focus: Surface & Rect
23
10
 
24
11
  - Surface improvements
data/Rakefile CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
  # The version number for Rubygame.
9
- RUBYGAME_VERSION = [2,4,1]
9
+ RUBYGAME_VERSION = [2,5,0]
10
10
 
11
11
 
12
12
  #
@@ -379,7 +379,7 @@ rubygame_core = ExtensionModule.new do |core|
379
379
  'rubygame_joystick',
380
380
  'rubygame_screen',
381
381
  'rubygame_surface',
382
- 'rubygame_time',
382
+ 'rubygame_clock',
383
383
  ]
384
384
  core.create_all_tasks()
385
385
  end
@@ -0,0 +1,303 @@
1
+ = Managing Framerate
2
+
3
+ This is a guide to using the Rubygame::Clock class in your games to
4
+ monitor and limit the game's framerate. It also gives tips and
5
+ good practices for dealing with framerate and time units in your
6
+ application.
7
+
8
+ The theory and general information here is applicable to most game
9
+ development platforms, so you may find this guide useful even if you
10
+ are not using Rubygame.
11
+
12
+
13
+ == The Short Version
14
+
15
+ 1. When your game launches, ceate a Clock instance, set the target
16
+ framerate, enable tick events, and calibrate it.
17
+
18
+ 2. If your game uses multiple ruby threads, set Clock#nice to true.
19
+
20
+ 3. Call Clock#tick once per frame. It returns a
21
+ Rubygame::Events::ClockTicked instance.
22
+
23
+ 4. Use ClockTicked#seconds to see how much time passed since the
24
+ previous frame. Use that number to calculate how far your
25
+ characters moved, etc.
26
+
27
+ 5. You can check the framerate with Clock#framerate.
28
+
29
+
30
+ === Usage Example
31
+
32
+ require "rubygame"
33
+
34
+ $clock = Rubygame::Clock.new()
35
+
36
+ # Set the desired framerate.
37
+ $clock.target_framerate = 20
38
+
39
+ # Make Clock#tick return ClockTicked (Rubygame 2.5+)
40
+ $clock.enable_tick_events()
41
+
42
+ # Allow Clock to work nicely with multiple ruby threads.
43
+ # You can skip this if you don't use multiple threads.
44
+ $clock.nice = true
45
+
46
+ # Optimize clock for this computer.
47
+ puts "Calibrating... "
48
+ $clock.calibrate()
49
+ puts "New granularity: %d ms"%[$clock.granularity]
50
+
51
+ i = 0
52
+
53
+ catch :quit do
54
+ loop do
55
+
56
+ tick_event = $clock.tick() # call tick once per frame.
57
+
58
+ # Give tick_event to an event handler or queue, or whatever.
59
+
60
+ fps = $clock.framerate # current framerate
61
+ diff = tick_event.seconds # time since previous call to tick
62
+
63
+ puts "Tick %0.2d = %0.2d fps (%0.4f s since previous)"%[i, fps, diff]
64
+
65
+ i += 1
66
+ throw :quit if( i > 50 )
67
+
68
+ end
69
+ end
70
+
71
+
72
+ == Background
73
+
74
+ Almost all games and other interactive applications have a main loop,
75
+ code that is repeated many times per second to take user input, update
76
+ the status of the game, and refresh the screen, among other things.
77
+ Each repetition of this loop is one *frame*, and the number of frames
78
+ that occur in one second is called the *framerate* or FPS (frames per
79
+ second).
80
+
81
+
82
+ == Effects of Framerate
83
+
84
+ In general, the higher the framerate, the smoother the motion in your
85
+ game seems.
86
+
87
+ At low framerates (generally less than 12-15 FPS), the game will
88
+ feel "choppy" or "jerky" to the user. At even lower framerates
89
+ (less than 5), the user may find it frustrating to interact with the
90
+ game. Obviously, that's bad!
91
+
92
+ High framerates appear smoother, but only up to a point. For example,
93
+ a user will almost certainly notice a big difference between 5 and 10
94
+ FPS, but would probably not notice much difference between 50 and 100
95
+ FPS. Framerates above 60 FPS are usually just a waste, as they use
96
+ much more CPU power but have very little gained smoothness.
97
+
98
+ So, it's best to find a balanced framerate, which will appear smooth to
99
+ the user, without being wasteful. A good framerate is usually in the
100
+ range of 20-40 FPS, but varies from game to game. For example, a
101
+ fast-paced action game may need 60 FPS, while a slow-paced puzzle game
102
+ may be fine with only 10.
103
+
104
+
105
+ == Framerate Monitoring
106
+
107
+ === How to Enable Framerate Monitoring
108
+
109
+ Rubygame's Clock class makes it simple to monitor (measure) framerate.
110
+ Simply call Clock#tick exactly once in your main game loop. Clock will
111
+ measure the time since the previous tick. From that information,
112
+ collected over many frames, it can determine the framerate that your
113
+ game is running at.
114
+
115
+ You can get the average recorded framerate, in frames per second, with
116
+ Clock#framerate.
117
+
118
+ If you prefer, you can get the frametime (the average time it took to
119
+ make one frame), measured in milliseconds per frame, with
120
+ Clock#frametime. Clock#frametime is equivalent to 1000.0 /
121
+ Clock#framerate.
122
+
123
+
124
+ === Finding Out How Long a Frame Took
125
+
126
+ The Clock#tick method returns information about how long it has been
127
+ since the previous frame. You can use this information to decide how
128
+ far objects in your game should move. (See the Framerate Independence
129
+ section, below).
130
+
131
+ For backwards compatibility, Clock#tick by default returns the number
132
+ milliseconds since the previous frame as an integer. But if you call
133
+ Clock#enable_tick_events (in Rubygame 2.5+), Clock#tick will instead
134
+ return an instance of ClockTicked containing that information. You can
135
+ then get that information with either ClockTicked#milliseconds or
136
+ ClockTicked#seconds, whichever is more convenient for you.
137
+
138
+
139
+ == Framerate Limiting
140
+
141
+ === Why Limit the Framerate?
142
+
143
+ If you don't limit the framerate of your game, the main loop will
144
+ repeat as quickly as the computer can run it. This will make the game
145
+ run as smoothly as possible, but it will also use as much of the
146
+ computer's CPU power as it can!
147
+
148
+ This can make other applications on the computer run more slowly or
149
+ choppily. Also, running the CPU full throttle uses more electricity,
150
+ so laptops and other mobile devices will lose battery charge faster.
151
+ It can also make the laptop get uncomfortably warm, or trigger the
152
+ fans on the laptop to turn on, causing unwanted noise.
153
+
154
+ Another benefit of framerate limiting is that it can make your game
155
+ run at a stable, consistent framerate. However, it is poor practice
156
+ to assume that every frame will take the same amount of time. Instead,
157
+ you should use the data returned by Clock#tick to see how long the
158
+ frame took. The "Framerate Independence" section below further
159
+ explains why and how to do that.
160
+
161
+
162
+ === How to Enable Framerate Limiting
163
+
164
+ Enabling framerate limiting in Rubygame is easy as pie. Just set
165
+ Clock#target_framerate= to the maximum framerate for your game. So
166
+ if you wanted your game to stay at 20 frames per second, you would do:
167
+
168
+ my_clock = Rubygame::Clock.new
169
+ my_clock.target_framerate = 20 # frames per second
170
+
171
+ There's also another way to set the target framerate:
172
+ Clock#target_frametime=. Instead of setting the number of frames per
173
+ second, this allows you to set the number of milliseconds per frame.
174
+ This has the same effect as setting the framerate, it's just another
175
+ way of expressing it. So, the following is exactly equivalent to the
176
+ earlier example:
177
+
178
+ my_clock = Rubygame::Clock.new
179
+ my_clock.target_frametime = 50 # milliseconds per frame
180
+
181
+ To use framerate limiting, you also need to call Clock#tick once per
182
+ frame, the same way you do for framerate monitoring (you should only
183
+ call it once per frame, even if you're doing both monitoring and
184
+ limiting). When framerate limiting is enabled, the tick method pauses
185
+ the program for a brief time. The length of the pause carefully
186
+ calculated each frame to keep a consistent framerate.
187
+
188
+ However, framerate limiting only set the *maximum* framerate. In other
189
+ words, it can only slow down your game if it's running too fast, not
190
+ make your game run faster. So if your game naturally runs at 25 FPS,
191
+ setting a target framerate of 30 FPS will have no effect.
192
+
193
+ You can change the target framerate/frametime at any time.
194
+ Setting the target back to nil will disable framerate limiting.
195
+
196
+
197
+ === Improving Clock Efficiency
198
+
199
+ In Rubygame 2.5 and later, you can call Clock#calibrate to optimize
200
+ the framerate limiting algorithm for the current computer. This
201
+ minimizes wasted CPU power by setting Clock#granularity to match
202
+ the system clock's granularity. The improvement varies by
203
+ operating system and processor, and will be most noticeable
204
+ on systems with high-precision system clocks.
205
+
206
+ By default, the calibration will take up to a maximum of 0.5 seconds
207
+ to complete. The needed amount of time will likely decrease in future
208
+ versions of Rubygame. If you want to calibrate more quickly (but
209
+ potentially less accurately), you can pass a different maximum time
210
+ as a parameter to Clock#calibrate.
211
+
212
+ You can also set Clock#granularity directly, if you wish. Setting
213
+ Clock#granularity to 0 will use the least CPU possible, but will
214
+ lose accuracy.
215
+
216
+
217
+ === Multithreaded Applications
218
+
219
+ By default, Clock's framerate limiting feature will pause *all* ruby
220
+ threads during the small pause each frame. This is a side effect of
221
+ the SDL function used for the pause. It also affects Clock.delay and
222
+ Clock.wait.
223
+
224
+ Starting in Rubygame 2.5, Clock has a new attribute, Clock#nice.
225
+ If true, Clock will try to give the other threads an opportunity to run
226
+ during the brief pause each frame when performing framerate limiting.
227
+
228
+ If you are calling Clock.delay or Clock.wait directly, you can get the
229
+ same effect by passing true for the +nice+ parameter.
230
+
231
+ *NOTE*: There is no guarantee or specification about how often other
232
+ threads will allowed to run during the delay, or even that they will
233
+ be allowed run during the delay at all. Setting +nice+ to true simply
234
+ tells the Clock to *try* to be nice to other threads, if it can do so
235
+ without losing accuracy.
236
+
237
+
238
+ == Framerate Independence
239
+
240
+ === Why Be Framerate Independent?
241
+
242
+ Some programmers are tempted to use framerate limiting to control the
243
+ speed of the action in their games. In other words, they assume that
244
+ every frame will take the same amount of time on all computers, so
245
+ they define movement speeds and other gameplay rates in "per frame"
246
+ units: move 2 pixel per frame, lose 1% HP per frame when poisoned,
247
+ etc. This is called "framerate dependence", because the speed of the
248
+ gameplay depends on how fast the framerate is.
249
+
250
+ You should *almost always* avoid this programming practice, because
251
+ it's not very robust, it usually makes the game more difficult to
252
+ maintain or change in the future, and can lead to bugs and unwanted
253
+ behavior.
254
+
255
+ For example, if you programmed your game so that the characters move
256
+ 2 pixels per frame, and limited your game's framerate to 30 FPS, the
257
+ character would move 60 pixels in one second. But if you later decided
258
+ to change the framerate to 60 FPS, the character would move 120 pixels
259
+ each second -- twice as fast! You would have to go through your entire
260
+ game and adjust the speed for every character, which is a hassle.
261
+
262
+ Also consider the other end: slow computers. Your game may reliably
263
+ run at 30 FPS on your computer, but an older or slower computer might
264
+ only be able to run at 15 FPS. In that case, all the characters would
265
+ move half as fast, which could make the game a lot less fun. Even worse,
266
+ if more objects started to appear on the screen, the framerate would
267
+ start to drop, and the gameplay would get even slower!
268
+
269
+ The solution to these problems is simple: define your gameplay in
270
+ per-second or per-millisecond units, instead of per-frame units.
271
+ You can then use the frame time to calculate how much the game
272
+ changed in the past frame. This is called "framerate independence".
273
+
274
+
275
+ === Framerate Independence with Rubygame
276
+
277
+ It's very easy to make your game framerate independent with
278
+ Rubygame. So, you have no excuse not to do it, not even laziness!
279
+
280
+ The first step is making sure all your speeds and other gameplay
281
+ rates are defined as per-second or per-millisecond units: move 60
282
+ pixels per second, lose 30% HP per second, etc. The choice to use
283
+ seconds or milliseconds is up to you, and doesn't make a difference as
284
+ long as you use the same time scale everywhere.
285
+
286
+ The second step is to use the value returned by Clock#tick each frame
287
+ to find out how long it has been since the previous frame, and use
288
+ that time to calculate how far the character has moved in the past frame,
289
+ how much HP they have lost, etc. (I will assume for this tutorial that
290
+ you have called Clock#enable_tick_events, so that Clock#tick will return
291
+ a ClockTicked event.)
292
+
293
+ This calculation is very simple: just multiply the number of seconds
294
+ (or milliseconds) by the speed or rate. Remember to use the correct
295
+ units! If your rates are defined in per-second units, multiply by
296
+ ClockTicked#seconds; if they are per-millisecond units, multiply by
297
+ ClockTicked#milliseconds.
298
+
299
+ tick_event = Clock.tick
300
+ movement = speed * tick_event.seconds
301
+
302
+ For a full example of how to apply this concept in code, see
303
+ samples/framerate.rb in the Rubygame source distribution.
Binary file
@@ -0,0 +1,295 @@
1
+ /*
2
+ * Functions for getting the time since initialization and delaying execution
3
+ * for a specified amounts of time.
4
+ *
5
+ * --
6
+ *
7
+ * Rubygame -- Ruby code and bindings to SDL to facilitate game creation
8
+ * Copyright (C) 2004-2009 John Croisant
9
+ *
10
+ * This library is free software; you can redistribute it and/or
11
+ * modify it under the terms of the GNU Lesser General Public
12
+ * License as published by the Free Software Foundation; either
13
+ * version 2.1 of the License, or (at your option) any later version.
14
+ *
15
+ * This library is distributed in the hope that it will be useful,
16
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
+ * Lesser General Public License for more details.
19
+ *
20
+ * You should have received a copy of the GNU Lesser General Public
21
+ * License along with this library; if not, write to the Free Software
22
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
+ *
24
+ * ++
25
+ */
26
+
27
+ #include "rubygame_shared.h"
28
+ #include "rubygame_clock.h"
29
+
30
+ void Rubygame_Init_Clock();
31
+
32
+ VALUE cClock;
33
+
34
+ VALUE rbgm_clock_wait(int, VALUE*, VALUE);
35
+ VALUE rbgm_clock_delay(int, VALUE*, VALUE);
36
+ VALUE rbgm_clock_runtime(VALUE);
37
+
38
+
39
+ /* Initialize the SDL timer system, if it hasn't been already. */
40
+ void rg_init_sdl_timer()
41
+ {
42
+ if(!SDL_WasInit(SDL_INIT_TIMER))
43
+ {
44
+ if(SDL_InitSubSystem(SDL_INIT_TIMER))
45
+ {
46
+ rb_raise(eSDLError,"Could not initialize timer system: %s",\
47
+ SDL_GetError());
48
+ }
49
+ }
50
+ }
51
+
52
+
53
+ /* NOTICE: if you change this value "officially", don't forget to update the
54
+ * documentation for rbgm_time_delay!!
55
+ */
56
+ #define WORST_CLOCK_ACCURACY 12
57
+
58
+
59
+
60
+ /* Delays for the given amount of time, but possibly split into small
61
+ * parts. Control is given to ruby between each part, so that other
62
+ * threads can run.
63
+ *
64
+ * delay: How many milliseconds to delay.
65
+ * nice: If 1 (true), split the delay into smaller parts and allow
66
+ * other ruby threads to run between each part.
67
+ *
68
+ */
69
+ Uint32 rg_threaded_delay( Uint32 delay, int nice )
70
+ {
71
+ Uint32 start;
72
+
73
+ start = SDL_GetTicks();
74
+
75
+ if( nice )
76
+ {
77
+ while( SDL_GetTicks() < start + delay )
78
+ {
79
+ SDL_Delay(1);
80
+ rb_thread_schedule(); /* give control to ruby */
81
+ }
82
+ }
83
+ else
84
+ {
85
+ SDL_Delay( delay );
86
+ }
87
+
88
+ return SDL_GetTicks() - start;
89
+ }
90
+
91
+
92
+ /*
93
+ * call-seq:
94
+ * Clock.wait( time, nice=false ) -> Integer
95
+ *
96
+ * time:: The target wait time, in milliseconds.
97
+ * (Non-negative Integer. Required.)
98
+ * nice:: If true, try to let other ruby threads run during the delay.
99
+ * (true or false. Optional.)
100
+ *
101
+ * Returns:: The actual wait time, in milliseconds.
102
+ *
103
+ * Pause the program for approximately +time+ milliseconds. Both this
104
+ * function and Clock.delay can be used to slow down the framerate so
105
+ * that the application doesn't use too much CPU time. See also
106
+ * Clock#tick for a good and easy way to limit the framerate.
107
+ *
108
+ * The accuracy of this function depends on processor scheduling,
109
+ * which varies with operating system and hardware. The actual delay
110
+ * time may be up to 10ms longer than +time+. If you need more
111
+ * accuracy use Clock.delay, which is more accurate but uses slightly
112
+ * more CPU time.
113
+ *
114
+ * If +nice+ is true, this function will try to allow other ruby
115
+ * threads to run during this function. Otherwise, other ruby threads
116
+ * will probably also be paused. Setting +nice+ to true is only
117
+ * useful if your application is multithreaded. It's safe (but
118
+ * pointless) to use this feature for single threaded applications.
119
+ *
120
+ * The Rubygame timer system will be initialized when you call this
121
+ * function, if it has not been already. See Clock.runtime.
122
+ *
123
+ */
124
+ VALUE rbgm_clock_wait(int argc, VALUE *argv, VALUE module)
125
+ {
126
+ rg_init_sdl_timer();
127
+
128
+ VALUE vtime, vnice;
129
+
130
+ rb_scan_args(argc,argv,"11", &vtime, &vnice);
131
+
132
+ int delay = NUM2INT(vtime);
133
+ if( delay < 0 )
134
+ {
135
+ delay = 0;
136
+ }
137
+
138
+ int nice = (vnice == Qtrue) ? 1 : 0;
139
+
140
+ return UINT2NUM( rg_threaded_delay(delay, nice) );
141
+ }
142
+
143
+
144
+
145
+ /*--
146
+ * From pygame code, with a few modifications:
147
+ * - takes 'accuracy' argument
148
+ * - ruby syntax for raising exceptions
149
+ * - uses rg_threaded_delay
150
+ *++
151
+ */
152
+ static Uint32 accurate_delay(Uint32 ticks, Uint32 accuracy, int nice)
153
+ {
154
+ Uint32 funcstart;
155
+ int delay;
156
+
157
+ if( accuracy <= 0 )
158
+ {
159
+ /* delay with no accuracy is like wait (no busy waiting) */
160
+ return rg_threaded_delay(ticks, nice);
161
+ }
162
+
163
+ funcstart = SDL_GetTicks();
164
+
165
+ if(ticks >= accuracy)
166
+ {
167
+ delay = (ticks - 2) - (ticks % accuracy);
168
+ if(delay >= accuracy)
169
+ {
170
+ rg_threaded_delay(delay, nice);
171
+ }
172
+ }
173
+
174
+ do{
175
+ delay = ticks - (SDL_GetTicks() - funcstart);
176
+ rb_thread_schedule(); /* give control to ruby */
177
+ }while(delay > 0);
178
+
179
+ return SDL_GetTicks() - funcstart;
180
+ }
181
+
182
+
183
+
184
+ /*
185
+ * call-seq:
186
+ * Clock.delay( time, gran=12, nice=false ) -> Integer
187
+ *
188
+ * time:: The target delay time, in milliseconds.
189
+ * (Non-negative integer. Required.)
190
+ * gran:: The assumed granularity (in ms) of the system clock.
191
+ * (Non-negative integer. Optional. Default: 12.)
192
+ * nice:: If true, try to let other ruby threads run during the delay.
193
+ * (true or false. Optional. Default: false.)
194
+ *
195
+ * Returns:: The actual delay time, in milliseconds.
196
+ *
197
+ * Pause the program for +time+ milliseconds. This function is more
198
+ * accurate than Clock.wait, but uses slightly more CPU time. Both
199
+ * this function and Clock.wait can be used to slow down the
200
+ * framerate so that the application doesn't use too much CPU time.
201
+ * See also Clock#tick for a good and easy way to limit the
202
+ * framerate.
203
+ *
204
+ * This function uses "busy waiting" during the last part
205
+ * of the delay, for increased accuracy. The value of +gran+ affects
206
+ * how many milliseconds of the delay are spent in busy waiting, and thus
207
+ * how much CPU it uses. A smaller +gran+ value uses less CPU, but if
208
+ * it's smaller than the true system granularity, this function may
209
+ * delay a few milliseconds too long. The default value (12ms) is very
210
+ * safe, but a value of approximately 5ms would give a better balance
211
+ * between accuracy and CPU usage on most modern computers.
212
+ * A granularity of 0ms makes this method act the same as Clock.wait
213
+ * (i.e. no busy waiting at all, very low CPU usage).
214
+ *
215
+ * If +nice+ is true, this function will try to allow other ruby
216
+ * threads to run during this function. Otherwise, other ruby threads
217
+ * will probably also be paused. Setting +nice+ to true is only
218
+ * useful if your application is multithreaded. It's safe (but
219
+ * pointless) to use this feature for single threaded applications.
220
+ *
221
+ * The Rubygame timer system will be initialized when you call this
222
+ * function, if it has not been already. See Clock.runtime.
223
+ *
224
+ */
225
+ VALUE rbgm_clock_delay(int argc, VALUE *argv, VALUE module)
226
+ {
227
+ rg_init_sdl_timer();
228
+
229
+ VALUE vtime, vgran, vnice;
230
+
231
+ rb_scan_args(argc,argv,"12", &vtime, &vgran, &vnice);
232
+
233
+ int delay = NUM2INT(vtime);
234
+ if( delay < 0 )
235
+ {
236
+ delay = 0;
237
+ }
238
+
239
+ int gran;
240
+ if( RTEST(vgran) )
241
+ {
242
+ gran = NUM2UINT(vgran);
243
+ if( gran < 0 )
244
+ {
245
+ gran = 0;
246
+ }
247
+ }
248
+ else
249
+ {
250
+ gran = WORST_CLOCK_ACCURACY;
251
+ }
252
+
253
+ int nice = (vnice == Qtrue) ? 1 : 0;
254
+
255
+ return UINT2NUM( accurate_delay(delay, gran, nice) );
256
+ }
257
+
258
+
259
+
260
+ /*
261
+ * call-seq:
262
+ * runtime -> Integer
263
+ *
264
+ * Return the number of milliseconds since the Rubygame timer system
265
+ * was initialized.
266
+ *
267
+ * The Rubygame timer system will be initialized when you call this function,
268
+ * if it has not been already.
269
+ */
270
+ VALUE rbgm_clock_runtime( VALUE module )
271
+ {
272
+ rg_init_sdl_timer();
273
+
274
+ return UINT2NUM(SDL_GetTicks());
275
+ }
276
+
277
+
278
+
279
+ void Rubygame_Init_Clock()
280
+ {
281
+ #if 0
282
+ mRubygame = rb_define_module("Rubygame");
283
+ #endif
284
+
285
+ /* Clock class */
286
+ cClock = rb_define_class_under(mRubygame, "Clock", rb_cObject);
287
+
288
+ /* Clock class methods */
289
+ rb_define_singleton_method(cClock, "wait", rbgm_clock_wait, -1);
290
+ rb_define_singleton_method(cClock, "delay", rbgm_clock_delay, -1);
291
+ rb_define_singleton_method(cClock, "runtime",rbgm_clock_runtime, 0);
292
+
293
+ /* Clock instance methods are defined in clock.rb. */
294
+
295
+ }