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.
Files changed (94) hide show
  1. data/CREDITS +60 -0
  2. data/LICENSE +504 -0
  3. data/NEWS +201 -0
  4. data/README +139 -0
  5. data/ROADMAP +43 -0
  6. data/Rakefile +409 -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/MANIFEST +25 -0
  12. data/ext/rubygame/rubygame_core.so +0 -0
  13. data/ext/rubygame/rubygame_event.c +644 -0
  14. data/ext/rubygame/rubygame_event.h +48 -0
  15. data/ext/rubygame/rubygame_event.o +0 -0
  16. data/ext/rubygame/rubygame_gfx.c +942 -0
  17. data/ext/rubygame/rubygame_gfx.h +101 -0
  18. data/ext/rubygame/rubygame_gfx.o +0 -0
  19. data/ext/rubygame/rubygame_gfx.so +0 -0
  20. data/ext/rubygame/rubygame_gl.c +154 -0
  21. data/ext/rubygame/rubygame_gl.h +32 -0
  22. data/ext/rubygame/rubygame_gl.o +0 -0
  23. data/ext/rubygame/rubygame_image.c +108 -0
  24. data/ext/rubygame/rubygame_image.h +41 -0
  25. data/ext/rubygame/rubygame_image.o +0 -0
  26. data/ext/rubygame/rubygame_image.so +0 -0
  27. data/ext/rubygame/rubygame_joystick.c +247 -0
  28. data/ext/rubygame/rubygame_joystick.h +41 -0
  29. data/ext/rubygame/rubygame_joystick.o +0 -0
  30. data/ext/rubygame/rubygame_main.c +155 -0
  31. data/ext/rubygame/rubygame_main.h +33 -0
  32. data/ext/rubygame/rubygame_main.o +0 -0
  33. data/ext/rubygame/rubygame_mixer.c +764 -0
  34. data/ext/rubygame/rubygame_mixer.h +62 -0
  35. data/ext/rubygame/rubygame_mixer.o +0 -0
  36. data/ext/rubygame/rubygame_mixer.so +0 -0
  37. data/ext/rubygame/rubygame_screen.c +448 -0
  38. data/ext/rubygame/rubygame_screen.h +43 -0
  39. data/ext/rubygame/rubygame_screen.o +0 -0
  40. data/ext/rubygame/rubygame_shared.c +209 -0
  41. data/ext/rubygame/rubygame_shared.h +60 -0
  42. data/ext/rubygame/rubygame_shared.o +0 -0
  43. data/ext/rubygame/rubygame_surface.c +1147 -0
  44. data/ext/rubygame/rubygame_surface.h +62 -0
  45. data/ext/rubygame/rubygame_surface.o +0 -0
  46. data/ext/rubygame/rubygame_time.c +183 -0
  47. data/ext/rubygame/rubygame_time.h +32 -0
  48. data/ext/rubygame/rubygame_time.o +0 -0
  49. data/ext/rubygame/rubygame_ttf.c +599 -0
  50. data/ext/rubygame/rubygame_ttf.h +69 -0
  51. data/ext/rubygame/rubygame_ttf.o +0 -0
  52. data/ext/rubygame/rubygame_ttf.so +0 -0
  53. data/lib/rubygame/MANIFEST +12 -0
  54. data/lib/rubygame/clock.rb +128 -0
  55. data/lib/rubygame/color/models/base.rb +106 -0
  56. data/lib/rubygame/color/models/hsl.rb +153 -0
  57. data/lib/rubygame/color/models/hsv.rb +149 -0
  58. data/lib/rubygame/color/models/rgb.rb +78 -0
  59. data/lib/rubygame/color/palettes/css.rb +49 -0
  60. data/lib/rubygame/color/palettes/palette.rb +100 -0
  61. data/lib/rubygame/color/palettes/x11.rb +177 -0
  62. data/lib/rubygame/color.rb +79 -0
  63. data/lib/rubygame/constants.rb +238 -0
  64. data/lib/rubygame/event.rb +313 -0
  65. data/lib/rubygame/ftor.rb +370 -0
  66. data/lib/rubygame/hotspot.rb +265 -0
  67. data/lib/rubygame/keyconstants.rb +237 -0
  68. data/lib/rubygame/mediabag.rb +94 -0
  69. data/lib/rubygame/queue.rb +288 -0
  70. data/lib/rubygame/rect.rb +612 -0
  71. data/lib/rubygame/sfont.rb +223 -0
  72. data/lib/rubygame/sprite.rb +511 -0
  73. data/lib/rubygame.rb +41 -0
  74. data/samples/FreeSans.ttf +0 -0
  75. data/samples/GPL.txt +340 -0
  76. data/samples/README +40 -0
  77. data/samples/chimp.bmp +0 -0
  78. data/samples/chimp.rb +313 -0
  79. data/samples/demo_gl.rb +151 -0
  80. data/samples/demo_gl_tex.rb +197 -0
  81. data/samples/demo_music.rb +75 -0
  82. data/samples/demo_rubygame.rb +284 -0
  83. data/samples/demo_sfont.rb +52 -0
  84. data/samples/demo_ttf.rb +193 -0
  85. data/samples/demo_utf8.rb +53 -0
  86. data/samples/fist.bmp +0 -0
  87. data/samples/load_and_blit.rb +22 -0
  88. data/samples/panda.png +0 -0
  89. data/samples/punch.wav +0 -0
  90. data/samples/ruby.png +0 -0
  91. data/samples/song.ogg +0 -0
  92. data/samples/term16.png +0 -0
  93. data/samples/whiff.wav +0 -0
  94. 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