Class: Vector2

Inherits:
Object show all
Includes:
Enumerable, MinMaxHelpers
Defined in:
lib/gamebox/lib/vector2.rb

Overview

The Vector2 class implements two-dimensional vectors. It is used to represent positions, movements, and velocities in 2D space.

Constant Summary collapse

RAD_TO_DEG =
180.0 / Math::PI
DEG_TO_RAD =
Math::PI / 180.0
MAX_UDOT_PRODUCT =
1.0
MIN_UDOT_PRODUCT =
-1.0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MinMaxHelpers

#max, #min

Constructor Details

#initialize(x, y) ⇒ Vector2

Creates a new Vector2 with the given x and y values.



71
72
73
# File 'lib/gamebox/lib/vector2.rb', line 71

def initialize( x, y )
  @x, @y = x.to_f, y.to_f
end

Instance Attribute Details

#xObject

Returns the value of attribute x.



75
76
77
# File 'lib/gamebox/lib/vector2.rb', line 75

def x
  @x
end

#yObject

Returns the value of attribute y.



75
76
77
# File 'lib/gamebox/lib/vector2.rb', line 75

def y
  @y
end

Class Method Details

.many(*pairs) ⇒ Object

call-seq:

Vector2.many( [x1,y1], [x2,y2], ... )

Converts multiple [x,y] Arrays to Vector2s. Returns the resulting vectors in an Array.



63
64
65
# File 'lib/gamebox/lib/vector2.rb', line 63

def many( *pairs )
  pairs.collect { |pair| self.new(*pair) }
end

.new_polar(angle_rad, magnitude) ⇒ Object

Creates a new Vector2 from an angle in radians and a magnitude. Use #new_polar_deg for degrees.



43
44
45
46
# File 'lib/gamebox/lib/vector2.rb', line 43

def new_polar( angle_rad, magnitude )
  self.new( Math::cos(angle_rad)*magnitude,
            Math::sin(angle_rad)*magnitude )
end

.new_polar_deg(angle_deg, magnitude) ⇒ Object

Creates a new Vector2 from an angle in degrees and a magnitude. Use #new_polar for radians.



52
53
54
# File 'lib/gamebox/lib/vector2.rb', line 52

def new_polar_deg( angle_deg, magnitude )
  self.new_polar( angle_deg * DEG_TO_RAD, magnitude )
end

Instance Method Details

#*(scalar) ⇒ Object

Multiplies this vector by the given scalar (Numeric), and return the resulting vector.



189
190
191
# File 'lib/gamebox/lib/vector2.rb', line 189

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

#+(vector) ⇒ Object

Adds the given vector to this one and return the resulting vector.



126
127
128
# File 'lib/gamebox/lib/vector2.rb', line 126

def +( vector )
  self.class.new( @x + vector.at(0), @y + vector.at(1) )
end

#-(vector) ⇒ Object

Subtracts the given vector from this one and return the resulting vector.



162
163
164
# File 'lib/gamebox/lib/vector2.rb', line 162

def -( vector )
  self.class.new( @x - vector.at(0), @y - vector.at(1) )
end

#-@Object

Returns the opposite of this vector, i.e. Vector2[-x, -y].



168
169
170
# File 'lib/gamebox/lib/vector2.rb', line 168

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

#==(vector) ⇒ Object

True if the given vector’s x and y components are equal to this vector’s components (within a small margin of error to compensate for floating point imprecision).



198
199
200
201
# File 'lib/gamebox/lib/vector2.rb', line 198

def ==( vector )
  return false if vector.nil?
  _nearly_equal?(@x, vector.at(0)) and _nearly_equal?(@y, vector.at(1))
end

#[](index) ⇒ Object Also known as: at

Returns a component of this vector as if it were an

x,y

Array.



207
208
209
210
211
212
213
214
215
216
# File 'lib/gamebox/lib/vector2.rb', line 207

def []( index )
  case index
  when 0
    @x
  when 1
    @y
  else
    nil
  end
end

#angleObject

Returns the angle of this vector, relative to the positive X axis, in radians. Use #angle_deg for degrees.



237
238
239
# File 'lib/gamebox/lib/vector2.rb', line 237

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

#angle=(angle_rad) ⇒ Object

Sets the vector’s angle in radians. The vector keeps the same magnitude as before.



245
246
247
248
249
250
251
252
# File 'lib/gamebox/lib/vector2.rb', line 245

def angle=( angle_rad )
  raise "can't modify frozen object" if frozen?
  m = magnitude
  @x = Math::cos(angle_rad) * m
  @y = Math::sin(angle_rad) * m
  @hash = nil
  self
end

#angle_degObject

Returns the angle of this vector, relative to the positive X axis, in degrees. Use #angle for radians.



