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.
- data/CREDITS +60 -0
- data/LICENSE +504 -0
- data/NEWS +252 -0
- data/README +123 -0
- data/ROADMAP +109 -0
- data/Rakefile +440 -0
- data/doc/extended_readme.rdoc +49 -0
- data/doc/getting_started.rdoc +47 -0
- data/doc/macosx_install.rdoc +70 -0
- data/doc/windows_install.rdoc +123 -0
- data/ext/rubygame/rubygame_core.so +0 -0
- data/ext/rubygame/rubygame_event.c +644 -0
- data/ext/rubygame/rubygame_event.h +48 -0
- data/ext/rubygame/rubygame_event.obj +0 -0
- data/ext/rubygame/rubygame_gfx.c +942 -0
- data/ext/rubygame/rubygame_gfx.h +101 -0
- data/ext/rubygame/rubygame_gfx.obj +0 -0
- data/ext/rubygame/rubygame_gfx.so +0 -0
- data/ext/rubygame/rubygame_gl.c +154 -0
- data/ext/rubygame/rubygame_gl.h +32 -0
- data/ext/rubygame/rubygame_gl.obj +0 -0
- data/ext/rubygame/rubygame_image.c +252 -0
- data/ext/rubygame/rubygame_image.h +41 -0
- data/ext/rubygame/rubygame_image.obj +0 -0
- data/ext/rubygame/rubygame_image.so +0 -0
- data/ext/rubygame/rubygame_joystick.c +247 -0
- data/ext/rubygame/rubygame_joystick.h +41 -0
- data/ext/rubygame/rubygame_joystick.obj +0 -0
- data/ext/rubygame/rubygame_main.c +155 -0
- data/ext/rubygame/rubygame_main.h +36 -0
- data/ext/rubygame/rubygame_main.obj +0 -0
- data/ext/rubygame/rubygame_mixer.c +1024 -0
- data/ext/rubygame/rubygame_mixer.h +36 -0
- data/ext/rubygame/rubygame_mixer.obj +0 -0
- data/ext/rubygame/rubygame_mixer.so +0 -0
- data/ext/rubygame/rubygame_music.c +1017 -0
- data/ext/rubygame/rubygame_music.h +29 -0
- data/ext/rubygame/rubygame_music.obj +0 -0
- data/ext/rubygame/rubygame_screen.c +448 -0
- data/ext/rubygame/rubygame_screen.h +43 -0
- data/ext/rubygame/rubygame_screen.obj +0 -0
- data/ext/rubygame/rubygame_shared.c +272 -0
- data/ext/rubygame/rubygame_shared.h +68 -0
- data/ext/rubygame/rubygame_shared.obj +0 -0
- data/ext/rubygame/rubygame_sound.c +863 -0
- data/ext/rubygame/rubygame_sound.h +29 -0
- data/ext/rubygame/rubygame_sound.obj +0 -0
- data/ext/rubygame/rubygame_surface.c +1151 -0
- data/ext/rubygame/rubygame_surface.h +62 -0
- data/ext/rubygame/rubygame_surface.obj +0 -0
- data/ext/rubygame/rubygame_time.c +183 -0
- data/ext/rubygame/rubygame_time.h +32 -0
- data/ext/rubygame/rubygame_time.obj +0 -0
- data/ext/rubygame/rubygame_ttf.c +599 -0
- data/ext/rubygame/rubygame_ttf.h +69 -0
- data/ext/rubygame/rubygame_ttf.obj +0 -0
- data/ext/rubygame/rubygame_ttf.so +0 -0
- data/lib/rubygame.rb +41 -0
- data/lib/rubygame/clock.rb +128 -0
- data/lib/rubygame/color.rb +79 -0
- data/lib/rubygame/color/models/base.rb +111 -0
- data/lib/rubygame/color/models/hsl.rb +153 -0
- data/lib/rubygame/color/models/hsv.rb +149 -0
- data/lib/rubygame/color/models/rgb.rb +78 -0
- data/lib/rubygame/color/palettes/css.rb +49 -0
- data/lib/rubygame/color/palettes/palette.rb +100 -0
- data/lib/rubygame/color/palettes/x11.rb +177 -0
- data/lib/rubygame/constants.rb +238 -0
- data/lib/rubygame/event.rb +313 -0
- data/lib/rubygame/ftor.rb +370 -0
- data/lib/rubygame/hotspot.rb +265 -0
- data/lib/rubygame/keyconstants.rb +237 -0
- data/lib/rubygame/mediabag.rb +94 -0
- data/lib/rubygame/named_resource.rb +254 -0
- data/lib/rubygame/queue.rb +288 -0
- data/lib/rubygame/rect.rb +612 -0
- data/lib/rubygame/sfont.rb +223 -0
- data/lib/rubygame/sprite.rb +511 -0
- data/samples/FreeSans.ttf +0 -0
- data/samples/GPL.txt +340 -0
- data/samples/README +40 -0
- data/samples/chimp.bmp +0 -0
- data/samples/chimp.rb +302 -0
- data/samples/demo_gl.rb +151 -0
- data/samples/demo_gl_tex.rb +197 -0
- data/samples/demo_music.rb +77 -0
- data/samples/demo_rubygame.rb +296 -0
- data/samples/demo_sfont.rb +52 -0
- data/samples/demo_ttf.rb +193 -0
- data/samples/demo_utf8.rb +53 -0
- data/samples/fist.bmp +0 -0
- data/samples/load_and_blit.rb +22 -0
- data/samples/panda.png +0 -0
- data/samples/punch.wav +0 -0
- data/samples/ruby.png +0 -0
- data/samples/song.ogg +0 -0
- data/samples/term16.png +0 -0
- data/samples/whiff.wav +0 -0
- 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
|