rubygame 2.3.0-x86-mswin32-60

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.
Files changed (99) hide show
  1. data/CREDITS +60 -0
  2. data/LICENSE +504 -0
  3. data/NEWS +252 -0
  4. data/README +123 -0
  5. data/ROADMAP +109 -0
  6. data/Rakefile +440 -0
  7. data/doc/extended_readme.rdoc +49 -0
  8. data/doc/getting_started.rdoc +47 -0
  9. data/doc/macosx_install.rdoc +70 -0
  10. data/doc/windows_install.rdoc +123 -0
  11. data/ext/rubygame/rubygame_core.so +0 -0
  12. data/ext/rubygame/rubygame_event.c +644 -0
  13. data/ext/rubygame/rubygame_event.h +48 -0
  14. data/ext/rubygame/rubygame_event.obj +0 -0
  15. data/ext/rubygame/rubygame_gfx.c +942 -0
  16. data/ext/rubygame/rubygame_gfx.h +101 -0
  17. data/ext/rubygame/rubygame_gfx.obj +0 -0
  18. data/ext/rubygame/rubygame_gfx.so +0 -0
  19. data/ext/rubygame/rubygame_gl.c +154 -0
  20. data/ext/rubygame/rubygame_gl.h +32 -0
  21. data/ext/rubygame/rubygame_gl.obj +0 -0
  22. data/ext/rubygame/rubygame_image.c +252 -0
  23. data/ext/rubygame/rubygame_image.h +41 -0
  24. data/ext/rubygame/rubygame_image.obj +0 -0
  25. data/ext/rubygame/rubygame_image.so +0 -0
  26. data/ext/rubygame/rubygame_joystick.c +247 -0
  27. data/ext/rubygame/rubygame_joystick.h +41 -0
  28. data/ext/rubygame/rubygame_joystick.obj +0 -0
  29. data/ext/rubygame/rubygame_main.c +155 -0
  30. data/ext/rubygame/rubygame_main.h +36 -0
  31. data/ext/rubygame/rubygame_main.obj +0 -0
  32. data/ext/rubygame/rubygame_mixer.c +1024 -0
  33. data/ext/rubygame/rubygame_mixer.h +36 -0
  34. data/ext/rubygame/rubygame_mixer.obj +0 -0
  35. data/ext/rubygame/rubygame_mixer.so +0 -0
  36. data/ext/rubygame/rubygame_music.c +1017 -0
  37. data/ext/rubygame/rubygame_music.h +29 -0
  38. data/ext/rubygame/rubygame_music.obj +0 -0
  39. data/ext/rubygame/rubygame_screen.c +448 -0
  40. data/ext/rubygame/rubygame_screen.h +43 -0
  41. data/ext/rubygame/rubygame_screen.obj +0 -0
  42. data/ext/rubygame/rubygame_shared.c +272 -0
  43. data/ext/rubygame/rubygame_shared.h +68 -0
  44. data/ext/rubygame/rubygame_shared.obj +0 -0
  45. data/ext/rubygame/rubygame_sound.c +863 -0
  46. data/ext/rubygame/rubygame_sound.h +29 -0
  47. data/ext/rubygame/rubygame_sound.obj +0 -0
  48. data/ext/rubygame/rubygame_surface.c +1151 -0
  49. data/ext/rubygame/rubygame_surface.h +62 -0
  50. data/ext/rubygame/rubygame_surface.obj +0 -0
  51. data/ext/rubygame/rubygame_time.c +183 -0
  52. data/ext/rubygame/rubygame_time.h +32 -0
  53. data/ext/rubygame/rubygame_time.obj +0 -0
  54. data/ext/rubygame/rubygame_ttf.c +599 -0
  55. data/ext/rubygame/rubygame_ttf.h +69 -0
  56. data/ext/rubygame/rubygame_ttf.obj +0 -0
  57. data/ext/rubygame/rubygame_ttf.so +0 -0
  58. data/lib/rubygame.rb +41 -0
  59. data/lib/rubygame/clock.rb +128 -0
  60. data/lib/rubygame/color.rb +79 -0
  61. data/lib/rubygame/color/models/base.rb +111 -0
  62. data/lib/rubygame/color/models/hsl.rb +153 -0
  63. data/lib/rubygame/color/models/hsv.rb +149 -0
  64. data/lib/rubygame/color/models/rgb.rb +78 -0
  65. data/lib/rubygame/color/palettes/css.rb +49 -0
  66. data/lib/rubygame/color/palettes/palette.rb +100 -0
  67. data/lib/rubygame/color/palettes/x11.rb +177 -0
  68. data/lib/rubygame/constants.rb +238 -0
  69. data/lib/rubygame/event.rb +313 -0
  70. data/lib/rubygame/ftor.rb +370 -0
  71. data/lib/rubygame/hotspot.rb +265 -0
  72. data/lib/rubygame/keyconstants.rb +237 -0
  73. data/lib/rubygame/mediabag.rb +94 -0
  74. data/lib/rubygame/named_resource.rb +254 -0
  75. data/lib/rubygame/queue.rb +288 -0
  76. data/lib/rubygame/rect.rb +612 -0
  77. data/lib/rubygame/sfont.rb +223 -0
  78. data/lib/rubygame/sprite.rb +511 -0
  79. data/samples/FreeSans.ttf +0 -0
  80. data/samples/GPL.txt +340 -0
  81. data/samples/README +40 -0
  82. data/samples/chimp.bmp +0 -0
  83. data/samples/chimp.rb +302 -0
  84. data/samples/demo_gl.rb +151 -0
  85. data/samples/demo_gl_tex.rb +197 -0
  86. data/samples/demo_music.rb +77 -0
  87. data/samples/demo_rubygame.rb +296 -0
  88. data/samples/demo_sfont.rb +52 -0
  89. data/samples/demo_ttf.rb +193 -0
  90. data/samples/demo_utf8.rb +53 -0
  91. data/samples/fist.bmp +0 -0
  92. data/samples/load_and_blit.rb +22 -0
  93. data/samples/panda.png +0 -0
  94. data/samples/punch.wav +0 -0
  95. data/samples/ruby.png +0 -0
  96. data/samples/song.ogg +0 -0
  97. data/samples/term16.png +0 -0
  98. data/samples/whiff.wav +0 -0
  99. metadata +164 -0
