rubygame 2.2.0-i586-linux
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 +201 -0
- data/README +139 -0
- data/ROADMAP +43 -0
- data/Rakefile +409 -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/MANIFEST +25 -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.o +0 -0
- data/ext/rubygame/rubygame_gfx.c +942 -0
- data/ext/rubygame/rubygame_gfx.h +101 -0
- data/ext/rubygame/rubygame_gfx.o +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.o +0 -0
- data/ext/rubygame/rubygame_image.c +108 -0
- data/ext/rubygame/rubygame_image.h +41 -0
- data/ext/rubygame/rubygame_image.o +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.o +0 -0
- data/ext/rubygame/rubygame_main.c +155 -0
- data/ext/rubygame/rubygame_main.h +33 -0
- data/ext/rubygame/rubygame_main.o +0 -0
- data/ext/rubygame/rubygame_mixer.c +764 -0
- data/ext/rubygame/rubygame_mixer.h +62 -0
- data/ext/rubygame/rubygame_mixer.o +0 -0
- data/ext/rubygame/rubygame_mixer.so +0 -0
- data/ext/rubygame/rubygame_screen.c +448 -0
- data/ext/rubygame/rubygame_screen.h +43 -0
- data/ext/rubygame/rubygame_screen.o +0 -0
- data/ext/rubygame/rubygame_shared.c +209 -0
- data/ext/rubygame/rubygame_shared.h +60 -0
- data/ext/rubygame/rubygame_shared.o +0 -0
- data/ext/rubygame/rubygame_surface.c +1147 -0
- data/ext/rubygame/rubygame_surface.h +62 -0
- data/ext/rubygame/rubygame_surface.o +0 -0
- data/ext/rubygame/rubygame_time.c +183 -0
- data/ext/rubygame/rubygame_time.h +32 -0
- data/ext/rubygame/rubygame_time.o +0 -0
- data/ext/rubygame/rubygame_ttf.c +599 -0
- data/ext/rubygame/rubygame_ttf.h +69 -0
- data/ext/rubygame/rubygame_ttf.o +0 -0
- data/ext/rubygame/rubygame_ttf.so +0 -0
- data/lib/rubygame/MANIFEST +12 -0
- data/lib/rubygame/clock.rb +128 -0
- data/lib/rubygame/color/models/base.rb +106 -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/color.rb +79 -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/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/lib/rubygame.rb +41 -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 +313 -0
- data/samples/demo_gl.rb +151 -0
- data/samples/demo_gl_tex.rb +197 -0
- data/samples/demo_music.rb +75 -0
- data/samples/demo_rubygame.rb +284 -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 +152 -0
@@ -0,0 +1,313 @@
|
|
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
|
+
module Rubygame
|
21
|
+
|
22
|
+
# List of all Rubygame hardware event classes. *Do not modify!*
|
23
|
+
SDL_EVENTS = [ActiveEvent, KeyDownEvent, KeyUpEvent,\
|
24
|
+
MouseMotionEvent,MouseDownEvent,MouseUpEvent,JoyAxisEvent,\
|
25
|
+
JoyBallEvent, JoyHatEvent,JoyDownEvent, JoyUpEvent,\
|
26
|
+
ResizeEvent, QuitEvent]
|
27
|
+
|
28
|
+
# Converts a keyboard symbol (keysym) into a human-readable text string.
|
29
|
+
# If either Shift key was being pressed, alphanumeric or punctuation keys
|
30
|
+
# will be made uppercase or alternate, based on U.S. keyboard layout.
|
31
|
+
# E.g. "a" becomes "A", "1" becomes "!", and "/" becomes "?".
|
32
|
+
def Rubygame.key2str( sym, mods )
|
33
|
+
if (mods.include? K_LSHIFT) or (mods.include? K_RSHIFT)
|
34
|
+
return (Rubygame::Key::KEY2UPPER[sym]\
|
35
|
+
or Rubygame::Key::KEY2ASCII[sym] or "")
|
36
|
+
else
|
37
|
+
return (Rubygame::Key::KEY2LOWER[sym]\
|
38
|
+
or Rubygame::Key::KEY2ASCII[sym] or "")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# The parent class for all event classes. You can make custom event classes,
|
43
|
+
# if desired; inheriting this class is not necessary, but makes it easier
|
44
|
+
# to check if an object is an event or not.
|
45
|
+
class Event
|
46
|
+
end
|
47
|
+
|
48
|
+
# Indicates that the Rubygame window has gained or lost focus from the
|
49
|
+
# window manager.
|
50
|
+
#
|
51
|
+
# This event has these attributes:
|
52
|
+
# gain:: true if the window gained focus, and false if it lost focus.
|
53
|
+
# state:: string indicating what type of focus was gained or lost:
|
54
|
+
# "mouse":: the mouse entered/exited the window
|
55
|
+
# "keyboard":: the window gained or lost input focus
|
56
|
+
# "active":: the window was minimized/iconified.
|
57
|
+
class ActiveEvent < Event
|
58
|
+
attr_accessor :gain, :state
|
59
|
+
def initialize(gain,state)
|
60
|
+
@gain = gain
|
61
|
+
@state = state
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Indicates that a keyboard key was pressed.
|
66
|
+
#
|
67
|
+
# This event has these attributes:
|
68
|
+
# string:: a human-readable string telling what key was pressed, or nil.
|
69
|
+
# See #key2str.
|
70
|
+
# key:: the integer keysym for the key. These can be compared with the
|
71
|
+
# K_* constants in the Rubygame module, e.g. Rubygame::K_A.
|
72
|
+
# mods:: an Array of zero or more keysyms indicating which modifier keys
|
73
|
+
# were being pressed when the key was pressed. You can compare
|
74
|
+
# with these constants in the Rubygame module:
|
75
|
+
# K_RSHIFT:: shift key (right side)
|
76
|
+
# K_LSHIFT:: shift key (left side)
|
77
|
+
# K_RCTRL:: ctrl key (right side)
|
78
|
+
# K_LCTRL:: ctrl key (left side)
|
79
|
+
# K_RALT:: alt key (right side)
|
80
|
+
# K_LALT:: alt key (left side)
|
81
|
+
# K_RMETA:: meta key (right side)
|
82
|
+
# K_LMETA:: meta key (left side)
|
83
|
+
# K_RSUPER:: super key, aka. Windows key (right side)
|
84
|
+
# K_LSUPER:: super key, aka. Windows key (left side)
|
85
|
+
# K_RALT:: alt key (right side)
|
86
|
+
# K_NUMLOCK:: num lock
|
87
|
+
# K_CAPSLOCK:: caps lock
|
88
|
+
# K_MODE:: mode key
|
89
|
+
#
|
90
|
+
#
|
91
|
+
class KeyDownEvent < Event
|
92
|
+
attr_accessor :string,:key,:mods
|
93
|
+
|
94
|
+
# Create a new KeyDownEvent.
|
95
|
+
#
|
96
|
+
# key:: either an integer keysym (e.g. Rubygame::K_A) or string (e.g. "a")
|
97
|
+
# mods:: array of modifier keysyms
|
98
|
+
def initialize(key,mods)
|
99
|
+
if key.kind_of? Integer
|
100
|
+
@key = key
|
101
|
+
@string = Rubygame.key2str(key, mods) #a string or nil
|
102
|
+
elsif key.kind_of? String
|
103
|
+
@key = Rubygame::Key::ASCII2KEY[key]
|
104
|
+
if @key != nil
|
105
|
+
@string = key
|
106
|
+
else
|
107
|
+
raise(ArgumentError,"First argument of KeyDownEvent.new() must be an Integer KeySym (like K_A) or a ASCII-like String (like \"a\" or \"A\"). Got %s (%s)"%[key,key.class])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
@mods = mods
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Indicates that a keyboard key was released.
|
115
|
+
#
|
116
|
+
# See KeyDownEvent.
|
117
|
+
class KeyUpEvent < Event
|
118
|
+
attr_accessor :string,:key,:mods
|
119
|
+
def initialize(key,mods)
|
120
|
+
if key.kind_of? Integer
|
121
|
+
@key = key
|
122
|
+
@string = Rubygame.key2str(key, mods) #a string or nil
|
123
|
+
elsif key.kind_of? String
|
124
|
+
@key = Rubygame::Key::ASCII2KEY[key]
|
125
|
+
if @key != nil
|
126
|
+
@string = key
|
127
|
+
else
|
128
|
+
raise(ArgumentError,"First argument of KeyUpEvent.new() must be an Integer KeySym (like K_A) or a ASCII-like String (like \"a\" or \"A\"). Got %s (%s)"%[key,key.class])
|
129
|
+
end
|
130
|
+
end
|
131
|
+
@mods = mods
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Indicates that the mouse cursor moved.
|
136
|
+
#
|
137
|
+
# This event has these attributes:
|
138
|
+
# pos:: the new position of the cursor, in the form [x,y].
|
139
|
+
# rel:: the relative movement of the cursor since the last update, [x,y].
|
140
|
+
# buttons:: the mouse buttons that were being held during the movement,
|
141
|
+
# an Array of zero or more of these constants in module Rubygame
|
142
|
+
# (or the corresponding button number):
|
143
|
+
# MOUSE_LEFT:: 1; left mouse button
|
144
|
+
# MOUSE_MIDDLE:: 2; middle mouse button
|
145
|
+
# MOUSE_RIGHT:: 3; right mouse button
|
146
|
+
class MouseMotionEvent < Event
|
147
|
+
attr_accessor :pos,:rel,:buttons
|
148
|
+
def initialize(pos,rel,buttons)
|
149
|
+
@pos, @rel, @buttons = pos, rel, buttons
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Indicates that a mouse button was pressed.
|
154
|
+
#
|
155
|
+
# This event has these attributes:
|
156
|
+
# string:: string indicating the button that was pressed ("left","middle", or
|
157
|
+
# "right").
|
158
|
+
# pos:: the position of the mouse cursor when the button was pressed,
|
159
|
+
# in the form [x,y].
|
160
|
+
# button:: the mouse button that was pressed; one of these constants in
|
161
|
+
# module Rubygame (or the corresponding button number):
|
162
|
+
# MOUSE_LEFT:: 1; left mouse button
|
163
|
+
# MOUSE_MIDDLE:: 2; middle mouse button
|
164
|
+
# MOUSE_RIGHT:: 3; right mouse button
|
165
|
+
class MouseDownEvent < Event
|
166
|
+
attr_accessor :string,:pos,:button
|
167
|
+
def initialize(pos,button)
|
168
|
+
@pos = pos
|
169
|
+
if button.kind_of? Integer
|
170
|
+
@button = button
|
171
|
+
@string = Rubygame::Mouse::MOUSE2STR[button] #a string or nil
|
172
|
+
elsif key.kind_of? String
|
173
|
+
@button = Rubygame::Mouse::STR2MOUSE[key]
|
174
|
+
if @button != nil
|
175
|
+
@string = button
|
176
|
+
else
|
177
|
+
raise(ArgumentError,"First argument of MouseDownEvent.new() must be an Integer Mouse button indentifier (like MOUSE_LEFT) or a String (like \"left\"). Got %s (%s)"%[button,button.class])
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# Indicates that a mouse button was released.
|
184
|
+
#
|
185
|
+
# See MouseDownEvent.
|
186
|
+
class MouseUpEvent < Event
|
187
|
+
attr_accessor :string,:pos,:button
|
188
|
+
def initialize(pos,button)
|
189
|
+
@pos = pos
|
190
|
+
if button.kind_of? Integer
|
191
|
+
@button = button
|
192
|
+
@string = Rubygame::Mouse::MOUSE2STR[button] #a string or nil
|
193
|
+
elsif key.kind_of? String
|
194
|
+
@button = Rubygame::Mouse::STR2MOUSE[key]
|
195
|
+
if @button != nil
|
196
|
+
@string = button
|
197
|
+
else
|
198
|
+
raise(ArgumentError,"First argument of MouseUpEvent.new() must be an Integer Mouse button indentifier (like MOUSE_LEFT) or a String (like \"left\"). Got %s (%s)"%[button,button.class])
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Indicates that a Joystick axis was moved.
|
205
|
+
#
|
206
|
+
# This event has these attributes:
|
207
|
+
# joynum:: the identifier number of the affected Joystick.
|
208
|
+
# axis:: the identifier number of the axis.
|
209
|
+
# value:: the new value of the axis, between -32768 and 32767
|
210
|
+
class JoyAxisEvent < Event
|
211
|
+
attr_accessor :joynum,:axis,:value
|
212
|
+
def initialize(joy,axis,value)
|
213
|
+
# eventually, joy could be int OR a Rubygame::Joystick instance,
|
214
|
+
# which would be stored as joy or maybe joyinstance?
|
215
|
+
@joynum = joy
|
216
|
+
@axis, @value = axis, value
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# Indicates that a Joystick trackball was moved.
|
221
|
+
#
|
222
|
+
# This event has these attributes:
|
223
|
+
# joynum:: the identifier number of the affected Joystick.
|
224
|
+
# ball:: the identifier number of the trackball.
|
225
|
+
# rel:: the relative movement of the trackball, [x,y].
|
226
|
+
class JoyBallEvent < Event
|
227
|
+
attr_accessor :joynum,:ball,:rel
|
228
|
+
def initialize(joy,ball,rel)
|
229
|
+
# eventually, joy could be int OR a Rubygame::Joystick instance,
|
230
|
+
# which would be stored as joy or maybe joyinstance?
|
231
|
+
@joynum = joy
|
232
|
+
@ball, @rel = ball, rel
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
# Indicates that a Joystick POV hat was moved.
|
237
|
+
#
|
238
|
+
# This event has these attributes:
|
239
|
+
# joynum:: the identifier number of the affected Joystick.
|
240
|
+
# hat:: the identifier number of the hat.
|
241
|
+
# value:: the new direction of the hat, one of these constants in module
|
242
|
+
# Rubygame (or the corresponding number):
|
243
|
+
# HAT_CENTERED:: 0
|
244
|
+
# HAT_UP:: 1
|
245
|
+
# HAT_RIGHT:: 2
|
246
|
+
# HAT_DOWN:: 4
|
247
|
+
# HAT_LEFT:: 8
|
248
|
+
# HAT_RIGHTUP:: 3
|
249
|
+
# HAT_RIGHTDOWN:: 6
|
250
|
+
# HAT_LEFTUP:: 9
|
251
|
+
# HAT_LEFTDOWN:: 12
|
252
|
+
class JoyHatEvent < Event
|
253
|
+
attr_accessor :joynum,:hat,:value
|
254
|
+
def initialize(joy,hat,value)
|
255
|
+
# eventually, joy could be int OR a Rubygame::Joystick instance,
|
256
|
+
# which would be stored as joy or maybe joyinstance?
|
257
|
+
@joynum = joy
|
258
|
+
@hat, @value = hat, value
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Indicates that a Joystick button was pressed.
|
263
|
+
#
|
264
|
+
# This event has these attributes:
|
265
|
+
# joynum:: the identifier number of the affected Joystick.
|
266
|
+
# hat:: the identifier number of the button.
|
267
|
+
class JoyDownEvent < Event
|
268
|
+
attr_accessor :joynum, :button
|
269
|
+
def initialize(joy,button)
|
270
|
+
# eventually, joy could be int OR a Rubygame::Joystick instance,
|
271
|
+
# which would be stored as joy or maybe joyinstance?
|
272
|
+
@joynum = joy
|
273
|
+
@button = button
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# Indicates that a Joystick button was released.
|
278
|
+
#
|
279
|
+
# See JoyDownEvent.
|
280
|
+
class JoyUpEvent < Event
|
281
|
+
attr_accessor :joynum, :button
|
282
|
+
def initialize(joy,button)
|
283
|
+
# eventually, joy could be int OR a Rubygame::Joystick instance,
|
284
|
+
# which would be stored as joy or maybe joyinstance?
|
285
|
+
@joynum = joy
|
286
|
+
@button = button
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# Indicates that the application window was resized. (After this event
|
291
|
+
# occurs, you should use Screen#set_mode to change the display surface to
|
292
|
+
# the new size.)
|
293
|
+
#
|
294
|
+
# This event has these attributes:
|
295
|
+
# size:: the new size of the window, in pixels [w,h].
|
296
|
+
class ResizeEvent < Event
|
297
|
+
attr_accessor :size
|
298
|
+
def initialize(new_size)
|
299
|
+
@size = new_size
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
# Indicates that part of the application window was exposed or otherwise
|
304
|
+
# changed, and perhaps the window needs to be refreshed. This event occurs,
|
305
|
+
# for example, when an OpenGL display should be updated.
|
306
|
+
class ExposeEvent < Event
|
307
|
+
end
|
308
|
+
|
309
|
+
# Indicates that the application has been signaled to quit. (E.g. the user
|
310
|
+
# pressed the close button.)
|
311
|
+
class QuitEvent < Event
|
312
|
+
end
|
313
|
+
end # module Rubygame
|
@@ -0,0 +1,370 @@
|
|
1
|
+
# Ftor ("Fake vecTOR"), a vector-like class for 2D position/movement.
|
2
|
+
#--
|
3
|
+
# Rubygame -- Ruby code and bindings to SDL to facilitate game creation
|
4
|
+
# Copyright (C) 2004-2007 John Croisant
|
5
|
+
#
|
6
|
+
# This library is free software; you can redistribute it and/or
|
7
|
+
# modify it under the terms of the GNU Lesser General Public
|
8
|
+
# License as published by the Free Software Foundation; either
|
9
|
+
# version 2.1 of the License, or (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This library is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
+
# Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public
|
17
|
+
# License along with this library; if not, write to the Free Software
|
18
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19
|
+
#++
|
20
|
+
|
21
|
+
module Rubygame
|
22
|
+
|
23
|
+
# *NOTE*: you must require 'rubygame/ftor' manually to gain access to
|
24
|
+
# Rubygame::Ftor. It is not imported with Rubygame by default!
|
25
|
+
#
|
26
|
+
# Ftor ("Fake vecTOR"), a vector-like class for 2D position/movement.
|
27
|
+
#
|
28
|
+
# (NB: See #angle for an important note about why angles appear to be the
|
29
|
+
# opposite of what you may expect.)
|
30
|
+
#
|
31
|
+
# Ftor is useful for storing 2D coordinates (x,y) as well as
|
32
|
+
# vector quantities such as velocity and acceleration (representationally,
|
33
|
+
# points and vectors are equivalent.) Although Ftors are always represented
|
34
|
+
# internally as Cartesian coordinates (x, y), it is possible to deal with an
|
35
|
+
# Ftor as polar coordinates (#angle, #magnitude) instead.
|
36
|
+
# See #new_am and #set_am!, for example.
|
37
|
+
#
|
38
|
+
# Ftor is a "fake" vector because it has certain convenient properties which
|
39
|
+
# differ from "true" vectors (i.e. vectors in a strict mathematical sense).
|
40
|
+
#
|
41
|
+
# Unlike vectors, Ftors may be multiplied or divided to another Ftor. This is
|
42
|
+
# equivalent to multiplying or dividing each component by the corresponding
|
43
|
+
# component in the second Ftor. If you like, you can think of this feature as
|
44
|
+
# scaling each component of the Ftor by a separate factor:
|
45
|
+
#
|
46
|
+
# Ftor(a,b) * Ftor(c,d) = Ftor(a*c, b*d)
|
47
|
+
#
|
48
|
+
# Of course, Ftors also have the usual vector behavior for addition/subraction
|
49
|
+
# between two Ftors, and multiplication/division of an Ftor by a scalar:
|
50
|
+
#
|
51
|
+
# Ftor(a,b) + Ftor(c,d) = Ftor(a+c, b+d)
|
52
|
+
# Ftor(a,b) * n = Ftor(a*n, b*n)
|
53
|
+
#
|
54
|
+
# Additionally, Ftor contains functions for manipulating itself.
|
55
|
+
# You can both get and set such properties as #angle, #magnitude, #unit,
|
56
|
+
# and #normal, and the Ftor will change in-place as needed. For example,
|
57
|
+
# if you set #angle=, the vector will change to have the new angle,
|
58
|
+
# but keeps the same magnitude as before.
|
59
|
+
#
|
60
|
+
# Ftor attempts to save processing time (at the expense of memory) by
|
61
|
+
# storing secondary properties (angle, magnitude, etc.) whenever they are
|
62
|
+
# calculated,so that they need not be calculated repeatedly. If the vector
|
63
|
+
# changes, the properties will be calculated again the next time they
|
64
|
+
# are needed.
|
65
|
+
# (In future versions, it may be possible to disable this feature for
|
66
|
+
# certain Ftors, for example if they will change very often, to save memory.)
|
67
|
+
#
|
68
|
+
class Ftor
|
69
|
+
PI = Math::PI
|
70
|
+
HALF_PI = PI*0.5
|
71
|
+
THREE_HALF_PI = PI*1.5
|
72
|
+
TWO_PI = PI*2
|
73
|
+
|
74
|
+
# Create a new Ftor by specifying its x and y components. See also #new_am
|
75
|
+
# and #new_from_to.
|
76
|
+
def initialize(x,y)
|
77
|
+
@x, @y = x, y
|
78
|
+
end
|
79
|
+
|
80
|
+
# Create a new Ftor by specifying its #angle (in radians) and #magnitude.
|
81
|
+
# See also #new.
|
82
|
+
def self.new_am(a,m)
|
83
|
+
v = Ftor.new(1,0)
|
84
|
+
v.a, v.m = a, m
|
85
|
+
return v
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns a new Ftor which represents the difference in position of two
|
89
|
+
# points +p1+ and +p2+. (+p1+ and +p2+ can be Ftors, size-2 Arrays, or
|
90
|
+
# anything else which has two numerical components and responds to #[].)
|
91
|
+
#
|
92
|
+
# In other words, assuming +v+ is the Ftor returned by this function:
|
93
|
+
# p1 + v = p2
|
94
|
+
def self.new_from_to(p1,p2)
|
95
|
+
return self.class.new(p2[0]-p1[0],p2[1]-p1[1])
|
96
|
+
end
|
97
|
+
|
98
|
+
attr_reader :x # The x component of the Ftor.
|
99
|
+
# Set the x component of the Ftor.
|
100
|
+
def x=(value)
|
101
|
+
@x = value
|
102
|
+
_clear()
|
103
|
+
end
|
104
|
+
|
105
|
+
attr_reader :y # The y component of the Ftor.
|
106
|
+
# Set the y component of the Ftor.
|
107
|
+
def y=(value)
|
108
|
+
@y = value
|
109
|
+
_clear()
|
110
|
+
end
|
111
|
+
|
112
|
+
# Modify the x and y components of the Ftor in-place
|
113
|
+
def set!(x,y)
|
114
|
+
@x, @y = x,y
|
115
|
+
_clear()
|
116
|
+
end
|
117
|
+
|
118
|
+
# Modify the #angle (in radians) and #magnitude of the Ftor in-place
|
119
|
+
def set_am!(a,m)
|
120
|
+
self.angle, self.magnitude = a, m
|
121
|
+
end
|
122
|
+
|
123
|
+
# Same as #to_s, but this Ftor's #object_id is also displayed.
|
124
|
+
def inspect
|
125
|
+
"#<#{self.class}:#{object_id}: %f, %f>"%[@x,@y]
|
126
|
+
end
|
127
|
+
|
128
|
+
# Display this Ftor in the format: "#<Ftor: [x, y]>". x and y are displayed
|
129
|
+
# as floats at full precision. See also #pp.
|
130
|
+
def to_s
|
131
|
+
"#<#{self.class}: [%f, %f]>"%[@x,@y]
|
132
|
+
end
|
133
|
+
|
134
|
+
# "Pretty print". Same as #to_s, but components are displayed as rounded
|
135
|
+
# floats to 3 decimal places, for easy viewing.
|
136
|
+
def pretty
|
137
|
+
"#<#{self.class}: [%0.3f, %0.3f]>"%[@x,@y]
|
138
|
+
end
|
139
|
+
|
140
|
+
# Same as #to_s_am, but this Ftor's #object_id is also displayed.
|
141
|
+
def inspect_am
|
142
|
+
"#<#{self.class}:AM:#{object_id}: %f, %f>"%[angle(),magnitude()]
|
143
|
+
end
|
144
|
+
|
145
|
+
# Display this Ftor in the format: "#<Ftor:AM: [angle, magnitude]>".
|
146
|
+
# angle and magnitude are displayed as floats at full precision.
|
147
|
+
# See also #to_s and #pp_am.
|
148
|
+
def to_s_am
|
149
|
+
"#<#{self.class}:AM: [%f, %f]>"%[angle(),magnitude()]
|
150
|
+
end
|
151
|
+
|
152
|
+
# "Pretty print" with angle and magnitude.
|
153
|
+
# Same as #to_s_am, but components are displayed as rounded floats to 3
|
154
|
+
# decimal places, for easy viewing.
|
155
|
+
def pretty_am
|
156
|
+
"#<#{self.class}:AM: [%0.3f, %0.3f]>"%[angle(),magnitude()]
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns an Array of this Ftor's components, [x,y].
|
160
|
+
def to_a
|
161
|
+
[@x,@y]
|
162
|
+
end
|
163
|
+
alias :to_ary :to_a
|
164
|
+
|
165
|
+
# Return the +i+th component of this Ftor, as if it were the Array
|
166
|
+
# returned by #to_a.
|
167
|
+
def [](i)
|
168
|
+
[@x,@y][i]
|
169
|
+
end
|
170
|
+
|
171
|
+
# True if this Ftor is equal to +other+, when both have been converted to
|
172
|
+
# Arrays via #to_a. In other words, a component-by-component equality check.
|
173
|
+
def ==(other)
|
174
|
+
to_a() == other.to_a
|
175
|
+
end
|
176
|
+
|
177
|
+
# The reverse of this Ftor. I.e., all components are negated. See also
|
178
|
+
# #reverse!.
|
179
|
+
def -@
|
180
|
+
self.class.new(-@x,-@y)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Like #-@, but reverses this Ftor in-place.
|
184
|
+
def reverse!
|
185
|
+
set!(-@x,-@y)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Perform vector addition with this Ftor and +other+, adding them on a
|
189
|
+
# component-by-component basis, like so:
|
190
|
+
# Ftor(a,b) + Ftor(c,d) = Ftor(a+c, b+d)
|
191
|
+
def +(other)
|
192
|
+
return self.class.new(@x+other[0],@y+other[1])
|
193
|
+
end
|
194
|
+
|
195
|
+
# Like #+, but performs subtraction instead of addition.
|
196
|
+
def -(other)
|
197
|
+
return self.class.new(@x-other[0],@y-other[1])
|
198
|
+
end
|
199
|
+
|
200
|
+
# Perform multiplication of this Ftor by the scalar +other+, like so:
|
201
|
+
# Ftor(a,b) * n = Ftor(a*n, b*n)
|
202
|
+
#
|
203
|
+
# However, if this causes TypeError, attempt to extract indices 0 and 1
|
204
|
+
# with +other+'s #[] operator, and multiply them into the corresponding
|
205
|
+
# components of this Ftor, like so:
|
206
|
+
# Ftor(a,b) * Ftor(c,d) = Ftor(a*c, b*d)
|
207
|
+
# Ftor(a,b) * [c,d] = Ftor(a*c, b*d)
|
208
|
+
def *(other)
|
209
|
+
return self.class.new(@x*other,@y*other)
|
210
|
+
rescue TypeError
|
211
|
+
return self.class.new(@x*other[0],@y*other[1])
|
212
|
+
end
|
213
|
+
|
214
|
+
# Like #*, but performs division instead of multiplication.
|
215
|
+
def /(other)
|
216
|
+
x, y = @x.to_f, @y.to_f
|
217
|
+
return self.class.new(x/other,y/other)
|
218
|
+
rescue TypeError
|
219
|
+
return self.class.new(x/other[0],y/other[1])
|
220
|
+
end
|
221
|
+
|
222
|
+
# Return the angle (radians) this Ftor forms with the positive X axis.
|
223
|
+
# This is the same as the Ftor's angle in a polar coordinate system.
|
224
|
+
#
|
225
|
+
# *IMPORTANT*: Because the positive Y axis on the Rubygame::Screen points
|
226
|
+
# *downwards*, an angle in the range 0..PI will appear to point *downwards*,
|
227
|
+
# rather than upwards!
|
228
|
+
# This also means that positive rotation will appear *clockwise*, and
|
229
|
+
# negative rotation will appear *counterclockwise*!
|
230
|
+
# This is the opposite of what you would expect in geometry class!
|
231
|
+
def angle
|
232
|
+
@angle or @angle = Math.atan2(@y,@x)
|
233
|
+
end
|
234
|
+
|
235
|
+
# Set the angle (radians) of this Ftor from the positive X axis.
|
236
|
+
# Magnitude is preserved.
|
237
|
+
def angle=(a)
|
238
|
+
m = magnitude()
|
239
|
+
set!( Math.cos(a)*m, Math.sin(a)*m )
|
240
|
+
end
|
241
|
+
|
242
|
+
alias :a :angle
|
243
|
+
alias :a= :angle= ;
|
244
|
+
|
245
|
+
# Returns the magnitude of the Ftor, i.e. its length from tail to head.
|
246
|
+
# This is the same as the Ftor's magnitude in a polar coordinate system.
|
247
|
+
def magnitude
|
248
|
+
@magnitude or @magnitude = Math.hypot(@x,@y)
|
249
|
+
end
|
250
|
+
|
251
|
+
# Modifies the #magnitude of the Ftor, preserving its #angle.
|
252
|
+
#
|
253
|
+
# In other words, the Ftor will point in the same direction, but it will
|
254
|
+
# be a different length from tail to head.
|
255
|
+
def magnitude=(m)
|
256
|
+
new = unit() * m
|
257
|
+
set!(new.x, new.y)
|
258
|
+
end
|
259
|
+
|
260
|
+
alias :m :magnitude
|
261
|
+
alias :m= :magnitude= ;
|
262
|
+
|
263
|
+
# Return a new unit Ftor which is perpendicular to this Ftor (rotated by
|
264
|
+
# pi/2 radians, to be specific).
|
265
|
+
def normal
|
266
|
+
@normal or @normal = unit().rotate(HALF_PI)
|
267
|
+
end
|
268
|
+
|
269
|
+
# Rotate this Ftor in-place, so that it is perpendicular to +other+.
|
270
|
+
# This Ftor will be at an angle of -pi/2 to +other+.
|
271
|
+
def normal=(other)
|
272
|
+
set!( *(self.class.new(*other).unit().rotate(-HALF_PI) * magnitude()) )
|
273
|
+
end
|
274
|
+
|
275
|
+
alias :n :normal
|
276
|
+
alias :n= :normal= ;
|
277
|
+
|
278
|
+
# Return the unit vector of the Ftor, i.e. an Ftor with the same direction,
|
279
|
+
# but a #magnitude of 1. (This is sometimes called a "normalized" vector,
|
280
|
+
# not to be confused with a vector's #normal.)
|
281
|
+
def unit
|
282
|
+
m = magnitude().to_f
|
283
|
+
@unit or @unit = Ftor.new(@x/m, @y/m)
|
284
|
+
end
|
285
|
+
|
286
|
+
# Rotates this Ftor in-place, so that its #unit vector matches the unit
|
287
|
+
# vector of the given Ftor.
|
288
|
+
#
|
289
|
+
# In other words, changes the #angle of this Ftor to be the same as the angle
|
290
|
+
# of the given Ftor, but this Ftor's #magnitude does not change.
|
291
|
+
#--
|
292
|
+
# TODO: investigate efficiency of using `self.angle = other.angle` instead
|
293
|
+
#++
|
294
|
+
def unit=(other)
|
295
|
+
set!( *(self.class.new(*other).unit() * magnitude()) )
|
296
|
+
end
|
297
|
+
|
298
|
+
alias :u :unit
|
299
|
+
alias :u= :unit=
|
300
|
+
alias :align! :unit=;
|
301
|
+
|
302
|
+
# Return the dot product (aka inner product) of this Ftor and +other+.
|
303
|
+
# The dot product of two vectors +v1+ and +v2+ is:
|
304
|
+
# v1.x * v2.x + v1.y * v2.y
|
305
|
+
def dot(other)
|
306
|
+
@x*other[0] + @y*other[1]
|
307
|
+
end
|
308
|
+
|
309
|
+
# Return the #dot product of #unit vectors of this Ftor and +other+.
|
310
|
+
def udot(other)
|
311
|
+
unit().dot(self.class.new(*other).unit)
|
312
|
+
end
|
313
|
+
|
314
|
+
#Return the difference in angles (radians) between this Ftor and +other+.
|
315
|
+
def angle_with(other)
|
316
|
+
Math.acos( self.udot(other) )
|
317
|
+
end
|
318
|
+
|
319
|
+
# Rotate this Ftor in-place by +angle+ (radians). This is the same as
|
320
|
+
# adding +angle+ to this Ftor's #angle.
|
321
|
+
#
|
322
|
+
#--
|
323
|
+
# , with one important difference:
|
324
|
+
# This method will be much more efficient when rotating at a right angle,
|
325
|
+
# i.e.rotating by any multiple of PI/2 radians from -2*PI to 2*PI radians.
|
326
|
+
#
|
327
|
+
# For convenience, and to ensure exactitude, several numerical constants
|
328
|
+
# have been defined for multiples of PI/2:
|
329
|
+
# * Ftor::PI:: (same as Math::PI)
|
330
|
+
# * Ftor::HALF_PI:: PI * 0.5 (or PI/2)
|
331
|
+
# * Ftor::THREE_HALF_PI:: PI * 1.5 (or 3*PI/2)
|
332
|
+
# * Ftor::TWO_PI:: PI * 2
|
333
|
+
#++
|
334
|
+
#
|
335
|
+
# *IMPORTANT*: Positive rotation will appear *clockwise*, and negative
|
336
|
+
# rotation will appear *counterclockwise*! See #angle for the reason.
|
337
|
+
def rotate!(angle)
|
338
|
+
# case(angle)
|
339
|
+
# when HALF_PI, -THREE_HALF_PI
|
340
|
+
# self.set!(@y,-@x)
|
341
|
+
# when THREE_HALF_PI, -HALF_PI
|
342
|
+
# self.set!(-@y,@x)
|
343
|
+
# when PI, -PI
|
344
|
+
# self.set!(@y,-@x)
|
345
|
+
# when 0, TWO_PI, -TWO_PI
|
346
|
+
# self.set!(@y,-@x)
|
347
|
+
# else
|
348
|
+
self.a += angle
|
349
|
+
# end
|
350
|
+
return self
|
351
|
+
end
|
352
|
+
|
353
|
+
# Like #rotate!, but returns a duplicate instead of rotating this Ftor
|
354
|
+
# in-place.
|
355
|
+
def rotate(radians)
|
356
|
+
self.dup.rotate!(radians)
|
357
|
+
end
|
358
|
+
|
359
|
+
# Clears stored values for #angle, #magnitude, #normal, and #unit,
|
360
|
+
# so that they will be recalculated the next time they are needed.
|
361
|
+
# Intended for internal use, but might be useful in other situations.
|
362
|
+
def _clear
|
363
|
+
@angle = nil
|
364
|
+
@magnitude = nil
|
365
|
+
@normal = nil
|
366
|
+
@unit = nil
|
367
|
+
return self
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|