266
267
268
# File 'lib/gamebox/lib/vector2.rb', line 266

def angle_deg
  angle * RAD_TO_DEG
end

#angle_deg=(angle_deg) ⇒ Object

Sets the vector’s angle in degrees. The vector keeps the same magnitude as before.



274
275
276
277
# File 'lib/gamebox/lib/vector2.rb', line 274

def angle_deg=( angle_deg )
  self.angle = angle_deg * DEG_TO_RAD
  self
end

#angle_deg_with(vector) ⇒ Object

Returns the angle of this vector relative to the other vector, in degrees. Use #angle_with for radians.



283
284
285
# File 'lib/gamebox/lib/vector2.rb', line 283

def angle_deg_with( vector )
  angle_with(vector) * RAD_TO_DEG
end

#angle_with(vector) ⇒ Object

Returns the angle of this vector relative to the other vector, in radians. Use #angle_deg_with for degrees.



258
259
260
# File 'lib/gamebox/lib/vector2.rb', line 258

def angle_with( vector )
  Math.acos( max(min(udot(vector),MAX_UDOT_PRODUCT), MIN_UDOT_PRODUCT) )
end

#cross(vector) ⇒ Object

Returns the cross product between this vector and the other vector.



295
296
297
# File 'lib/gamebox/lib/vector2.rb', line 295

def cross( vector )
  (@x * vector.y) - (@y * vector.x)
end

#dot(vector) ⇒ Object

Returns the dot product between this vector and the other vector.



289
290
291
# File 'lib/gamebox/lib/vector2.rb', line 289

def dot( vector )
  (@x * vector.at(0)) + (@y * vector.at(1))
end

#each {|@x| ... } ⇒ Object

Iterates over this vector as if it were an [x,y] Array.

Yields:

  • (@x)


228
229
230
231
# File 'lib/gamebox/lib/vector2.rb', line 228

def each
  yield @x
  yield @y
end

#hashObject

:nodoc:



221
222
223
# File 'lib/gamebox/lib/vector2.rb', line 221

def hash # :nodoc:
  @hash ||= [@x, @y, self.class].hash
end

#magnitudeObject

Returns the magnitude (distance) of this vector.



301
302
303
# File 'lib/gamebox/lib/vector2.rb', line 301

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

#magnitude=(mag) ⇒ Object

Sets the vector’s magnitude (distance). The vector keeps the same angle as before.



309
310
311
312
313
314
315
316
# File 'lib/gamebox/lib/vector2.rb', line 309

def magnitude=( mag )
  raise "can't modify frozen object" if frozen?
  angle_rad = angle
  @x = Math::cos(angle_rad) * mag
  @y = Math::sin(angle_rad) * mag
  @hash = nil
  self
end

#move(x, y = nil) ⇒ Object

call-seq:

move( [x,y] )
move( x,y )

Like #move!, but returns a new vector.



154
155
156
# File 'lib/gamebox/lib/vector2.rb', line 154

def move( x, y=nil )
  self.dup.move!(x, y)
end

#move!(x, y = nil) ⇒ Object

call-seq:

move!( [x,y] )
move!( x,y )

Moves the vector by the given x and y amounts.



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/gamebox/lib/vector2.rb', line 135

def move!( x, y=nil )
  raise "can't modify frozen object" if frozen?
  if y.nil?
    a = x.to_ary
    @x += a[0]
    @y += a[1]
  else
    @x += x
    @y += y
  end
  @hash = nil
  self
end

#perpObject

Returns a copy of this vector, but rotated 90 degrees counter-clockwise.



322
323
324
# File 'lib/gamebox/lib/vector2.rb', line 322

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

#project_onto!(vector) ⇒ Object

Sets this vector to the vector projection (aka vector resolute) of this vector onto the other vector. See also #projected_onto.



329
330
331
332
333
334
335
# File 'lib/gamebox/lib/vector2.rb', line 329

def project_onto!( vector )
  raise "can't modify frozen object" if frozen?
  b = vector.unit
  @x, @y = *(b.scale(self.dot(b)))
  @hash = nil
  self
end

#projected_onto(vector) ⇒ Object

Like #project_onto!, but returns a new vector.



339
340
341
# File 'lib/gamebox/lib/vector2.rb', line 339

def projected_onto( vector )
  dup.project_onto!( vector )
end

#reverseObject

Like #reverse!, but returns a new vector.



181
182
183
# File 'lib/gamebox/lib/vector2.rb', line 181

def reverse
  self.dup.reverse!
end

#reverse!Object

Reverses the vector’s direction, i.e. Vector2[-x, -y].



173
174
175
176
177
178
# File 'lib/gamebox/lib/vector2.rb', line 173