@@ -0,0 +1,288 @@
1
+ #--
2
+ # Rubygame -- Ruby code and bindings to SDL to facilitate game creation
3
+ # Copyright (C) 2004-2007 John Croisant
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ #++
19
+
20
+ require "rubygame/event"
21
+
22
+ module Rubygame
23
+
24
+ # EventQueue provides a simple way to manage SDL's events, allowing the
25
+ # application to detect keyboard presses, mouse movements and clicks,
26
+ # joystick movement, etc. You can also post custom events to the
27
+ # EventQueue to help manage the game state.
28
+ #
29
+ # This class replaces the old Rubygame::Queue class, which is no longer
30
+ # available. While EventQueue class serves the same purpose as the old
31
+ # class, they are somewhat different in behavior. Please note that while
32
+ # the old class was a Singleton, this class is not; you may have as many
33
+ # separate instances of EventQueue as you wish (although it is strongly
34
+ # recommended that only one be used to #fetch_sdl_events).
35
+ #
36
+ # For basic usage, create a #new EventQueue with autofetch, then call the
37
+ # #each method once per game loop, passing a block which handles events.
38
+ # See the sample applications for examples of this.
39
+ #
40
+ # If you wish to ignore all events of a certain class, append those classes
41
+ # the instance variable @ignore (accessors are provided). You can ignore as
42
+ # many classes of events as you want, but make sure you don't ignore ALL
43
+ # event classes, or the user won't be able to control the game!
44
+ #
45
+ # If the program has to pause and wait for an event (for example, if the
46
+ # player must press a button to begin playing), you might find the #wait
47
+ # method to be convenient.
48
+ #
49
+ # For reference, the full list of SDL events is:
50
+ # - Event (base class, not used by itself)
51
+ # - ActiveEvent
52
+ # - JoyAxisEvent
53
+ # - JoyBallEvent
54
+ # - JoyDownEvent
55
+ # - JoyHatEvent
56
+ # - JoyUpEvent
57
+ # - KeyDownEvent
58
+ # - KeyUpEvent
59
+ # - MouseDownEvent
60
+ # - MouseMotionEvent
61
+ # - MouseUpEvent
62
+ # - QuitEvent
63
+ # - ResizeEvent
64
+ #
65
+ class EventQueue < Array
66
+ # Array of classes to be ignored by #push.
67
+ attr_accessor :ignore
68
+
69
+ # Whether to fetch SDL events automatically when #each and #wait are used.
70
+ # Enabled by default.
71
+ attr_accessor :autofetch
72
+
73
+ # Create a new EventQueue.
74
+ def initialize()
75
+ @autofetch = true
76
+ @ignore = []
77
+ yield self if block_given?
78
+ end
79
+
80
+ # Append events to the EventQueue.
81
+ # Silently ignores events whose class is in @ignore.
82
+ def push(*events)
83
+ events = events.flatten.delete_if {|e| @ignore.include?(e.class)}
84
+ events.each do |e|
85
+ super( e )
86
+ end
87
+ end
88
+
89
+ alias post push
90
+
91
+ alias peek_each each # Iterate through all events without removing.
92
+
93
+ # Iterate through all events in the EventQueue, yielding them one at a time
94
+ # to the given block. The EventQueue is flushed after all events have been
95
+ # yielded. You can use #peek_each if you want to keep the events.
96
+ #
97
+ # If the internal variable @autofetch is true, this method will call
98
+ # #fetch_sdl_events once before iterating.
99
+ def each(&block)
100
+ fetch_sdl_events if @autofetch
101
+ super
102
+ self.clear
103
+ end
104
+
105
+ # Posts pending SDL hardware events to the EventQueue. Only one EventQueue
106
+ # should call this method per application, and only if you are not using
107
+ # Rubygame#fetch_sdl_events to manually process events! Otherwise, some
108
+ # events may be removed from SDL's event stack before they can be properly
109
+ # processed!
110
+ def fetch_sdl_events
111
+ self.push(Rubygame.fetch_sdl_events())
112
+ end
113
+
114
+ # Wait for an event to be posted, then return that event.
115
+ # If there is already an event in the queue, this method will immediately
116
+ # return that event.
117
+ # Events that are ignored will not trigger the return.
118
+ #
119
+ # This method takes this argument:
120
+ # time:: how long (in milliseconds) to delay between each check for
121
+ # new events. Defaults to 10 ms.
122
+ #
123
+ # If a block is given to this method, it will be run after each
124
+ # unsuccessful check for new events. This method will pass to the block the
125
+ # number of times it has checked for new events.
126
+ #
127
+ # If the internal variable @autofetch is true, this method will call
128
+ # #fetch_sdl_events before every check for new events.
129
+ #
130
+ # Please be cautious when using this method, as it is rather easy to
131
+ # cause an infinite loop. Two ways an infinite loop might occur are:
132
+ # 1. Waiting for an SDL event when @autofetch is disabled. (This is
133
+ # not a problem if the block will post an event.)
134
+ # 2. Waiting for any event when all possible event types are ignored.
135
+ #
136
+ def wait(delay=10, &block)
137
+ iterations = 0
138
+ if block_given?
139
+ loop do
140
+ fetch_sdl_events() if @autofetch
141
+ if self.length >= 1
142
+ s = self.shift
143
+ return s unless s == nil
144
+ end
145
+ yield iterations
146
+ iterations += 1
147
+ Rubygame::Clock.delay(delay)
148
+ end
149
+ else
150
+ loop do
151
+ fetch_sdl_events() if @autofetch
152
+ s = self.shift
153
+ return s unless s == nil
154
+ iterations += 1
155
+ Rubygame::Clock.delay(delay)
156
+ end
157
+ end
158
+ end
159
+
160
+ end # class EventQueue
161
+
162
+
163
+ # A mixin module to extend EventQueue with the ability to 'deliver' specific
164
+ # types of events to subscribed objects, a la a mailing list. Each object
165
+ # must subscribe for the classes of events it wishes to receive;
166
+ # when the MailQueue receives an event of that type, it will deliver
167
+ # it to the subscribers. See #subscribe for more information.
168
+ #
169
+ # Please note that if you extend an already-existing EventQueue object
170
+ # with this mixin module (rather than including it in a class), you must
171
+ # call #setup before using the object. This will create the necessary
172
+ # internal variables for the MailQueue to work.
173
+ #
174
+ module MailQueue
175
+ # Whether to automatically deliver events as they are received.
176
+ # Enabled by default.
177
+ attr_accessor :autodeliver
178
+
179
+ # Create a new MailQueue object.
180
+ # Like EventQueue.new, this method will yield self if a block is given.
181
+ def initialize()
182
+ setup()
183
+ super
184
+ end
185
+
186
+ # Create the necessary internal variables for the MailQueue.
187
+ def setup
188
+ @subscribe = Hash.new
189
+ @autodeliver = true
190
+ end
191
+
192
+ # Returns an Array of all event classes which have at least one subscriber.
193
+ def list
194
+ @subscribe.collect { |k, v|
195
+ (v.length > 0) ? k : nil rescue NoMethodError nil
196
+ }.compact
197
+ end
198
+
199
+ # Subscribe +client+ to receive events that match +klass+.
200
+ #
201
+ # After the client object has been subscribed, the MailQueue will
202
+ # push along any event for which "klass === event" is true. This usually
203
+ # means that the event is an instance of klass or one of klass's child
204
+ # classes; however, note that klass may have changed its own #=== operator
205
+ # to have different behavior, so this is not always the case.
206
+ #
207
+ # Important: the MailQueue uses the client's #push method to deliver
208
+ # events! If the client does not have such a method, MailQueue will
209
+ # silently catch the error and move on to the next client.
210
+ #
211
+ # A client object may be subscribed for many different types of events
212
+ # simultaneously, and more than one client object may be subscribed to
213
+ # any type of event (in which case each object will receive the event).
214
+ # A client may also be subscribed multiple times for the same type (in
215
+ # which case it will receive duplicate events). Likewise, the client will
216
+ # receive duplicates if it is subscribed to multiple classes which share
217
+ # ancestry, for example Numeric and Float.
218
+ #
219
+ # If a client wishes to receive ALL types of events, it can subscribe to
220
+ # Object, which is a parent class of all objects.
221
+ #
222
+ # If the queue's @autodeliver is true, it will deliver events to
223
+ # subscribers immediately after they are posted, rather than waiting for
224
+ # #deliver to be called.
225
+ def subscribe(client,klass)
226
+ @subscribe[klass] << client
227
+ rescue NoMethodError
228
+ @subscribe[klass] = [client] if @subscribe[klass].nil?
229
+ end
230
+
231
+ # Returns true if +client+ is currently subscribed to receive events
232
+ # of type +klass+.
233
+ def subscribed?(client,klass)
234
+ return true if @subscribe[klass].include?(client) rescue NoMethodError
235
+ return false
236
+ end
237
+
238
+ # Unsubscribes the client to stop receiving events of type +klass+.
239
+ # It is safe (has no effect) to unsubscribe for an event type you
240
+ # are not subscribed to receive.
241
+ def unsubscribe(client,klass)
242
+ @subscribe[klass] -= [client] rescue NoMethodError
243
+ ensure
244
+ return
245
+ end
246
+
247
+ # This private method is used by #deliver to do the real work.
248
+ def deliver_event(event)
249
+ @subscribe.each_pair { |klass,clients|
250
+ begin
251
+ if klass === event
252
+ clients.each do |client|
253
+ client.push(event) rescue NoMethodError
254
+ end
255
+ end
256
+ rescue NoMethodError
257
+ end
258
+ }
259
+ end
260
+ private :deliver_event
261
+
262
+ # Deliver each pending event to all objects which are subscribed to
263
+ # that event class. Every client object MUST have a #push method, or
264
+ # events can't be delivered to it, and it will become very lonely!
265
+ #
266
+ # The queue will be cleared of all events after all deliveries are done.
267
+ def deliver()
268
+ each() { |event| deliver_event(event) }
269
+ clear()
270
+ end
271
+
272
+ # Append events to the queue. If @autodeliver is enabled, all events
273
+ # on the queue will be delivered to subscribed client objects immediately.
274
+ def push(*args)
275
+ # Temporarily disable autofetch to avoid infinite loop
276
+ a, @autofetch = @autofetch, false
277
+ # Fetch once to emulate autofetch, if it was enabled before
278
+ fetch_sdl_events() if a
279
+
280
+ super
281
+ deliver() if @autodeliver
282
+
283
+ @autofetch = a
284
+ return
285
+ end
286
+ end
287
+
288
+ end # module Rubygame
@@ -0,0 +1,612 @@
1
+ #--
2
+ # Rubygame -- Ruby code and bindings to SDL to facilitate game creation
3
+ # Copyright (C) 2004-2007 John Croisant
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License as published by the Free Software Foundation; either
8
+ # version 2.1 of the License, or (at your option) any later version.
9
+ #
10
+ # This library is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ # Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public
16
+ # License along with this library; if not, write to the Free Software
17
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ #++
19
+
20
+ #--
21
+ # Table of Contents:
22
+ #
23
+ # class Rect
24
+ # GENERAL:
25
+ # initialize
26
+ # new_from_object
27
+ # to_s
28
+ # to_a, to_ary
29
+ # []
30
+ # ATTRIBUTES:
31
+ # x, y, w, h [<- accessors]
32
+ # width, height, size
33
+ # left, top, right, bottom
34
+ # center, centerx, centery
35
+ # topleft, topright
36
+ # bottomleft, bottomright
37
+ # midleft, midtop, midright, midbottom
38
+ # UTILITY METHODS:
39
+ # clamp, clamp!
40
+ # clip, clip!
41
+ # collide_hash, collide_hash_all
42
+ # collide_array, collide_array_all
43
+ # collide_point?
44
+ # collide_rect?
45
+ # contain?
46
+ # inflate, inflate!
47
+ # move, move!
48
+ # normalize, normalize!
49
+ # union, union!
50
+ # union_all, union_all!
51
+ #
52
+ # class Surface
53
+ # make_rect
54
+ #
55
+ #++
56
+
57
+ module Rubygame
58
+
59
+ # A Rect is a representation of a rectangle, with four core attributes
60
+ # (x offset, y offset, width, and height) and a variety of functions
61
+ # for manipulating and accessing these attributes.
62
+ #
63
+ # Like all coordinates in Rubygame (and its base library, SDL), x and y
64
+ # offsets are measured from the top-left corner of the screen, with greater
65
+ # y offsets being lower. Thus, specifying the x and y offsets of the Rect
66
+ # is equivalent to setting the location of its top-left corner.
67
+ #
68
+ # In Rubygame, Rects are used for collision detection and describing
69
+ # the area of a Surface to operate on.
70
+ class Rect < Array
71
+
72
+ #--
73
+ # GENERAL
74
+ #++
75
+
76
+ # Create a new Rect, attempting to extract its own information from
77
+ # the given arguments. The arguments must fall into one of these cases:
78
+ #
79
+ # - 4 integers +(x, y, w, h)+.
80
+ # - 1 Rect or Array containing 4 integers +([x, y, w, h])+.
81
+ # - 2 Arrays containing 2 integers each +([x,y], [w,h])+.
82
+ # - 1 object with a +rect+ attribute which is a valid Rect object.
83
+ #
84
+ # All rect core attributes (x,y,w,h) must be integers.
85
+ #
86
+ def initialize(*argv)
87
+ case argv.length
88
+ when 1
89
+ if argv[0].kind_of? Array; super(argv[0])
90
+ elsif argv[0].respond_to? :rect; super(argv[0])
91
+ end
92
+ when 2
93
+ super(argv[0].concat(argv[1]))
94
+ when 4
95
+ super(argv)
96
+ end
97
+ return self
98
+ end
99
+
100
+ # Extract or generate a Rect from the given object, if possible, using the
101
+ # following process:
102
+ #
103
+ # 1. If it's a Rect already, return a duplicate Rect.
104
+ # 2. Elsif it's an Array with at least 4 values, make a Rect from it.
105
+ # 3. Elsif it has a +rect+ attribute., perform (1) and (2) on that.
106
+ # 4. Otherwise, raise TypeError.
107
+ #
108
+ # See also Surface#make_rect()
109
+ def Rect.new_from_object(object)
110
+ case(object)
111
+ when Rect
112
+ return object.dup
113
+ when Array
114
+ if object.length >= 4
115
+ return Rect.new(object)
116
+ else
117
+ raise(ArgumentError,"Array does not have enough indices to be made into a Rect (%d for 4)."%object.length )
118
+ end
119
+ else
120
+ begin
121
+ case(object.rect)
122
+ when Rect
123
+ return object.rect.dup
124
+ when Array
125
+ if object.rect.length >= 4
126
+ return Rect.new(object.rect)
127
+ else
128
+ raise(ArgumentError,"Array does not have enough indices to be made into a Rect (%d for 4)."%object.rect.length )
129
+ end
130
+ end # case object.rect
131
+ rescue NoMethodError # if no rect.rect
132
+ raise(TypeError,"Object must be a Rect or Array [x,y,w,h], or have an attribute called 'rect'. (Got %s instance.)"%object.class)
133
+ end
134
+ end # case object
135
+ end
136
+
137
+
138
+ # Print the Rect in the form "+#<Rect [x,y,w,h]>+"
139
+ def to_s; "#<Rect [%s,%s,%s,%s]>"%self; end
140
+
141
+ # Print the Rect in the form "+#<Rect:id [x,y,w,h]>+"
142
+ def inspect; "#<Rect:#{self.object_id} [%s,%s,%s,%s]>"%self; end
143
+
144
+ #--
145
+ # ATTRIBUTES
146
+ #++
147
+
148
+ # Returns self.at(0)
149
+ def x; return self.at(0); end
150
+ # Sets self[0] to +val+
151
+ def x=(val); self[0] = val; end
152
+
153
+ alias left x
154
+ alias left= x=;
155
+ alias l x
156
+ alias l= x=;
157
+
158
+ # Returns self.at(1)
159
+ def y; return self.at(1); end
160
+ # Sets self[1] to +val+
161
+ def y=(val); self[1] = val; end
162
+
163
+ alias top y
164
+ alias top= y=;
165
+ alias t y
166
+ alias t= y=;
167
+
168
+ # Returns self.at(2)
169
+ def w; return self.at(2); end
170
+ # Sets self[2] to +val+
171
+ def w=(val); self[2] = val; end
172
+
173
+ alias width w
174
+ alias width= w=;
175
+
176
+ # Returns self.at(3)
177
+ def h; return self.at(3); end
178
+ # Sets self[3] to +val+
179
+ def h=(val); self[3] = val; end
180
+
181
+ alias height h
182
+ alias height= h=;
183
+
184
+ # Return the width and height of the Rect.
185
+ def size; return self[2,2]; end
186
+
187
+ # Set the width and height of the Rect.
188
+ def size=(size)
189
+ raise ArgumentError, "Rect#size= takes an Array of form [width, height]." if size.size != 2
190
+ self[2,2] = size
191
+ size
192
+ end
193
+
194
+ # Return the x coordinate of the right side of the Rect.
195
+ def right; return self.at(0)+self.at(2); end
196
+
197
+ # Set the x coordinate of the right side of the Rect by translating the
198
+ # Rect (adjusting the x offset).
199
+ def right=(r); self[0] = r - self.at(2); return r; end
200
+
201
+ alias r right
202
+ alias r= right=;
203
+
204
+ # Return the y coordinate of the bottom side of the Rect.
205
+ def bottom; return self.at(1)+self.at(3); end
206
+
207
+ # Set the y coordinate of the bottom side of the Rect by translating the
208
+ # Rect (adjusting the y offset).
209
+ def bottom=(b); self[1] = b - self.at(3); return b; end
210
+
211
+ alias b bottom
212
+ alias b= bottom=;
213
+
214
+ # Return the x and y coordinates of the center of the Rect.
215
+ def center; return self.centerx, self.centery; end
216
+
217
+ # Set the x and y coordinates of the center of the Rect by translating the
218
+ # Rect (adjusting the x and y offsets).
219
+ def center=(center)
220
+ raise ArgumentError, "Rect#center= takes an Array of the form [x,y]." if center.size != 2
221
+ self.centerx, self.centery = center
222
+ center
223
+ end
224
+ alias c center
225
+ alias c= center=;
226
+
227
+ # Return the x coordinate of the center of the Rect
228
+ def centerx; return self.at(0)+(self.at(2).div(2)); end
229
+
230
+ # Set the x coordinate of the center of the Rect by translating the
231
+ # Rect (adjusting the x offset).
232
+ def centerx=(x); self[0] = x - (self.at(2).div(2)); return x; end
233
+
234
+ alias cx centerx
235
+ alias cx= centerx=;
236
+
237
+ # Return the y coordinate of the center of the Rect
238
+ def centery; return self.at(1)+(self.at(3).div(2)); end
239
+
240
+ # Set the y coordinate of the center of the Rect by translating the
241
+ # Rect (adjusting the y offset).
242
+ def centery=(y); self[1] = y- (self.at(3).div(2)); return y; end
243
+
244
+ alias cy centery
245
+ alias cy= centery=;
246
+
247
+ # Return the x and y coordinates of the top-left corner of the Rect
248
+ def topleft; return self[0,2].to_a; end
249
+
250
+ # Set the x and y coordinates of the top-left corner of the Rect by
251
+ # translating the Rect (adjusting the x and y offsets).
252
+ def topleft=(topleft)
253
+ raise ArgumentError, "Rect#topright= takes an Array of form [x, y]." if topleft.size != 2
254
+ self[0,2] = topleft
255
+ return topleft
256
+ end
257
+
258
+ alias tl topleft
259
+ alias tl= topleft=;
260
+
261
+ # Return the x and y coordinates of the top-right corner of the Rect
262
+ def topright; return self.right, self.at(1); end
263
+
264
+ # Set the x and y coordinates of the top-right corner of the Rect by
265
+ # translating the Rect (adjusting the x and y offsets).
266
+ def topright=(topright)
267
+ raise ArgumentError, "Rect#topright= takes an Array of form [x, y]." if topright.size != 2
268
+ self.right, self[1] = topright
269
+ return topright
270
+ end
271
+
272
+ alias tr topright
273
+ alias tr= topright=;
274
+
275
+ # Return the x and y coordinates of the bottom-left corner of the Rect
276
+ def bottomleft; return self.at(0), self.bottom; end
277
+
278
+ # Set the x and y coordinates of the bottom-left corner of the Rect by
279
+ # translating the Rect (adjusting the x and y offsets).
280
+ def bottomleft=(bottomleft)
281
+ raise ArgumentError, "Rect#bottomleft= takes an Array of form [x, y]." if bottomleft.size != 2
282
+ self[0], self.bottom = bottomleft
283
+ return bottomleft
284
+ end
285
+
286
+ alias bl bottomleft
287
+ alias bl= bottomleft=;
288
+
289
+ # Return the x and y coordinates of the bottom-right corner of the Rect
290
+ def bottomright; return self.right, self.bottom; end
291
+
292
+ # Set the x and y coordinates of the bottom-right corner of the Rect by
293
+ # translating the Rect (adjusting the x and y offsets).
294
+ def bottomright=(bottomright)
295
+ raise ArgumentError, "Rect#bottomright= takes an Array of form [x, y]." if bottomright.size != 2
296
+ self.right, self.bottom = bottomright
297
+ return bottomright
298
+ end
299
+
300
+ alias br bottomright
301
+ alias br= bottomright=;
302
+
303
+ # Return the x and y coordinates of the midpoint on the left side of the
304
+ # Rect.
305
+ def midleft; return self.at(0), self.centery; end
306
+
307
+ # Set the x and y coordinates of the midpoint on the left side of the Rect
308
+ # by translating the Rect (adjusting the x and y offsets).
309
+ def midleft=(midleft)
310
+ raise ArgumentError, "Rect#midleft= takes an Array of form [x, y]." if midleft.size != 2
311
+ self[0], self.centery = midleft
312
+ return midleft
313
+ end
314
+
315
+ alias ml midleft
316
+ alias ml= midleft=;
317
+
318
+ # Return the x and y coordinates of the midpoint on the left side of the
319
+ # Rect.
320
+ def midtop; return self.centerx, self.at(1); end
321
+
322
+ # Set the x and y coordinates of the midpoint on the top side of the Rect
323
+ # by translating the Rect (adjusting the x and y offsets).
324
+ def midtop=(midtop)
325
+ raise ArgumentError, "Rect#midtop= takes an Array of form [x, y]." if midtop.size != 2
326
+ self.centerx, self[1] = midtop
327
+ return midtop
328
+ end
329
+
330
+ alias mt midtop
331
+ alias mt= midtop=;
332
+
333
+ # Return the x and y coordinates of the midpoint on the left side of the
334
+ # Rect.
335
+ def midright; return self.right, self.centery; end
336
+
337
+ # Set the x and y coordinates of the midpoint on the right side of the Rect
338
+ # by translating the Rect (adjusting the x and y offsets).
339
+ def midright=(midright)
340
+ raise ArgumentError, "Rect#midright= takes an Array of form [x, y]." if midright.size != 2
341
+ self.right, self.centery = midright
342
+ return midright
343
+ end
344
+
345
+ alias mr midright
346
+ alias mr= midright=;
347
+
348
+ # Return the x and y coordinates of the midpoint on the left side of the
349
+ # Rect.
350
+ def midbottom; return self.centerx, self.bottom; end
351
+
352
+ # Set the x and y coordinates of the midpoint on the bottom side of the
353
+ # Rect by translating the Rect (adjusting the x and y offsets).
354
+ def midbottom=(midbottom)
355
+ raise ArgumentError, "Rect#midbottom= takes an Array of form [x, y]." if midbottom.size != 2
356
+ self.centerx, self.bottom = midbottom
357
+ return midbottom
358
+ end
359
+
360
+ alias mb midbottom
361
+ alias mb= midbottom=;
362
+
363
+ #--
364
+ # UTILITY METHODS
365
+ #++
366
+
367
+
368
+ # As #clamp!, but the original caller is not changed.
369
+ def clamp(rect)
370
+ self.dup.clamp!(rect)
371
+ end
372
+
373
+ # Translate the calling Rect to be entirely inside the given Rect. If
374
+ # the caller is too large along either axis to fit in the given rect,
375
+ # it is centered with respect to the given rect, along that axis.
376
+ def clamp!(rect)
377
+ nself = self.normalize
378
+ rect = Rect.new_from_object(rect)
379
+ #If self is inside given, there is no need to move self
380
+ unless rect.contain?(nself)
381
+
382
+ #If self is too wide:
383
+ if nself.at(2) >= rect.at(2)
384
+ self[0] = rect.centerx - nself.at(2).div(2)
385
+ #Else self is not too wide
386
+ else
387
+ #If self is to the left of arg
388
+ if nself.at(0) < rect.at(0)
389
+ self[0] = rect.at(0)
390
+ #If self is to the right of arg
391
+ elsif nself.right > rect.right
392
+ self[0] = rect.right - nself.at(2)
393
+ #Otherwise, leave x alone
394
+ end
395
+ end
396
+
397
+ #If self is too tall:
398
+ if nself.at(3) >= rect.at(3)
399
+ self[1] = rect.centery - nself.at(3).div(2)
400
+ #Else self is not too tall
401
+ else
402
+ #If self is above arg
403
+ if nself.at(1) < rect.at(1)
404
+ self[1] = rect.at(1)
405
+ #If self below arg
406
+ elsif nself.bottom > rect.bottom
407
+ self[1] = rect.bottom - nself.at(3)
408
+ #Otherwise, leave y alone
409
+ end
410
+ end
411
+ end
412
+ return self
413
+ end
414
+
415
+ # As #clip!, but the original caller is not changed.
416
+ def clip(rect)
417
+ self.dup.clip!(rect)
418
+ end
419
+
420
+ # Crop the calling Rect to be entirely inside the given Rect. If the
421
+ # caller does not intersect the given Rect at all, its width and height
422
+ # are set to zero, but its x and y offsets are not changed.
423
+ #
424
+ # As a side effect, the Rect is normalized.
425
+ def clip!(rect)
426
+ nself = self.normalize
427
+ other = Rect.new_from_object(rect).normalize!
428
+ if self.collide_rect?(other)
429
+ self[0] = [nself.at(0), other.at(0)].max
430
+ self[1] = [nself.at(1), other.at(1)].max
431
+ self[2] = [nself.right, other.right].min - self.at(0)
432
+ self[3] = [nself.bottom, other.bottom].min - self.at(1)
433
+ else #if they do not intersect at all:
434
+ self[0], self[1] = nself.topleft
435
+ self[2], self[3] = 0, 0
436
+ end
437
+ return self
438
+ end
439
+
440
+ # Iterate through all key/value pairs in the given hash table, and
441
+ # return the first pair whose value is a Rect that collides with the
442
+ # caller.
443
+ #
444
+ # Because a hash table is unordered, you should not expect any
445
+ # particular Rect to be returned first.
446
+ def collide_hash(hash_rects)
447
+ hash_rects.each { |key,value|
448
+ if value.collide_rect?+(self); return [key,value]; end
449
+ }
450
+ return nil
451
+ end
452
+
453
+ # Iterate through all key/value pairs in the given hash table, and
454
+ # return an Array of every pair whose value is a Rect that collides
455
+ # the caller.
456
+ #
457
+ # Because a hash table is unordered, you should not expect the returned
458
+ # pairs to be in any particular order.
459
+ def collide_hash_all(hash_rects)
460
+ hash_rects.select { |key,value|
461
+ value.collide_rect?+(self)
462
+ }
463
+ end
464
+
465
+ # Iterate through all elements in the given Array, and return
466
+ # the *index* of the first element which is a Rect that collides with
467
+ # the caller.
468
+ def collide_array(array_rects)
469
+ for i in (0...(array_rects.length))
470
+ if array_rects[i].collide_rect?(self)
471
+ return i
472
+ end
473
+ end
474
+ return nil
475
+ end
476
+
477
+ # Iterate through all elements in the given Array, and return
478
+ # an Array containing the *indices* of every element that is a Rect
479
+ # that collides with the caller.
480
+ def collide_array_all(array_rects)
481
+ indexes = []
482
+ for i in (0...(array_rects.length))
483
+ if array_rects[i].collide_rect?(self)
484
+ indexes += [i]
485
+ end
486
+ end
487
+ return indexes
488
+ end
489
+
490
+ # True if the point is inside (including on the border) of the caller.
491
+ # If you have Array of coordinates, you can use collide_point?(*coords).
492
+ def collide_point?(x,y)
493
+ nself = normalize()
494
+ x.between?(nself.left,nself.right) && y.between?(nself.top,nself.bottom)
495
+ end
496
+
497
+ # True if the caller and the given Rect overlap (or touch) at all.
498
+ def collide_rect?(rect)
499
+ nself = self.normalize
500
+ rect = Rect.new_from_object(rect).normalize!
501
+ return ((nself.l >= rect.l && nself.l <= rect.r) or (rect.l >= nself.l && rect.l <= nself.r)) &&
502
+ ((nself.t >= rect.t && nself.t <= rect.b) or (rect.t >= nself.t && rect.t <= nself.b))
503
+ end
504
+
505
+ # True if the given Rect is totally within the caller. Borders may
506
+ # overlap.
507
+ def contain?(rect)
508
+ nself = self.normalize
509
+ rect = Rect.new_from_object(rect).normalize!
510
+ return (nself.left <= rect.left and rect.right <= nself.right and
511
+ nself.top <= rect.top and rect.bottom <= nself.bottom)
512
+ end
513
+
514
+ # As #inflate!, but the original caller is not changed.
515
+ def inflate(x,y)
516
+ return self.class.new(self.at(0) - x.div(2),
517
+ self.at(1) - y.div(2),
518
+ self.at(2) + x,
519
+ self.at(3) + y)
520
+ end
521
+
522
+ # Increase the Rect's size is the x and y directions, while keeping the
523
+ # same center point. For best results, expand by an even number.
524
+ # X and y inflation can be given as an Array or as separate values.
525
+ def inflate!(x,y)
526
+ self[0] -= x.div(2)
527
+ self[1] -= y.div(2)
528
+ self[2] += x
529
+ self[3] += y
530
+ return self
531
+ end
532
+
533
+ # As #move!, but the original caller is not changed.
534
+ def move(x,y)
535
+ self.dup.move!(x,y)
536
+ end
537
+
538
+ # Translate the Rect by the given amounts in the x and y directions.
539
+ # Positive values are rightward for x and downward for y.
540
+ # X and y movement can be given as an Array or as separate values.
541
+ def move!(x,y)
542
+ self[0]+=x; self[1]+=y
543
+ return self
544
+ end
545
+
546
+ # As #normalize!, but the original caller is not changed.
547
+ def normalize
548
+ self.dup.normalize!()
549
+ end
550
+
551
+ # Fix Rects that have negative width or height, without changing the
552
+ # area it represents. Has no effect on Rects with non-negative width
553
+ # and height. Some Rect methods will automatically normalize the Rect.
554
+ def normalize!
555
+ if self.at(2) < 0
556
+ self[0], self[2] = self.at(0)+self.at(2), -self.at(2)
557
+ end
558
+ if self.at(3) < 0
559
+ self[1], self[3] = self.at(1)+self.at(3), -self.at(3)
560
+ end
561
+ self
562
+ end
563
+
564
+ # As #union!, but the original caller is not changed.
565
+ def union(rect)
566
+ self.dup.union!(rect)
567
+ end
568
+
569
+ # Expand the caller to also cover the given Rect. The Rect is still a
570
+ # rectangle, so it may also cover areas that neither of the original
571
+ # Rects did, for example areas between the two Rects.
572
+ def union!(rect)
573
+ self.normalize!
574
+ rleft, rtop = self.topleft
575
+ rright, rbottom = self.bottomright
576
+ r2 = Rect.new_from_object(rect).normalize!
577
+
578
+ rleft = [rleft, r2.left].min
579
+ rtop = [rtop, r2.top].min
580
+ rright = [rright, r2.right].max
581
+ rbottom = [rbottom, r2.bottom].max
582
+
583
+ self[0,4] = rleft, rtop, rright - rleft, rbottom - rtop
584
+ return self
585
+ end
586
+
587
+ # As #union_all!, but the original caller is not changed.
588
+ def union_all(array_rects)
589
+ self.dup.union_all!(array_rects)
590
+ end
591
+
592
+ # Expand the caller to cover all of the given Rects. See also #union!
593
+ def union_all!(array_rects)
594
+ array_rects.each do |r|
595
+ self.union!(r)
596
+ end
597
+ return self
598
+ end
599
+
600
+
601
+ end # class Rect
602
+
603
+
604
+ class Surface
605
+ # Return a Rect with the same width and height as the Surface, positioned
606
+ # at (0,0).
607
+ def make_rect()
608
+ return Rect.new(0,0,self.width,self.height)
609
+ end
610
+ end
611
+
612
+ end # module Rubygame