rubygame 2.4.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * Rubygame -- Ruby code and bindings to SDL to facilitate game creation
3
- * Copyright (C) 2004-2007 John Croisant
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 _RUBYGAME_TIME_H
22
- #define _RUBYGAME_TIME_H
21
+ #ifndef _RUBYGAME_CLOCK_H
22
+ #define _RUBYGAME_CLOCK_H
23
23
 
24
- extern void Rubygame_Init_Time();
24
+ extern void Rubygame_Init_Clock();
25
25
 
26
26
  extern VALUE cClock;
27
27
 
28
- extern VALUE rbgm_time_wait(VALUE, VALUE);
29
- extern VALUE rbgm_time_delay(int, VALUE*, VALUE);
30
- extern VALUE rbgm_time_getticks(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 "rubygame_time.h"
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
- Rubygame_Init_Time();
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
- * (aliases: set_mode, instance)
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 #set_mode can be called again
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 rbgm_screen_setmode(int argc, VALUE *argv, VALUE module)
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
- /* Screen methods: */
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 Display.set_mode), you should use
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 #set_mode), flips
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.set_mode to create the
406
- * Screen or modify its properties.
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",rbgm_screen_setmode, -1);
423
- rb_define_alias(rb_singleton_class(cScreen),"set_mode","new");
424
- rb_define_alias(rb_singleton_class(cScreen),"instance","new");
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-2007, 2008 John Croisant
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
 
@@ -1,6 +1,7 @@
1
1
  #--
2
+ #
2
3
  # Rubygame -- Ruby code and bindings to SDL to facilitate game creation
3
- # Copyright (C) 2004-2007 John Croisant
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
- # Clock provides class methods for tracking running time and delaying
22
- # execution of the program for specified time periods. This is used to
23
- # provide a consistent framerate, prevent the program from using
24
- # all the processor time, etc.
25
- #
26
- # Clock also provides instance methods to make it convenient to
27
- # monitor and limit application framerate. See #tick.
28
- class Clock
29
- # The runtime when the Clock was initialized.
30
- attr_reader :start
31
- # The number of times #tick has been called.
32
- attr_reader :ticks
33
-
34
- # Create a new Clock instance.
35
- def initialize()
36
- @start = Clock.runtime()
37
- @last_tick = @start
38
- @ticks = 0
39
- @target_frametime = nil
40
- yield self if block_given?
41
- end
42
-
43
- # The target frametime (milliseconds/frame). See #tick
44
- attr_accessor :target_frametime
45
-
46
- # Returns the current target framerate (frames/second).
47
- # This is an alternate way to access @target_frametime.
48
- # Same as: 1000.0 / #target_frametime
49
- def target_framerate
50
- if @target_frametime
51
- 1000.0 / @target_frametime
52
- else
53
- nil
54
- end
55
- rescue ZeroDivisionError
56
- return nil
57
- end
58
-
59
- # Sets the target number of frames per second to +framerate+.
60
- # This is an alternate way to access @target_frametime.
61
- # Same as: #target_frametime = 1000.0 / framerate
62
- def target_framerate=( framerate )
63
- if framerate
64
- @target_frametime = 1000.0 / framerate
65
- else
66
- @target_frametime = nil
67
- end
68
- rescue ZeroDivisionError
69
- @target_frametime = nil
70
- end
71
-
72
- # call-seq: lifetime() -> Numeric
73
- #
74
- # Returns time in milliseconds since this Clock instance was created.
75
- def lifetime
76
- Clock.runtime() - @start
77
- end
78
-
79
- # call-seq: framerate() -> Numeric
80
- #
81
- # Return the actual framerate (frames per second) recorded by the Clock.
82
- # See #tick.
83
- #
84
- # TODO: sample only a few seconds in the past, instead of the
85
- # entire lifetime of the Clock.
86
- def framerate
87
- # below is same as: return @ticks / (lifetime / 1000.0)
88
- return 1000.0 * @ticks / lifetime()
89
- rescue ZeroDivisionError
90
- return 0
91
- end
92
-
93
- # Returns the number of milliseconds since you last called this method.
94
- #
95
- # You must call this method once per frame (i.e. per iteration of
96
- # your main loop) if you want to use the framerate monitoring and/or
97
- # framerate limiting features.
98
- #
99
- # Framerate monitoring allows you to check the framerate (frames per
100
- # second) with the #framerate method.
101
- #
102
- # Framerate limiting allows you to prevent the application from running
103
- # too fast (and using 100% of processor time) by pausing the program
104
- # very briefly each frame. The pause duration is calculated each frame
105
- # to maintain a constant framerate.
106
- #
107
- # Framerate limiting is only enabled if you have set the
108
- # #target_framerate= or #target_frametime=.
109
- # If you have done that, this method will automatically perform the
110
- # delay each time you call it.
111
- #
112
- # (Please note that no effort is made to correct a framerate
113
- # which is *slower* than the target framerate. Clock can't
114
- # make your code run faster, only slow it down if it is
115
- # running too fast.)
116
- def tick()
117
- passed = Clock.runtime() - @last_tick # how long since the last tick?
118
- if @target_frametime
119
- return Clock.delay(@target_frametime - passed) + passed
120
- end
121
- return passed
122
- ensure
123
- @last_tick = Clock.runtime()
124
- @ticks += 1
125
- end
126
-
127
- end # class Clock
128
- end #module Rubygame
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