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 +98 -0
- data/ROADMAP +0 -13
- data/Rakefile +2 -2
- data/doc/managing_framerate.rdoc +303 -0
- data/ext/body/rubygame_body.so +0 -0
- data/ext/rubygame/rubygame_clock.c +295 -0
- data/ext/rubygame/{rubygame_time.h → rubygame_clock.h} +7 -7
- data/ext/rubygame/rubygame_main.c +2 -2
- data/ext/rubygame/rubygame_screen.c +137 -13
- data/ext/rubygame/rubygame_screen.h +2 -0
- data/lib/rubygame.rb +5 -1
- data/lib/rubygame/clock.rb +291 -109
- data/lib/rubygame/event_handler.rb +22 -3
- data/lib/rubygame/event_hook.rb +10 -10
- data/lib/rubygame/event_triggers.rb +14 -6
- data/lib/rubygame/events/clock_events.rb +58 -0
- data/lib/rubygame/ftor.rb +13 -0
- data/lib/rubygame/mediabag.rb +10 -0
- data/lib/rubygame/shared.rb +36 -0
- data/samples/chimp.rb +3 -2
- data/samples/demo_gl.rb +2 -2
- data/samples/demo_gl_tex.rb +3 -1
- data/samples/demo_rubygame.rb +24 -27
- data/samples/framerate.rb +120 -0
- metadata +11 -4
- data/ext/rubygame/rubygame_time.c +0 -183
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
2
|
* Rubygame -- Ruby code and bindings to SDL to facilitate game creation
|
3
|
-
* Copyright (C) 2004-
|
3
|
+
* Copyright (C) 2004-2009 John Croisant
|
4
4
|
*
|
5
5
|
* This library is free software; you can redistribute it and/or
|
6
6
|
* modify it under the terms of the GNU Lesser General Public
|
@@ -18,15 +18,15 @@
|
|
18
18
|
*
|
19
19
|
*/
|
20
20
|
|
21
|
-
#ifndef
|
22
|
-
#define
|
21
|
+
#ifndef _RUBYGAME_CLOCK_H
|
22
|
+
#define _RUBYGAME_CLOCK_H
|
23
23
|
|
24
|
-
extern void
|
24
|
+
extern void Rubygame_Init_Clock();
|
25
25
|
|
26
26
|
extern VALUE cClock;
|
27
27
|
|
28
|
-
extern VALUE
|
29
|
-
extern VALUE
|
30
|
-
extern VALUE
|
28
|
+
extern VALUE rbgm_clock_wait(int, VALUE*, VALUE);
|
29
|
+
extern VALUE rbgm_clock_delay(int, VALUE*, VALUE);
|
30
|
+
extern VALUE rbgm_clock_runtime(VALUE);
|
31
31
|
|
32
32
|
#endif
|
@@ -27,7 +27,7 @@
|
|
27
27
|
#include "rubygame_joystick.h"
|
28
28
|
#include "rubygame_screen.h"
|
29
29
|
#include "rubygame_surface.h"
|
30
|
-
#include "
|
30
|
+
#include "rubygame_clock.h"
|
31
31
|
|
32
32
|
VALUE rbgm_init(VALUE);
|
33
33
|
VALUE rbgm_quit(VALUE);
|
@@ -127,7 +127,7 @@ void Init_rubygame_core()
|
|
127
127
|
INT2NUM(SDL_MINOR_VERSION),
|
128
128
|
INT2NUM(SDL_PATCHLEVEL)));
|
129
129
|
|
130
|
-
|
130
|
+
Rubygame_Init_Clock();
|
131
131
|
Rubygame_Init_Surface();
|
132
132
|
Rubygame_Init_Screen();
|
133
133
|
Rubygame_Init_Event();
|
@@ -32,6 +32,8 @@ VALUE cScreen;
|
|
32
32
|
VALUE rbgm_screen_setmode(int, VALUE*, VALUE);
|
33
33
|
VALUE rbgm_screen_getsurface(VALUE);
|
34
34
|
|
35
|
+
VALUE rbgm_screen_getresolution(VALUE);
|
36
|
+
|
35
37
|
VALUE rbgm_screen_getcaption(VALUE);
|
36
38
|
VALUE rbgm_screen_setcaption(VALUE, VALUE);
|
37
39
|
|
@@ -46,8 +48,8 @@ VALUE rbgm_screen_setshowcursor(VALUE, VALUE);
|
|
46
48
|
|
47
49
|
|
48
50
|
/* call-seq:
|
49
|
-
* new(size, depth=0, flags=[SWSURFACE]) -> Screen
|
50
|
-
* (
|
51
|
+
* Screen.new( size, depth=0, flags=[SWSURFACE] ) -> Screen
|
52
|
+
* (alias: open)
|
51
53
|
*
|
52
54
|
* Create a new Rubygame window if there is none, or modify the existing one.
|
53
55
|
* You cannot create more than one Screen; the existing one will be replaced.
|
@@ -94,13 +96,13 @@ VALUE rbgm_screen_setshowcursor(VALUE, VALUE);
|
|
94
96
|
* OpenGL functions.
|
95
97
|
* RESIZABLE:: Create a resizable window. When the window is
|
96
98
|
* resized by the user, a ResizeEvent is
|
97
|
-
* generated and
|
99
|
+
* generated and this method can be called again
|
98
100
|
* with the new size.
|
99
101
|
* NOFRAME:: If possible, create a window with no title bar or
|
100
102
|
* frame decoration.
|
101
103
|
* Fullscreen modes automatically have this flag set.
|
102
104
|
*/
|
103
|
-
VALUE
|
105
|
+
VALUE rbgm_screen_new(int argc, VALUE *argv, VALUE module)
|
104
106
|
{
|
105
107
|
SDL_Surface *screen;
|
106
108
|
int w, h, depth;
|
@@ -133,8 +135,73 @@ VALUE rbgm_screen_setmode(int argc, VALUE *argv, VALUE module)
|
|
133
135
|
return Data_Wrap_Struct( cScreen,0,0,screen );
|
134
136
|
}
|
135
137
|
|
138
|
+
|
139
|
+
/* call-seq:
|
140
|
+
* Screen.set_mode( size, depth=0, flags=[SWSURFACE] ) -> Screen
|
141
|
+
*
|
142
|
+
* Deprecated alias for Screen.new. This method will be REMOVED
|
143
|
+
* in Rubygame 3.0. You should use Screen.new (or its alias, Screen.open)
|
144
|
+
* instead.
|
145
|
+
*/
|
146
|
+
VALUE rbgm_screen_setmode(int argc, VALUE *argv, VALUE module)
|
147
|
+
{
|
148
|
+
rg_deprecated("Rubygame::Screen.set_mode", "3.0");
|
149
|
+
return rbgm_screen_new(argc, argv, module);
|
150
|
+
}
|
151
|
+
|
152
|
+
/* call-seq:
|
153
|
+
* Screen.instance( size, depth=0, flags=[SWSURFACE] ) -> Screen
|
154
|
+
*
|
155
|
+
* Deprecated alias for Screen.new. This method will be REMOVED
|
156
|
+
* in Rubygame 3.0. You should use Screen.new (or its alias, Screen.open)
|
157
|
+
* instead.
|
158
|
+
*/
|
159
|
+
VALUE rbgm_screen_instance(int argc, VALUE *argv, VALUE module)
|
160
|
+
{
|
161
|
+
rg_deprecated("Rubygame::Screen.instance", "3.0");
|
162
|
+
return rbgm_screen_new(argc, argv, module);
|
163
|
+
}
|
164
|
+
|
165
|
+
|
166
|
+
/*
|
167
|
+
* call-seq:
|
168
|
+
* Screen.close
|
169
|
+
*
|
170
|
+
* Close the Screen, making the Rubygame window disappear.
|
171
|
+
* This method also exits from fullscreen mode, if needed.
|
172
|
+
*
|
173
|
+
* After calling this method, you should discard any references
|
174
|
+
* to the old Screen surface, as it is no longer valid, even
|
175
|
+
* if you call Screen.new again.
|
176
|
+
*
|
177
|
+
* (Note: You do not need to close the Screen to change its size
|
178
|
+
* or flags, you can simply call Screen.new while already open.)
|
179
|
+
*
|
180
|
+
*/
|
181
|
+
VALUE rbgm_screen_close(VALUE module)
|
182
|
+
{
|
183
|
+
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
184
|
+
return Qnil;
|
185
|
+
}
|
186
|
+
|
187
|
+
|
188
|
+
/*
|
189
|
+
* call-seq:
|
190
|
+
* Screen.open?
|
191
|
+
*
|
192
|
+
* True if there is an open Rubygame window.
|
193
|
+
* See Screen.new and Screen.close.
|
194
|
+
*
|
195
|
+
*/
|
196
|
+
VALUE rbgm_screen_openp(VALUE module)
|
197
|
+
{
|
198
|
+
return (SDL_GetVideoSurface() == NULL) ? Qfalse : Qtrue;
|
199
|
+
}
|
200
|
+
|
201
|
+
|
202
|
+
|
136
203
|
/* call-seq:
|
137
|
-
* get_surface
|
204
|
+
* Screen.get_surface
|
138
205
|
*
|
139
206
|
* Returns the current display window, or raises SDLError if it
|
140
207
|
* fails to get it (for example, if it doesn't exist yet).
|
@@ -150,7 +217,55 @@ VALUE rbgm_screen_getsurface(VALUE module)
|
|
150
217
|
return Data_Wrap_Struct( cScreen,0,0,surface );
|
151
218
|
}
|
152
219
|
|
153
|
-
|
220
|
+
|
221
|
+
/* call-seq:
|
222
|
+
* Screen.get_resolution -> [width, height]
|
223
|
+
*
|
224
|
+
* Returns the pixel dimensions of the user's display (i.e. monitor).
|
225
|
+
* (That is not the same as Screen#size, which only measures the
|
226
|
+
* Rubygame window.) You can use this information to detect
|
227
|
+
* how large of a Screen can fit on the user's display.
|
228
|
+
*
|
229
|
+
* This method can _only_ be used when there is no open Screen instance.
|
230
|
+
* This method raises SDLError if there is a Screen instance (i.e.
|
231
|
+
* you have done Screen.new before). This is a limitation of the SDL
|
232
|
+
* function SDL_GetVideoInfo, which behaves differently when a Screen
|
233
|
+
* is open than when it is closed.
|
234
|
+
*
|
235
|
+
* This method will also raise SDLError if it cannot get the display
|
236
|
+
* size for some other reason.
|
237
|
+
*
|
238
|
+
*/
|
239
|
+
VALUE rbgm_screen_getresolution(VALUE module)
|
240
|
+
{
|
241
|
+
VALUE array;
|
242
|
+
const SDL_VideoInfo* hw;
|
243
|
+
init_video_system();
|
244
|
+
|
245
|
+
/* Test for existing Screen */
|
246
|
+
SDL_Surface *surface;
|
247
|
+
surface = SDL_GetVideoSurface();
|
248
|
+
if(surface != NULL)
|
249
|
+
{
|
250
|
+
rb_raise(eSDLError, "You cannot get resolution when there is " \
|
251
|
+
"an open Screen. See the docs for the reason.");
|
252
|
+
}
|
253
|
+
|
254
|
+
hw = SDL_GetVideoInfo();
|
255
|
+
if(hw==NULL)
|
256
|
+
{
|
257
|
+
rb_raise(eSDLError,"Couldn't get video info: %s",SDL_GetError());
|
258
|
+
}
|
259
|
+
|
260
|
+
array = rb_ary_new();
|
261
|
+
rb_ary_push(array, INT2NUM(hw->current_w));
|
262
|
+
rb_ary_push(array, INT2NUM(hw->current_h));
|
263
|
+
return array;
|
264
|
+
}
|
265
|
+
|
266
|
+
|
267
|
+
/* Screen instance methods: */
|
268
|
+
|
154
269
|
|
155
270
|
/* call-seq:
|
156
271
|
* title -> String
|
@@ -224,7 +339,7 @@ VALUE rbgm_screen_seticon(VALUE self, VALUE data)
|
|
224
339
|
*
|
225
340
|
* Updates (refreshes) all or part of the Rubygame window, revealing to the
|
226
341
|
* user any changes that have been made since the last update. If you're using
|
227
|
-
* a double-buffered display (see
|
342
|
+
* a double-buffered display (see Screen.new), you should use
|
228
343
|
* Screen#flip instead.
|
229
344
|
*
|
230
345
|
* This method takes these arguments:
|
@@ -347,7 +462,7 @@ VALUE rbgm_screen_updaterects(VALUE self, VALUE array_rects)
|
|
347
462
|
/* call-seq:
|
348
463
|
* flip()
|
349
464
|
*
|
350
|
-
* If the Rubygame display is double-buffered (see
|
465
|
+
* If the Rubygame display is double-buffered (see Screen.new), flips
|
351
466
|
* the buffers and updates the whole screen. Otherwise, just updates the
|
352
467
|
* whole screen.
|
353
468
|
*/
|
@@ -402,8 +517,8 @@ VALUE rbgm_screen_setshowcursor(VALUE self, VALUE val)
|
|
402
517
|
* Surface#set_colorkey and Surface#set_alpha are not inherited.
|
403
518
|
*
|
404
519
|
* Please note that only *one* Screen can exist, per application, at a time;
|
405
|
-
* this is a limitation of SDL. You *must* use Screen.
|
406
|
-
* Screen or modify
|
520
|
+
* this is a limitation of SDL. You *must* use Screen.new (or its alias,
|
521
|
+
* Screen.open) to create or modify the Screen.
|
407
522
|
*
|
408
523
|
* Also note that no changes to the Screen will be seen until it is refreshed.
|
409
524
|
* See #update, #update_rects, and #flip for ways to refresh all or part of
|
@@ -419,10 +534,19 @@ void Rubygame_Init_Screen()
|
|
419
534
|
|
420
535
|
/* Screen class */
|
421
536
|
cScreen = rb_define_class_under(mRubygame,"Screen",cSurface);
|
422
|
-
rb_define_singleton_method(cScreen,"new",
|
423
|
-
rb_define_alias(rb_singleton_class(cScreen),"
|
424
|
-
|
537
|
+
rb_define_singleton_method(cScreen,"new",rbgm_screen_new, -1);
|
538
|
+
rb_define_alias(rb_singleton_class(cScreen),"open","new");
|
539
|
+
|
540
|
+
rb_define_singleton_method(cScreen,"close", rbgm_screen_close, 0);
|
541
|
+
rb_define_singleton_method(cScreen,"open?", rbgm_screen_openp, 0);
|
425
542
|
rb_define_singleton_method(cScreen,"get_surface",rbgm_screen_getsurface, 0);
|
543
|
+
rb_define_singleton_method(cScreen,"get_resolution",rbgm_screen_getresolution, 0);
|
544
|
+
|
545
|
+
/* Deprecated: */
|
546
|
+
rb_define_singleton_method(cScreen,"set_mode", rbgm_screen_setmode, -1);
|
547
|
+
rb_define_singleton_method(cScreen,"instance", rbgm_screen_instance, -1);
|
548
|
+
|
549
|
+
|
426
550
|
|
427
551
|
/* These are inherited from Surface, but should not be called on Screen */
|
428
552
|
rb_undef_method(cScreen,"set_alpha");
|
@@ -28,6 +28,8 @@ extern VALUE cScreen;
|
|
28
28
|
extern VALUE rbgm_screen_setmode(int, VALUE*, VALUE);
|
29
29
|
extern VALUE rbgm_screen_getsurface(VALUE);
|
30
30
|
|
31
|
+
extern VALUE rbgm_screen_getresolution(VALUE);
|
32
|
+
|
31
33
|
extern VALUE rbgm_screen_getcaption(VALUE);
|
32
34
|
extern VALUE rbgm_screen_setcaption(VALUE, VALUE);
|
33
35
|
|
data/lib/rubygame.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#--
|
2
|
+
#
|
2
3
|
# Rubygame -- Ruby code and bindings to SDL to facilitate game creation
|
3
|
-
# Copyright (C) 2004-
|
4
|
+
# Copyright (C) 2004-2009 John Croisant
|
4
5
|
#
|
5
6
|
# This library is free software; you can redistribute it and/or
|
6
7
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -15,6 +16,7 @@
|
|
15
16
|
# You should have received a copy of the GNU Lesser General Public
|
16
17
|
# License along with this library; if not, write to the Free Software
|
17
18
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#
|
18
20
|
#++
|
19
21
|
|
20
22
|
# This file is loaded when you "require 'rubygame'".
|
@@ -39,6 +41,8 @@ require "rubygame_core"
|
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
44
|
+
require "rubygame/shared"
|
45
|
+
|
42
46
|
require "rubygame/color"
|
43
47
|
require "rubygame/constants"
|
44
48
|
|
data/lib/rubygame/clock.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#--
|
2
|
+
#
|
2
3
|
# Rubygame -- Ruby code and bindings to SDL to facilitate game creation
|
3
|
-
# Copyright (C) 2004-
|
4
|
+
# Copyright (C) 2004-2009 John Croisant
|
4
5
|
#
|
5
6
|
# This library is free software; you can redistribute it and/or
|
6
7
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -15,114 +16,295 @@
|
|
15
16
|
# You should have received a copy of the GNU Lesser General Public
|
16
17
|
# License along with this library; if not, write to the Free Software
|
17
18
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#
|
18
20
|
#++
|
19
21
|
|
22
|
+
|
23
|
+
require "rubygame/events/clock_events"
|
24
|
+
|
25
|
+
|
20
26
|
module Rubygame
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
27
|
+
|
28
|
+
|
29
|
+
# Clock provides class methods for tracking running time and delaying
|
30
|
+
# execution of the program for specified time periods. This is used to
|
31
|
+
# provide a consistent framerate, prevent the program from using
|
32
|
+
# all the processor time, etc.
|
33
|
+
#
|
34
|
+
# Clock also provides instance methods to make it convenient to
|
35
|
+
# monitor and limit application framerate. See #tick.
|
36
|
+
#
|
37
|
+
# An in-depth tutorial on using Clock is available. See
|
38
|
+
# doc/managing_framerate.rdoc[link:files/doc/managing_framerate_rdoc.html]
|
39
|
+
# in the Rubygame source distribution or in the online
|
40
|
+
# documentation.
|
41
|
+
#
|
42
|
+
class Clock
|
43
|
+
|
44
|
+
# The runtime when the Clock was initialized.
|
45
|
+
attr_reader :start
|
46
|
+
|
47
|
+
# The number of times #tick has been called.
|
48
|
+
attr_reader :ticks
|
49
|
+
|
50
|
+
|
51
|
+
# Granularity used for framerate limiting delays in #tick.
|
52
|
+
# You can calibrate this easily with #calibrate.
|
53
|
+
# See also #tick and Clock.delay.
|
54
|
+
# (Non-negative integer. Default: 12.)
|
55
|
+
attr_accessor :granularity
|
56
|
+
|
57
|
+
# Whether to try to let other ruby threads run during framerate
|
58
|
+
# limiting delays in #tick. See #tick and Clock.delay.
|
59
|
+
# (true or false. Default: false.)
|
60
|
+
attr_accessor :nice
|
61
|
+
|
62
|
+
|
63
|
+
# Create a new Clock instance.
|
64
|
+
def initialize()
|
65
|
+
@start = self.class.runtime()
|
66
|
+
@last_tick = nil
|
67
|
+
@ticks = 0
|
68
|
+
|
69
|
+
@target_frametime = nil
|
70
|
+
|
71
|
+
# Frametime samples for framerate calculation
|
72
|
+
@samples = []
|
73
|
+
@max_samples = 20
|
74
|
+
|
75
|
+
@granularity = 12
|
76
|
+
@nice = false
|
77
|
+
|
78
|
+
# Should #tick return a ClockTicked event?
|
79
|
+
@tick_events = false
|
80
|
+
|
81
|
+
# Cache for past tick events with specific ms values
|
82
|
+
@tick_cache = {}
|
83
|
+
|
84
|
+
yield self if block_given?
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
# Calibrate some Clock settings to match the current computer.
|
89
|
+
# This improves efficiency and minimizes CPU usage without
|
90
|
+
# reducing accuracy.
|
91
|
+
#
|
92
|
+
# As of Rubygame 2.5, this method calibrates @granularity. See
|
93
|
+
# #tick and Clock.delay for more information about the effect of
|
94
|
+
# setting granularity. In future versions of Rubygame, this
|
95
|
+
# method may also calibrate additional Clock attributes.
|
96
|
+
#
|
97
|
+
# By default, the calibration takes a maximum of 0.5 seconds to
|
98
|
+
# complete. You can specify a different maximum length by passing
|
99
|
+
# a different value for +max_time+. In future versions of
|
100
|
+
# Rubygame, calibration may take less than max_time, but will
|
101
|
+
# not take more. Also, the default max_time may be lowered in
|
102
|
+
# future versions, but will not be raised.
|
103
|
+
#
|
104
|
+
# You usually only need to call this once, after you create the
|
105
|
+
# Clock instance at the start of your application. You should not
|
106
|
+
# run any other ruby threads at the same time, as doing so will
|
107
|
+
# skew the calibration.
|
108
|
+
#
|
109
|
+
#--
|
110
|
+
#
|
111
|
+
# I'm not 100% sure that this is a valid way to measure
|
112
|
+
# granularity, or that the granularity of ruby sleep is
|
113
|
+
# always the same as that of SDL_Delay. But it can be
|
114
|
+
# improved later if needed...
|
115
|
+
#
|
116
|
+
#++
|
117
|
+
def calibrate( max_time = 0.5 )
|
118
|
+
samples = []
|
119
|
+
|
120
|
+
end_time = Time.now + max_time
|
121
|
+
|
122
|
+
while( Time.now < end_time )
|
123
|
+
t = Time.now
|
124
|
+
sleep 0.01
|
125
|
+
samples << (Time.now - t - 0.01)
|
126
|
+
end
|
127
|
+
|
128
|
+
average = samples.inject{|sum,n| sum + n} / samples.length
|
129
|
+
|
130
|
+
# convert to ms, add some padding
|
131
|
+
gran = (average * 1000).to_i + 1
|
132
|
+
|
133
|
+
@granularity = gran
|
134
|
+
|
135
|
+
return nil
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
# Enable tick events, so that #tick will return a ClockTicked
|
140
|
+
# instance instead of a number of milliseconds.
|
141
|
+
#
|
142
|
+
# This option is available starting in Rubygame 2.5, and will
|
143
|
+
# become the default in Rubygame 3.0.
|
144
|
+
#
|
145
|
+
def enable_tick_events
|
146
|
+
@tick_events = true
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Returns the current target frametime (milliseconds/frame),
|
151
|
+
# or nil if there is no target.
|
152
|
+
#
|
153
|
+
# This is another way to access #target_framerate.
|
154
|
+
# Same as: 1000.0 / #target_framerate
|
155
|
+
#
|
156
|
+
def target_frametime
|
157
|
+
@target_frametime
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# Sets the target milliseconds per frame to +frametime+.
|
162
|
+
# If +frametime+ is nil, the target is unset, and #tick
|
163
|
+
# will no longer apply any delay.
|
164
|
+
#
|
165
|
+
# This is another way to access #target_framerate.
|
166
|
+
# Same as: #target_framerate = 1000.0 / frametime
|
167
|
+
#
|
168
|
+
def target_frametime=( frametime )
|
169
|
+
@target_frametime = frametime
|
170
|
+
end
|
171
|
+
|
172
|
+
|
173
|
+
# Returns the current target framerate (frames/second),
|
174
|
+
# or nil if there is no target.
|
175
|
+
#
|
176
|
+
# This is another to access #target_frametime.
|
177
|
+
# Same as: 1000.0 / #target_frametime
|
178
|
+
#
|
179
|
+
def target_framerate
|
180
|
+
if @target_frametime
|
181
|
+
1000.0 / @target_frametime
|
182
|
+
else
|
183
|
+
nil
|
184
|
+
end
|
185
|
+
rescue ZeroDivisionError
|
186
|
+
return nil
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
# Sets the target number of frames per second to +framerate+.
|
191
|
+
# If +framerate+ is nil, the target is unset, and #tick
|
192
|
+
# will no longer apply any delay.
|
193
|
+
#
|
194
|
+
# This is another way to access #target_frametime.
|
195
|
+
# Same as: #target_frametime = 1000.0 / framerate
|
196
|
+
#
|
197
|
+
def target_framerate=( framerate )
|
198
|
+
if framerate
|
199
|
+
@target_frametime = 1000.0 / framerate
|
200
|
+
else
|
201
|
+
@target_frametime = nil
|
202
|
+
end
|
203
|
+
rescue ZeroDivisionError
|
204
|
+
@target_frametime = nil
|
205
|
+
end
|
206
|
+
|
207
|
+
|
208
|
+
# call-seq:
|
209
|
+
# lifetime -> Integer
|
210
|
+
#
|
211
|
+
# Returns time in milliseconds since this Clock instance was created.
|
212
|
+
#
|
213
|
+
def lifetime
|
214
|
+
self.class.runtime() - @start
|
215
|
+
end
|
216
|
+
|
217
|
+
|
218
|
+
# call-seq:
|
219
|
+
# framerate -> Float
|
220
|
+
#
|
221
|
+
# Return the actual framerate (frames per second) recorded by the
|
222
|
+
# Clock. See #tick.
|
223
|
+
#
|
224
|
+
def framerate
|
225
|
+
1000.0 * @samples.length / @samples.inject(0){|sum, n| sum + n}
|
226
|
+
rescue ZeroDivisionError
|
227
|
+
0.0
|
228
|
+
end
|
229
|
+
|
230
|
+
|
231
|
+
# call-seq:
|
232
|
+
# frametime -> Float
|
233
|
+
#
|
234
|
+
# Return the actual frametime (milliseconds per frame) recorded by
|
235
|
+
# the Clock. See #tick.
|
236
|
+
#
|
237
|
+
def frametime
|
238
|
+
@samples.inject(0){|sum, n| sum + n} / (@samples.length)
|
239
|
+
rescue ZeroDivisionError
|
240
|
+
0.0
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
# Returns the number of milliseconds since you last called this
|
245
|
+
# method. Or, if you have called #enable_tick_events, this returns
|
246
|
+
# a ClockTicked event representing the time since you last called
|
247
|
+
# this method. (ClockTicked was added in Rubygame 2.5, and will
|
248
|
+
# become the default and only option in Rubygame 3.0.)
|
249
|
+
#
|
250
|
+
# You must call this method once per frame (i.e. per iteration
|
251
|
+
# of your main loop) if you want to use the framerate monitoring
|
252
|
+
# and/or framerate limiting features.
|
253
|
+
#
|
254
|
+
# Framerate monitoring allows you to check the #framerate (frames
|
255
|
+
# per second) or #frametime (milliseconds per frame) of your game.
|
256
|
+
#
|
257
|
+
# Framerate limiting allows you to prevent the application from
|
258
|
+
# running too fast (and using 100% of processor time) by pausing
|
259
|
+
# the program very briefly each frame. The pause duration is
|
260
|
+
# calculated each frame to maintain a stable framerate.
|
261
|
+
#
|
262
|
+
# Framerate limiting is only enabled if you have set the
|
263
|
+
# #target_framerate= or #target_frametime=. If you have done that,
|
264
|
+
# this method will automatically perform the delay each time you
|
265
|
+
# call it.
|
266
|
+
#
|
267
|
+
# There are two other attributes which affect framerate limiting,
|
268
|
+
# #granularity and #nice. These are passed as parameters to
|
269
|
+
# Clock.delay for the brief pause each frame. See Clock.delay for
|
270
|
+
# the effects of those parameters on CPU usage and threading.
|
271
|
+
#
|
272
|
+
# (Please note that no effort is made to correct a framerate which
|
273
|
+
# is *slower* than the target framerate. Clock can't make your
|
274
|
+
# code run faster, only slow it down if it is running too fast.)
|
275
|
+
#
|
276
|
+
def tick()
|
277
|
+
|
278
|
+
# how long since the last tick?
|
279
|
+
passed = 0
|
280
|
+
if @last_tick
|
281
|
+
passed += self.class.runtime() - @last_tick
|
282
|
+
end
|
283
|
+
|
284
|
+
if @target_frametime
|
285
|
+
extra = @target_frametime - passed
|
286
|
+
if( extra > 0 )
|
287
|
+
passed += self.class.delay( extra, @granularity, @nice )
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
if @tick_events
|
292
|
+
return (@tick_cache[passed] or
|
293
|
+
(@tick_cache[passed] =
|
294
|
+
Rubygame::Events::ClockTicked.new( passed ) ))
|
295
|
+
else
|
296
|
+
return passed
|
297
|
+
end
|
298
|
+
|
299
|
+
ensure
|
300
|
+
@last_tick = self.class.runtime()
|
301
|
+
@ticks += 1
|
302
|
+
|
303
|
+
# Save the frametime for framerate calculation
|
304
|
+
@samples.push(passed)
|
305
|
+
@samples.shift if @samples.length > @max_samples
|
306
|
+
end
|
307
|
+
|
308
|
+
end
|
309
|
+
|
310
|
+
end
|