Skip to content

Commit 3eae922

Browse files
committed
example of local library, use of Boundary Struct
1 parent fc2cf7d commit 3eae922

File tree

4 files changed

+131
-0
lines changed

4 files changed

+131
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# frozen_string_literal: true
2+
# Chain link end as a ball
3+
class VerletBall
4+
include Processing::Proxy
5+
attr_reader :pos, :pos_old, :push, :radius, :x_bound, :y_bound
6+
7+
def initialize(pos, push, radius)
8+
@pos = pos
9+
@push = push
10+
@radius = radius
11+
@pos_old = Vec2D.new(pos.x, pos.y)
12+
# start motion
13+
@pos += push
14+
@x_bound = Boundary.new(radius, width - radius)
15+
@y_bound = Boundary.new(radius, height - radius)
16+
end
17+
18+
def run
19+
verlet
20+
render
21+
bounds_collision
22+
end
23+
24+
def adjust(vec)
25+
@pos += vec
26+
end
27+
28+
private
29+
30+
def verlet
31+
pos_temp = Vec2D.new(pos.x, pos.y)
32+
@pos += (pos - pos_old)
33+
@pos_old = pos_temp
34+
end
35+
36+
def render
37+
ellipse(pos.x, pos.y, radius, radius)
38+
end
39+
40+
def bounds_collision
41+
if x_bound.exclude? pos.x
42+
pos.x = constrain pos.x, x_bound.lower, x_bound.upper
43+
pos_old.x = pos.x
44+
pos.x = (pos.x <= radius)? pos.x + push.x : pos.x - push.x
45+
end
46+
return unless y_bound.exclude? pos.y
47+
pos.y = constrain pos.y, y_bound.lower, y_bound.upper
48+
pos_old.y = pos.y
49+
pos.y = (pos.y <= radius)? pos.y + push.y : pos.y - push.y
50+
end
51+
end
52+
53+
# We can easily create and test bounds in ruby
54+
Boundary = Struct.new(:lower, :upper) do
55+
def exclude? val
56+
true unless (lower..upper).cover? val
57+
end
58+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
# Chain link end as a ball
3+
class VerletStick
4+
include Processing::Proxy
5+
attr_reader :ball_1, :ball_2, :stiffness, :len
6+
7+
def initialize(ball_1, ball_2, stiffness)
8+
@ball_1 = ball_1
9+
@ball_2 = ball_2
10+
@stiffness = stiffness
11+
@len = ball_1.pos.dist(ball_2.pos)
12+
end
13+
14+
def run
15+
render
16+
constrain_len
17+
end
18+
19+
private
20+
21+
def render
22+
begin_shape
23+
vertex(ball_1.pos.x, ball_1.pos.y)
24+
vertex(ball_2.pos.x, ball_2.pos.y)
25+
end_shape
26+
end
27+
28+
def constrain_len
29+
delta = ball_2.pos - ball_1.pos
30+
delta_length = delta.mag
31+
difference = ((delta_length - len) / delta_length)
32+
ball_1.adjust delta * (0.5 * stiffness * difference)
33+
ball_2.adjust delta * (-0.5 * stiffness * difference)
34+
end
35+
end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# frozen_string_literal: true
2+
require_relative 'lib/verlet_ball'
3+
require_relative 'lib/verlet_stick'
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# Verlet Integration - ragdoll chain
3+
# after a sketch by Ira Greenberg
4+
#
5+
load_library :verlet_chain
6+
PARTICLES = 5
7+
LINKS = PARTICLES - 1
8+
9+
attr_reader :sticks, :balls
10+
11+
def settings
12+
size(400, 400)
13+
end
14+
15+
def setup
16+
sketch_title 'Verlet Chain'
17+
ellipse_mode(RADIUS)
18+
rshape = 40
19+
tension = 0.05
20+
@sticks = []
21+
@balls = []
22+
(0..PARTICLES).each do |i|
23+
push = Vec2D.new(rand(3..6.5), rand(3..6.5))
24+
pos = Vec2D.new(width / 2 + (rshape * i), height / 2)
25+
balls << VerletBall.new(pos, push, 5.0)
26+
next if i.zero?
27+
sticks << VerletStick.new(balls[i - 1], balls[i], tension)
28+
end
29+
end
30+
31+
def draw
32+
background(255)
33+
sticks.each(&:run)
34+
balls.each(&:run)
35+
end

0 commit comments

Comments
 (0)