def reverse!
  raise "can't modify frozen object" if frozen?
  @x, @y = -@x, -@y
  @hash = nil
  self
end

#rotate(angle_rad) ⇒ Object

Like #rotate!, but returns a new vector.



353
354
355
# File 'lib/gamebox/lib/vector2.rb', line 353

def rotate( angle_rad )
  dup.rotate!( angle_rad )
end

#rotate!(angle_rad) ⇒ Object

Rotates the vector the given number of radians. Use #rotate_deg! for degrees.



347
348
349
350
# File 'lib/gamebox/lib/vector2.rb', line 347

def rotate!( angle_rad )
  self.angle += angle_rad
  self
end

#rotate_deg(angle_deg) ⇒ Object

Like #rotate_deg!, but returns a new vector.



367
368
369
# File 'lib/gamebox/lib/vector2.rb', line 367

def rotate_deg( angle_deg )
  dup.rotate_deg!( angle_deg )
end

#rotate_deg!(angle_deg) ⇒ Object

Rotates the vector the given number of degrees. Use #rotate for radians.



361
362
363
364
# File 'lib/gamebox/lib/vector2.rb', line 361

def rotate_deg!( angle_deg )
  self.angle_deg += angle_deg
  self
end

#scale(scale_x, scale_y = scale_x) ⇒ Object

Like #scale!, but returns a new vector.



396
397
398
# File 'lib/gamebox/lib/vector2.rb', line 396

def scale( scale_x, scale_y = scale_x )
  dup.scale!(scale_x, scale_y)
end

#scale!(scale_x, scale_y = scale_x) ⇒ Object

call-seq:

scale!( scale )
scale!( scale_x, scale_y )

Multiplies this vector’s x and y values.

If one number is given, the vector will be equal to Vector2[x*scale, y*scale]. If two numbers are given, it will be equal to Vector2[x*scale_x, y*scale_y].

Example:

v = Vector2[1.5,2.5]
v.scale!( 2 )           # => Vector2[3,5]
v.scale!( 3, 4 )        # => Vector2[9,20]


388
389
390
391
392
393
# File 'lib/gamebox/lib/vector2.rb', line 388

def scale!( scale_x, scale_y = scale_x )
  raise "can't modify frozen object" if frozen?
  @x, @y = @x * scale_x, @y * scale_y
  @hash = nil
  self
end

#set!(x, y) ⇒ Object

Sets this vector’s x and y components.



93
94
95
96
97
98
99
# File 'lib/gamebox/lib/vector2.rb', line 93

def set!( x, y )
  raise "can't modify frozen object" if frozen?
  @x = x.to_f
  @y = y.to_f
  @hash = nil
  self
end

#set_polar!(angle_rad, mag) ⇒ Object

Sets this vector’s angle (in radians) and magnitude. Use #set_polar_deg! for degrees.



105
106
107
108
109
110
111
# File 'lib/gamebox/lib/vector2.rb', line 105

def set_polar!( angle_rad, mag )
  raise "can't modify frozen object" if frozen?
  @x = Math::cos(angle_rad) * mag
  @y = Math::sin(angle_rad) * mag
  @hash = nil
  self
end

#set_polar_deg!(angle_deg, mag) ⇒ Object

Sets this vector’s angle (in degrees) and magnitude. Use #set_polar! for radians.



117
118
119
120
# File 'lib/gamebox/lib/vector2.rb', line 117

def set_polar_deg!( angle_deg, mag )
  set_polar!( angle_deg * DEG_TO_RAD, mag )
  self
end

#to_aryObject Also known as: to_a

Returns this vector as an [x,y] Array.



402
403
404
# File 'lib/gamebox/lib/vector2.rb', line 402

def to_ary
  [@x, @y]
end

#to_sObject Also known as: inspect



409
410
411
# File 'lib/gamebox/lib/vector2.rb', line 409

def to_s
  "Vector2[#{@x}, #{@y}]"
end

#udot(vector) ⇒ Object

Returns the dot product of this vector’s #unit and the other vector’s #unit.



419
420
421
# File 'lib/gamebox/lib/vector2.rb', line 419

def udot( vector )
  unit.dot( vector.unit )
end

#unitObject Also known as: normalized

Like #unit!, but returns a new vector.



436
437
438
# File 'lib/gamebox/lib/vector2.rb', line 436

def unit
  self.dup.unit!
end

#unit!Object Also known as: normalize!

Sets this vector’s magnitude to 1.



425
426
427
428
429
430
431
# File 'lib/gamebox/lib/vector2.rb', line 425

def unit!
  raise "can't modify frozen object" if frozen?
  scale = 1/magnitude
  @x, @y = @x * scale, @y * scale
  @hash = nil
  self
end