Class: Graphics::Body

Inherits:
Object
  • Object
show all
Defined in:
lib/graphics/body.rb

Overview

A body in the simulation.

All bodies know their position, their angle, goal angle (optional), and momentum.

Constant Summary collapse

D2R =

degrees to radians

Graphics::Simulation::D2R
R2D =

radians to degrees

Graphics::Simulation::R2D
NORMAL =

The normals for the cardinal directions.

{
:north => 270,
:south => 90,
:east  => 180,
:west  => 0,
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(w) ⇒ Body

Create a new body in windowing system w with a random x/y and everything else zero’d out.



64
65
66
67
68
69
70
71
# File 'lib/graphics/body.rb', line 64

def initialize w
  self.w = w

  self.x, self.y = rand(w.w), rand(w.h)
  self.a = 0.0
  self.ga = 0.0
  self.m = 0.0
end

Instance Attribute Details

#aObject

Body’s angle, in degrees.



43
44
45
# File 'lib/graphics/body.rb', line 43

def a
  @a
end

#gaObject

Body’s goal angle, in degrees.



48
49
50
# File 'lib/graphics/body.rb', line 48

def ga
  @ga
end

#mObject

Body’s magnitude.



53
54
55
# File 'lib/graphics/body.rb', line 53

def m
  @m
end

#wObject

Body’s window.



58
59
60
# File 'lib/graphics/body.rb', line 58

def w
  @w
end

#xObject

Body’s x coordinate.



33
34
35
# File 'lib/graphics/body.rb', line 33

def x
  @x
end

#yObject

Body’s y coordinate.



38
39
40
# File 'lib/graphics/body.rb', line 38

def y
  @y
end

Instance Method Details

#angle_to(body) ⇒ Object

Return the angle to another body in degrees.



134
135
136
137
138
139
# File 'lib/graphics/body.rb', line 134

def angle_to body
  dx = body.x - self.x
  dy = body.y - self.y

  (R2D * Math.atan2(dy, dx)).degrees
end

#bounce(friction = 0.2) ⇒ Object

Like clip, keep the body in bounds of the window, but set the angle to the angle of reflection. Also slows momentum by friction%.



236
237
238
239
240
241
242
# File 'lib/graphics/body.rb', line 236

def bounce friction = 0.2
  if wall = clip then
    self.a = (2 * NORMAL[wall] - 180 - a).degrees
    self.m *= (1.0 - friction) if friction and friction > 0
    true
  end
end

#clipObject

Keep the body in bounds of the window. If it went out of bounds, set its position to be on that bound and return the cardinal direction of the wall it hit.

See also: NORMALS



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/graphics/body.rb', line 184

def clip
  max_h, max_w = w.h, w.w

  if x < 0 then
    self.x = x.abs
    return :west
  elsif x > max_w then
    self.x = 2 * max_w - x
    return :east
  end

  if y < 0 then
    self.y = y.abs
    return :south
  elsif y > max_h then
    self.y = 2 * max_h - y
    return :north
  end

  nil
end

#clip_off_wallObject

clip and then set the goal angle to the normal plus or minus a random 45 degrees.



225
226
227
228
229
230
# File 'lib/graphics/body.rb', line 225

def clip_off_wall
  if wall = clip then
    normal = NORMAL[wall]
    self.ga = (normal + random_turn(90)).degrees unless (normal - ga).abs < 45
  end
end

#distance_to_squared(p) ⇒ Object

Return the distance to another body, squared.



144
145
146
147
148
# File 'lib/graphics/body.rb', line 144

def distance_to_squared p
  dx = p.x - x
  dy = p.y - y
  dx * dx + dy * dy
end

#dx_dyObject

:nodoc:



124
125
126
127
128
129
# File 'lib/graphics/body.rb', line 124

def dx_dy # :nodoc:
  rad = a * D2R
  dx = Math.cos(rad) * m
  dy = Math.sin(rad) * m
  [dx, dy]
end

#inspectObject

:nodoc:



81
82
83
84
# File 'lib/graphics/body.rb', line 81

def inspect # :nodoc:
  "%s(%.2fx%.2f @ %.2f°x%.2f == %p @ %p)" %
    [self.class, x, y, a, m, position, velocity]
end

#m_aObject

:nodoc:



150
151
152
# File 'lib/graphics/body.rb', line 150

def m_a # :nodoc:
  [m, a]
end

#moveObject

Move the body via its current angle and momentum.



164
165
166
# File 'lib/graphics/body.rb', line 164

def move
  move_by a, m
end

#move_by(a, m) ⇒ Object

Move the body by a specified angle and momentum.



171
172
173
174
175
# File 'lib/graphics/body.rb', line 171

def move_by a, m
  rad = a * D2R
  self.x += Math.cos(rad) * m
  self.y += Math.sin(rad) * m
end

#positionObject

Convert the body to a vector representing its position.

DO NOT modify this vector expecting it to modify the body. It is a copy.



112
113
114
# File 'lib/graphics/body.rb', line 112

def position
  V[x, y]
end

#position=(o) ⇒ Object

Set the body’s position from a velocity vector.



119
120
121
122
# File 'lib/graphics/body.rb', line 119

def position= o
  self.x = o.x
  self.y = o.y
end

#random_angleObject

Return a random angle 0…360.



209
210
211
# File 'lib/graphics/body.rb', line 209

def random_angle
  360 * rand
end

#random_turn(deg) ⇒ Object

Randomly turn the body inside an arc of deg degrees from where it is currently facing.



217
218
219
# File 'lib/graphics/body.rb', line 217

def random_turn deg
  rand(deg) - (deg/2)
end

#turn(dir) ⇒ Object

Turn the body dir degrees.



157
158
159
# File 'lib/graphics/body.rb', line 157

def turn dir
  self.a = (a + dir).degrees if dir
end

#updateObject

Update the body. Does nothing by default. Override this method to add behavior to the body.



77
78
79
# File 'lib/graphics/body.rb', line 77

def update
  # do nothing
end

#velocityObject

Convert the body to a vector representing its velocity.

DO NOT modify this vector expecting it to modify the body. It is a copy.



92
93
94
95
# File 'lib/graphics/body.rb', line 92

def velocity
  x, y = dx_dy
  V[x, y]
end

#velocity=(o) ⇒ Object

Set the body’s magnitude and angle from a velocity vector.



100
101
102
103
104
# File 'lib/graphics/body.rb', line 100

def velocity= o
  dx, dy = o.x, o.y
  self.m = Math.sqrt(dx*dx + dy*dy)
  self.a = Math.atan2(dy, dx) * R2D
end

#wrapObject

Wrap the body if it hits an edge.



247
248
249
250
251
252
253
254
255
# File 'lib/graphics/body.rb', line 247

def wrap
  max_h, max_w = w.h, w.w

  self.x = max_w if x < 0
  self.y = max_h if y < 0

  self.x = 0 if x > max_w
  self.y = 0 if y > max_h
end