rubygame 2.4.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }