This commit is contained in:
Tangent 2020-05-21 21:37:15 -07:00
commit 9554dcba22

123
src/main.moon Normal file
View File

@ -0,0 +1,123 @@
math.randomseed os.time!
w, h = love.graphics.getDimensions!
body_count = 1000
starting_area = 1000^2
percent_scale = 100 / body_count
radius_scale = 1/4
G = 100 -- 6.67408e-11
-- snapshot doubling ??
time, frame_time, sim_rate = 0, 1/60, 1/60
distance = (A, B) ->
local dx, dy
dx = A.x - B.x
dy = A.y - B.y
return math.sqrt dx * dx + dy * dy
gravity = (A, B) ->
local dx, dy, d2, F, theta, cos, sin
dx = A.x - B.x
dy = A.y - B.y
d2 = dx * dx + dy * dy
-- return if d2 == 0
if d2 <= (A.radius + B.radius)^2
return
F = G * A.mass * B.mass / d2
theta = math.atan2 dy, dx
cos = math.cos theta
sin = math.sin theta
A.vx -= (F / A.mass) * cos * sim_rate
A.vy -= (F / A.mass) * sin * sim_rate
B.vx += (F / B.mass) * cos * sim_rate
B.vy += (F / B.mass) * sin * sim_rate
class Body
new: =>
local d, theta
d = math.sqrt(starting_area) / 2
theta = math.random! * math.pi * 2
@x = math.random! * d * math.cos theta
@y = math.random! * d * math.sin theta
@vx = math.random! / d
@vy = math.random! / d
@mass = 1
@radius = @mass ^ radius_scale
bodies = {}
for i = 1, body_count
table.insert bodies, Body!
simulate = (bodies) ->
for i = 1, #bodies - 1, 2
for j = i + 1, #bodies
gravity(bodies[i], bodies[j])
for body in *bodies
body.x += body.vx * sim_rate
body.y += body.vy * sim_rate
invalid_bodies = {}
for i = #bodies, 2, -2
for j = i - 1, 1, -1
valid = true
for id in *invalid_bodies
if i == id or j == id
valid = false
if not valid
continue
A = bodies[i]
B = bodies[j]
-- print i, j
-- if not A
-- print i, j, #bodies
if distance(A, B) <= A.radius + B.radius
-- print "#{i} and #{j} collided!", distance(A, B), A.radius + B.radius
mass = A.mass + B.mass
radius = mass ^ radius_scale
-- print mass, radius
mx = (A.x * A.mass + B.x * B.mass) / mass
my = (A.y * A.mass + B.y * B.mass) / mass
vx = (A.vx * A.mass + B.vx * B.mass) / mass
vy = (A.vy * A.mass + B.vy * B.mass) / mass
A.mass = mass
A.radius = radius
A.x = mx
A.y = my
A.vx = vx
A.vy = vy
table.insert(invalid_bodies, j)
-- table.remove(bodies, j)
-- j += 1
table.sort invalid_bodies, (a, b) -> a > b
for id in *invalid_bodies
-- print id
table.remove bodies, id
-- print "end"
love.update = (dt) ->
simulate bodies
love.draw = ->
if #bodies > 1000
return
love.graphics.setColor 1, 1, 1, 0.25
love.graphics.line 0, h / 2, w, h / 2
love.graphics.line w / 2, 0, w / 2, h
love.graphics.setColor 1, 1, 1, 1
love.graphics.translate w / 2, h / 2
m, x, y = 0, 0, 0
for body in *bodies
if body.mass > m
m = body.mass
x = body.x
y = body.y
love.graphics.translate -x, -y
for body in *bodies
-- love.graphics.points body.x, body.y
love.graphics.circle "fill", body.x, body.y, body.radius
love.keypressed = (key) ->
if key == "escape"
love.event.quit!