commit 9554dcba220f0d016856828f20261b8fe971c4a4 Author: Tangent Date: Thu May 21 21:37:15 2020 -0700 init diff --git a/src/main.moon b/src/main.moon new file mode 100644 index 0000000..414cf81 --- /dev/null +++ b/src/main.moon @@ -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!