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 +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
|