Last active
May 17, 2017 22:41
-
-
Save JoshCheek/bb707eebbd6b3d97a2920961d2c5d2f7 to your computer and use it in GitHub Desktop.
Melancholy animation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://vimeo.com/217760201 | |
# can't remember if this is the version from the video or not | |
# that one might've been simpler (w/o the lambdas) | |
require 'graphics' | |
class Smth < Graphics::Simulation | |
def initialize | |
super 1000, 600, 24 | |
self.color.default_proc = -> h, k { k } | |
@num_orbiters = 200 | |
@orbiters = @num_orbiters.times.map { rand_orbiter } | |
@wells = [ | |
Well.new(x: rand(w), y: rand(h), strength: 3), | |
Well.new(x: rand(w), y: rand(h), strength: 2), | |
Well.new(x: rand(w), y: rand(h), strength: 3), | |
Well.new(x: rand(w), y: rand(h), strength: 1), | |
] | |
end | |
def draw(n) | |
clear :black | |
n % 20 == 0 and | |
@wells.each { |well| well.x, well.y = rand(w), rand(h) } | |
@orbiters.reject! &:dead? | |
@orbiters << rand_orbiter while @orbiters.length < @num_orbiters | |
segments = @orbiters.flat_map do |orbiter| | |
orbiter.next_xy | |
orbiter.apply_rand_accel | |
@wells.each do |well| | |
orbiter.apply_gravity(well) | |
end | |
orbiter.apply_velocity | |
orbiter.drawers_for self | |
end | |
segments.sort_by(&:first).each do |_lumin, drawer| | |
drawer.call | |
end | |
end | |
def rand_orbiter | |
color = [ | |
rand(255), | |
rand(255), | |
rand(255), | |
] | |
Orbiter.new x: rand(w), y: rand(h), vx: rand*5, vy: rand*5, color: color, length: rand(50) | |
end | |
class Point | |
attr_accessor :x, :y | |
def initialize(x:, y:) | |
self.x = x | |
self.y = y | |
end | |
end | |
class Well < Point | |
attr_accessor :strength | |
def initialize(strength:, **attrs) | |
super **attrs | |
self.strength = strength | |
end | |
end | |
class Orbiter < Point | |
attr_accessor :vx, :vy, :color, :locations, :length | |
def initialize(vx:, vy:, color:, length:, **attrs) | |
super **attrs | |
self.vx = vx | |
self.vy = vy | |
self.color = color | |
self.locations = [] | |
self.length = length | |
end | |
def drawers_for(canvas) | |
locations.each_cons(2).with_index(1).map do |((x1, y1), (x2, y2)), i| | |
r, g, b = color | |
percent = i.to_f / locations.length | |
r *= percent | |
g *= percent | |
b *= percent | |
segment_color = [r, g, b] | |
drawer = lambda do | |
canvas.line x1, y1, x2, y2, segment_color | |
canvas.line x1+1, y1, x2+1, y2, segment_color | |
canvas.line x1, y1+1, x2, y2+1, segment_color | |
end | |
# http://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color | |
lumin = 0.2126*r + 0.7152*g + 0.0722+b | |
[lumin, drawer] | |
end | |
end | |
def next_xy | |
locations << [x, y] | |
end | |
def dead? | |
locations.length > length | |
end | |
def apply_gravity(well) | |
∆x = x - well.x | |
∆y = y - well.y | |
dist = Math.sqrt ∆x**2 + ∆y**2 | |
self.vx -= (∆x/dist)*well.strength | |
self.vy -= (∆y/dist)*well.strength | |
end | |
def apply_rand_accel | |
self.vx += (rand-0.5) | |
self.vy += (rand-0.5) | |
end | |
def apply_velocity | |
self.x += vx | |
self.y += vy | |
end | |
end | |
end | |
Smth.new.run |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment