function love.load() --options love.graphics.setColor(1,1,1) love.graphics.setDefaultFilter("nearest") -- good pixel SCREEN_WIDTH = love.graphics.getWidth() SCREEN_HEIGHT = love.graphics.getHeight() require "class" require "body" -- simulation variables CONST_G = 39.5 CONST_S = 0.15 -- time T = 0 DT = 1/60 TIME_SPEED = 0.25 CURR_TS = 0 -- view VIEW = {} VIEW.x = 0 VIEW.y = 0 VIEW.size = 104 VIEW.planet_size = 40 VIEW.prints = {} VIEW.print_time = 1/4 VIEW.orbit_prints = {} VIEW.orbit_print_time = 1500 VIEW.fixated = true newBody( { pos = {0, 0, 0}, vel = {-0, 0, 0}, mass = 40000, color = {1,0,0} } ) newBody( { pos = {10000, 0, 0}, vel = {0, 100000, 0}, mass = 200, color = {0,1,0} } ) newBody( { pos = {20000, 0, 0}, vel = {0, 100000, 0}, mass = 400, color = {0,0,1} } ) newBody( { pos = {0, 20000, 0}, vel = {-200000, 0, 0}, mass = 3000, color = {0,1,1} } ) newBody( { pos = {0, -20000, 0}, vel = {200000, 0, 0}, mass = 3000, color = {0,1,1} } ) end function love.keypressed(key) if key == "space" then if CURR_TS == 0 then CURR_TS = TIME_SPEED else CURR_TS = 0 end end if key == "up" or key == "right" then CURR_TS = CURR_TS + 0.1 end if key == "down" or key == "left" then CURR_TS = CURR_TS - 0.1 end CURR_TS = math.max(0, CURR_TS) if key == "z" then VIEW.fixated = not VIEW.fixated end end function love.update(dt) T = math.floor((T + DT * CURR_TS)*1000)/1000 -- merge planets that collision for i=1, #BodyList do for j=i+1, #BodyList do if BodyList[i] and BodyList[j] then local body = BodyList[i] local other_body = BodyList[j] local size = body.size/VIEW.size local other_size = VIEW.planet_size*math.sqrt(other_body.mass) if math.sqrt( (other_body.x - body.x) * (other_body.x - body.x) + (other_body.y - body.y) * (other_body.y - body.y) + (other_body.z - body.z) * (other_body.z - body.z) ) < (size + other_size) * 2 then print("matching ".. i .. " and " .. j) print("original "..i.." pos {"..body.x..", "..body.y..", "..body.z.."}") print("original "..i.." vel {"..body.vx..", "..body.vy..", "..body.vz.."}") print("original "..j.." pos {"..other_body.x..", "..other_body.y..", "..other_body.z.."}") print("original "..j.." vel {"..other_body.vx..", "..other_body.vy..", "..other_body.vz.."}") local new_x = (body.x + other_body.x) / 2 local new_y = (body.y + other_body.y) / 2 local new_z = (body.z + other_body.z) / 2 print("new pos {"..new_x..", "..new_y..", "..new_z.."}") local new_vx = (body.vx + other_body.vx) / 2 local new_vy = (body.vy + other_body.vy) / 2 local new_vz = (body.vz + other_body.vz) / 2 print("new vel {"..new_vx..", "..new_vy..", "..new_vz.."}") local new_mass = body.mass + other_body.mass print("new mass "..new_mass) local new_color_r = (body.color[1]+other_body.color[1])/2 local new_color_g = (body.color[2]+other_body.color[2])/2 local new_color_b = (body.color[3]+other_body.color[3])/2 print("new color {"..new_color_r..", "..new_color_g..", "..new_color_b.."}") newBody( { pos = {new_x, new_y, new_z}, vel = {new_vx, new_vy, new_vz}, mass = new_mass, color = {new_color_r,new_color_g,new_color_b} } ) BodyList[i] = nil BodyList[j] = nil end end end end UpdateBodiesAcceleration() UpdateBodiesVelocity(DT * CURR_TS) UpdateBodiesPosition(DT * CURR_TS) -- get previous view offset local pvx = VIEW.x local pvy = VIEW.y -- center camera on bigger one local vm = 0 for n, body in pairs(BodyList) do if body.mass > vm then vm = body.mass VIEW.x = -body.x VIEW.y = -body.y end end -- adjust sizes to slowest mass local vm = 0 for n, body in pairs(BodyList) do if body.max_distance >= vm then vm = body.max_distance VIEW.size = math.sqrt(body.max_distance) end end if VIEW.size == 0 and #BodyList > 0 then VIEW.fixated = false VIEW.size = math.sqrt(BodyList[1].mass) end -- adjust orbit trails to the reference object if VIEW.fixated then for n, print in pairs(VIEW.orbit_prints) do print.pos.x = print.pos.x - VIEW.x + pvx print.pos.y = print.pos.y - VIEW.y + pvy end end -- clean list of bodies local bl = {} for _, body in pairs(BodyList) do if body then table.insert(bl, body) end end BodyList = bl end function love.draw() love.graphics.setColor(1,1,1) -- draw bodies for n, body in pairs(BodyList) do addPrint(body) end drawObitPrints() drawPrints() -- draw info love.graphics.setColor(1,1,1) love.graphics.print("x,y: " .. VIEW.x .. VIEW.y .. " size: " .. VIEW.size .. " T: ".. T) for n, body in pairs(BodyList) do love.graphics.setColor(body.color[1],body.color[2],body.color[3]) local TT = "" if body.origin then TT = "T: " .. body.origin.T end love.graphics.print("mass: "..body.mass..TT..", x,y: "..body.x..", "..body.y..", vx, vy:"..body.vx..", "..body.vy,0,15*n) end end function addPrint(body) table.insert(VIEW.prints,{ pos = { x = body.x, y = body.y }, mass = body.mass, color = body.color, time = VIEW.print_time }) local trail_color = { (1 + body.color[1])/2, (1 + body.color[2])/2, (1 + body.color[3])/2 } if CURRENT_TS ~= 0 then table.insert(VIEW.orbit_prints,{ pos = { x = body.x, y = body.y }, mass = 1, color = trail_color, time = VIEW.orbit_print_time }) end end function drawPrints() for n, print in pairs(VIEW.prints) do love.graphics.setColor(print.color[1],print.color[2],print.color[3],print.time/VIEW.print_time) love.graphics.circle( "line", (VIEW.x+print.pos.x)/VIEW.size+SCREEN_WIDTH/2, (VIEW.y+print.pos.y)/VIEW.size+SCREEN_HEIGHT/2, VIEW.planet_size * math.sqrt(print.mass)/VIEW.size * (print.time/VIEW.print_time) ) print.time = print.time - CURR_TS if print.time < 1 or print.time > VIEW.print_time then VIEW.prints[n] = nil end end end function drawObitPrints() for n, print in pairs(VIEW.orbit_prints) do love.graphics.setColor(print.color[1],print.color[2],print.color[3],print.time/VIEW.orbit_print_time) love.graphics.circle( "line", (VIEW.x+print.pos.x)/VIEW.size+SCREEN_WIDTH/2, (VIEW.y+print.pos.y)/VIEW.size+SCREEN_HEIGHT/2, print.mass/VIEW.size * (print.time/VIEW.orbit_print_time) ) print.time = print.time - CURR_TS if print.time < 1 or print.time > VIEW.orbit_print_time then VIEW.orbit_prints[n] = nil end end end