Class: Rubygame::Ftor

Inherits:
Object
  • Object
show all
Defined in:
lib/rubygame/ftor.rb

Overview

NOTE: Ftor is DEPRECATED and will be removed in Rubygame 3.0! A mostly-compatible vector class will be provided at or before that time.

NOTE: you must require ‘rubygame/ftor’ manually to gain access to Rubygame::Ftor. It is not imported with Rubygame by default!

Ftor (“Fake vecTOR”), a vector-like class for 2D position/movement.

(NB: See #angle for an important note about why angles appear to be the opposite of what you may expect.)

Ftor is useful for storing 2D coordinates (x,y) as well as vector quantities such as velocity and acceleration (representationally, points and vectors are equivalent.) Although Ftors are always represented internally as Cartesian coordinates (x, y), it is possible to deal with an Ftor as polar coordinates (#angle, #magnitude) instead. See #new_am and #set_am!, for example.

Ftor is a “fake” vector because it has certain convenient properties which differ from “true” vectors (i.e. vectors in a strict mathematical sense).

Unlike vectors, Ftors may be multiplied or divided to another Ftor. This is equivalent to multiplying or dividing each component by the corresponding component in the second Ftor. If you like, you can think of this feature as scaling each component of the Ftor by a separate factor:

Ftor(a,b) * Ftor(c,d)  =  Ftor(a*c, b*d)

Of course, Ftors also have the usual vector behavior for addition/subraction between two Ftors, and multiplication/division of an Ftor by a scalar:

Ftor(a,b) + Ftor(c,d) = Ftor(a+c, b+d)
Ftor(a,b) * n = Ftor(a*n, b*n)

Additionally, Ftor contains functions for manipulating itself. You can both get and set such properties as #angle, #magnitude, #unit, and #normal, and the Ftor will change in-place as needed. For example, if you set #angle=, the vector will change to have the new angle, but keeps the same magnitude as before.

Ftor attempts to save processing time (at the expense of memory) by storing secondary properties (angle, magnitude, etc.) whenever they are calculated,so that they need not be calculated repeatedly. If the vector changes, the properties will be calculated again the next time they are needed. (In future versions, it may be possible to disable this feature for certain Ftors, for example if they will change very often, to save memory.)

Constant Summary collapse

PI =
Math::PI
HALF_PI =
PI*0.5
THREE_HALF_PI =
PI*1.5
TWO_PI =
PI*2

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(x, y) ⇒ Ftor

and #new_from_to.



82
83
84
85
# File 'lib/rubygame/ftor.rb', line 82

def initialize(x,y)
   Rubygame.deprecated("Rubygame::Ftor", "3.0")
   @x, @y = x, y
end

Instance Attribute Details

#xObject

The x component of the Ftor.



105
106
107
# File 'lib/rubygame/ftor.rb', line 105

def x
  @x
end

#yObject

The y component of the Ftor.



112
113
114
# File 'lib/rubygame/ftor.rb', line 112

def y
  @y
end

Class Method Details

.new_am(a, m) ⇒ Object

See also #new.



89
90
91
92
93
# File 'lib/rubygame/ftor.rb', line 89

def self.new_am(a,m)
	v = self.new(1,0)
   v.a, v.m = a, m
	return v
end

.new_from_to(p1, p2) ⇒ Object

Returns a new Ftor which represents the difference in position of two points p1 and p2. (p1 and p2 can be Ftors, size-2 Arrays, or anything else which has two numerical components and responds to #[].)

In other words, assuming v is the Ftor returned by this function:

p1 + v = p2


101
102
103
# File 'lib/rubygame/ftor.rb', line 101

def self.new_from_to(p1,p2)
  return self.new(p2[0]-p1[0],p2[1]-p1[1])
end

Instance Method Details

#*(other) ⇒ Object

Perform multiplication of this Ftor by the scalar other, like so:

Ftor(a,b) * n = Ftor(a*n, b*n)

However, if this causes TypeError, attempt to extract indices 0 and 1 with other‘s #[] operator, and multiply them into the corresponding components of this Ftor, like so:

Ftor(a,b) * Ftor(c,d) = Ftor(a*c, b*d)
Ftor(a,b) * [c,d]     = Ftor(a*c, b*d)


215
216
217
218
219
# File 'lib/rubygame/ftor.rb', line 215

def *(other)
   return self.class.new(@x*other,@y*other)
 rescue TypeError
   return self.class.new(@x*other[0],@y*other[1])
end

#+(other) ⇒ Object

Perform vector addition with this Ftor and other, adding them on a component-by-component basis, like so:

Ftor(a,b) + Ftor(c,d)  =  Ftor(a+c, b+d)


198
199
200
# File 'lib/rubygame/ftor.rb', line 198

def +(other)
   return self.class.new(@x+other[0],@y+other[1])
end

#-(other) ⇒ Object

Like #+, but performs subtraction instead of addition.



203
204
205
# File 'lib/rubygame/ftor.rb', line 203

def -(other)
   return self.class.new(@x-other[0],@y-other[1])
end

#-@Object

The reverse of this Ftor. I.e., all components are negated. See also #reverse!.



186
187
188
# File 'lib/rubygame/ftor.rb', line 186

def -@
  self.class.new(-@x,-@y)
end

#/(other) ⇒ Object

Like #*, but performs division instead of multiplication.



222
223
224
225
226
227
# File 'lib/rubygame/ftor.rb', line 222

def /(other)
	x, y = @x.to_f, @y.to_f
   return self.class.new(x/other,y/other)
 rescue TypeError
   return self.class.new(x/other[0],y/other[1])
end

#==(other) ⇒ Object

True if this Ftor is equal to other, when both have been converted to Arrays via #to_a. In other words, a component-by-component equality check.



180
181
182
# File 'lib/rubygame/ftor.rb', line 180

def ==(other)
	to_a() == other.to_a
end

#[](i) ⇒ Object

Return the ith component of this Ftor, as if it were the Array returned by #to_a.



174
175
176
# File 'lib/rubygame/ftor.rb', line 174

def [](i)
	[@x,@y][i]
end

#_clearObject

so that they will be recalculated the next time they are needed. Intended for internal use, but might be useful in other situations.



369
370
371
372
373
374
375
# File 'lib/rubygame/ftor.rb', line 369

def _clear
	@angle = nil
	@magnitude = nil
	@normal = nil
	@unit = nil
	return self
end

#angleObject Also known as: a

This is the same as the Ftor’s angle in a polar coordinate system.

IMPORTANT: Because the positive Y axis on the Rubygame::Screen points downwards, an angle in the range 0..PI will appear to point downwards, rather than upwards! This also means that positive rotation will appear clockwise, and negative rotation will appear counterclockwise! This is the opposite of what you would expect in geometry class!



238
239
240
# File 'lib/rubygame/ftor.rb', line 238

def angle
	@angle or @angle = Math.atan2(@y,@x)
end

#angle=(a) ⇒ Object Also known as: a=

Set the angle (radians) of this Ftor from the positive X axis. Magnitude is preserved.



244
245
246
247
# File 'lib/rubygame/ftor.rb', line 244

def angle=(a)
	m = magnitude()
	set!( Math.cos(a)*m, Math.sin(a)*m )
end

#angle_with(other) ⇒ Object

Return the difference in angles (radians) between this Ftor and other.



322
323
324
# File 'lib/rubygame/ftor.rb', line 322

def angle_with(other)
	Math.acos( self.udot(other) )
end

#dot(other) ⇒ Object

The dot product of two vectors v1 and v2 is:

v1.x * v2.x + v1.y * v2.y


312
313
314
# File 'lib/rubygame/ftor.rb', line 312

def dot(other)
	@x*other[0] + @y*other[1]
end

#inspectObject

Same as #to_s, but this Ftor’s #object_id is also displayed.



131
132
133
# File 'lib/rubygame/ftor.rb', line 131

def inspect
	"#<#{self.class}:#{object_id}: %f, %f>"%[@x,@y]
end

#inspect_amObject

Same as #to_s_am, but this Ftor’s #object_id is also displayed.



148
149
150
# File 'lib/rubygame/ftor.rb', line 148

def inspect_am
	"#<#{self.class}:AM:#{object_id}: %f, %f>"%[angle(),magnitude()]
end

#magnitudeObject Also known as: m

This is the same as the Ftor’s magnitude in a polar coordinate system.



254
255
256
# File 'lib/rubygame/ftor.rb', line 254

def magnitude
	@magnitude or @magnitude = Math.hypot(@x,@y)
end

#magnitude=(m) ⇒ Object Also known as: m=

In other words, the Ftor will point in the same direction, but it will be a different length from tail to head.



262
263
264
265
# File 'lib/rubygame/ftor.rb', line 262

def magnitude=(m)
	new = unit() * m
	set!(new.x, new.y)
end

#normalObject Also known as: n

pi/2 radians, to be specific).



272
273
274
# File 'lib/rubygame/ftor.rb', line 272

def normal
	@normal or @normal = unit().rotate(HALF_PI)
end

#normal=(other) ⇒ Object Also known as: n=

Rotate this Ftor in-place, so that it is perpendicular to other. This Ftor will be at an angle of -pi/2 to other.



278
279
280
# File 'lib/rubygame/ftor.rb', line 278

def normal=(other)
   set!( *(self.class.new(*other).unit().rotate(-HALF_PI) * magnitude()) )
end

#prettyObject

“Pretty print”. Same as #to_s, but components are displayed as rounded floats to 3 decimal places, for easy viewing.



143
144
145
# File 'lib/rubygame/ftor.rb', line 143

def pretty
	"#<#{self.class}: [%0.3f, %0.3f]>"%[@x,@y]
end

#pretty_amObject

“Pretty print” with angle and magnitude. Same as #to_s_am, but components are displayed as rounded floats to 3 decimal places, for easy viewing.



162
163
164
# File 'lib/rubygame/ftor.rb', line 162

def pretty_am
	"#<#{self.class}:AM: [%0.3f, %0.3f]>"%[angle(),magnitude()]
end

#reverse!Object

Like #-@, but reverses this Ftor in-place.



191
192
193
# File 'lib/rubygame/ftor.rb', line 191

def reverse!
  set!(-@x,-@y)
end

#rotate(radians) ⇒ Object

Like #rotate!, but returns a duplicate instead of rotating this Ftor in-place.



362
363
364
# File 'lib/rubygame/ftor.rb', line 362

def rotate(radians)
	self.dup.rotate!(radians)
end

#rotate!(angle) ⇒ Object

Rotate this Ftor in-place by angle (radians). This is the same as adding angle to this Ftor’s #angle.

– , with one important difference: This method will be much more efficient when rotating at a right angle, i.e.rotating by any multiple of PI/2 radians from -2*PI to 2*PI radians.

For convenience, and to ensure exactitude, several numerical constants have been defined for multiples of PI/2:

  • Ftor::PI

    (same as Math::PI)

  • Ftor::HALF_PI

    PI * 0.5 (or PI/2)

  • Ftor::THREE_HALF_PI

    PI * 1.5 (or 3*PI/2)

  • Ftor::TWO_PI

    PI * 2

++

IMPORTANT: Positive rotation will appear clockwise, and negative rotation will appear counterclockwise! See #angle for the reason.



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/rubygame/ftor.rb', line 344

def rotate!(angle)
# 		case(angle)
# 		when HALF_PI, -THREE_HALF_PI
# 			self.set!(@y,-@x)
# 		when THREE_HALF_PI, -HALF_PI
# 			self.set!(-@y,@x)
# 		when PI, -PI
# 			self.set!(@y,-@x)
# 		when 0, TWO_PI, -TWO_PI
# 			self.set!(@y,-@x)
# 		else
		self.a += angle
# 		end
	return self
end

#set!(x, y) ⇒ Object

Modify the x and y components of the Ftor in-place



120
121
122
123
# File 'lib/rubygame/ftor.rb', line 120

def set!(x,y)
   @x, @y = x,y
	_clear()
end

#set_am!(a, m) ⇒ Object

Modify the #angle (in radians) and #magnitude of the Ftor in-place



126
127
128
# File 'lib/rubygame/ftor.rb', line 126

def set_am!(a,m)
  self.angle, self.magnitude = a, m
end

#to_aObject Also known as: to_ary

Returns an Array of this Ftor’s components, [x,y].



167
168
169
# File 'lib/rubygame/ftor.rb', line 167

def to_a
	[@x,@y]
end

#to_sObject

Display this Ftor in the format: “#<Ftor: [x, y]>”. x and y are displayed as floats at full precision. See also #pp.



137
138
139
# File 'lib/rubygame/ftor.rb', line 137

def to_s
	"#<#{self.class}: [%f, %f]>"%[@x,@y]
end

#to_s_amObject

Display this Ftor in the format: “#<Ftor:AM: [angle, magnitude]>”. angle and magnitude are displayed as floats at full precision. See also #to_s and #pp_am.



155
156
157
# File 'lib/rubygame/ftor.rb', line 155

def to_s_am
"#<#{self.class}:AM: [%f, %f]>"%[angle(),magnitude()]
end

#udot(other) ⇒ Object

Return the #dot product of #unit vectors of this Ftor and other.



317
318
319
# File 'lib/rubygame/ftor.rb', line 317

def udot(other)
	unit().dot(self.class.new(*other).unit)
end

#unitObject Also known as: u

but a #magnitude of 1. (This is sometimes called a “normalized” vector, not to be confused with a vector’s #normal.)



288
289
290
291
# File 'lib/rubygame/ftor.rb', line 288

def unit
	m = magnitude().to_f
	@unit or @unit = Ftor.new(@x/m, @y/m)
end

#unit=(other) ⇒ Object Also known as: u=, align!

vector of the given Ftor.

In other words, changes the #angle of this Ftor to be the same as the angle of the given Ftor, but this Ftor’s #magnitude does not change. – TODO: investigate efficiency of using ‘self.angle = other.angle` instead ++



301
302
303
# File 'lib/rubygame/ftor.rb', line 301

def unit=(other)
	set!( *(self.class.new(*other).unit() * magnitude()) )
end