Created
June 1, 2022 03:11
-
-
Save akkartik/001dcd31aa0e042df0b0a0408f99d742 to your computer and use it in GitHub Desktop.
Gravity simulation. Pull on an object with a slingshot and see where it goes.
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
-- gravity simulation | |
-- | |
-- To run: | |
-- Download LÖVE from https://love2d.org | |
-- Download this file to a directory and rename it to `main.lua` | |
-- Run the program from that directory. | |
-- * on Linux (using the appimage binary): `chmod +x path/to/love-11.4-x86_64.AppImage; path/to/love-11.4-x86_64.AppImage .` | |
-- * on Mac: `path/to/love.app/Contents/MacOS/love .` | |
-- | |
-- You'll see an orange sun and a blue-green satellite. Try clicking on the | |
-- satellite and dragging it a little, then let go. See what happens. To | |
-- retry, quit and restart. Play around with different directions, dragging it | |
-- near or far. | |
function love.load() | |
-- maximize window | |
love.window.setMode(0, 0) -- maximize | |
Screen_width, Screen_height = love.window.getMode() | |
-- shrink slightly to account for window decoration | |
Screen_width = Screen_width-100 | |
Screen_height = Screen_height-100 | |
love.window.setMode(Screen_width, Screen_height) | |
-- satellite data | |
Wperiod = 10 -- seconds | |
Wposition = {x=Screen_width/2, y=Screen_height/4} | |
Wvelocity = nil -- not initialized yet | |
Wvelocitystart = nil | |
Whistory = {} | |
MouseCoefficient = 20 | |
K = 100000 -- constant that folds in relative masses and gravitational constant G | |
Sunx,Suny = Screen_width/2, Screen_height/2 | |
Sunradius = 50 | |
SunspotPeriod = 3 -- seconds | |
SunspotRadius = 2 | |
Sunspots = {} | |
initialize_sunspots() | |
love.keyboard.setTextInput(true) -- bring up keyboard on touch screen | |
love.keyboard.setKeyRepeat(true) | |
end | |
function love.draw() | |
draw_sun() | |
draw_satellite() | |
draw_history() | |
if Wvelocity == nil then | |
draw_velocity_arrow() | |
end | |
end | |
function love.mousepressed(x,y, button) | |
if Wvelocity then return end | |
Wvelocitystart = {x=x, y=y} | |
end | |
function love.mousereleased(x,y, button) | |
if Wvelocity then return end | |
Wvelocity = {x=(Wvelocitystart.x-x)/MouseCoefficient, y=(Wvelocitystart.y-y)/MouseCoefficient} | |
end | |
function draw_sun() | |
love.graphics.setColor(0.75,0.60,0) | |
love.graphics.circle('fill', Sunx,Suny, Sunradius) | |
love.graphics.setColor(1,0,0) | |
for _,spot in ipairs(Sunspots) do | |
love.graphics.circle('fill', Sunx-spot.x,Suny-spot.y, spot.radius) | |
end | |
end | |
function draw_satellite() | |
love.graphics.setColor(0,0.5,0.5) | |
love.graphics.circle('fill', Wposition.x,Wposition.y, 10) | |
end | |
function draw_history() | |
love.graphics.setColor(0,0.2,0.2) | |
for i=1,#Whistory-1 do | |
love.graphics.line(Whistory[i].x,Whistory[i].y, Whistory[i+1].x,Whistory[i+1].y) | |
end | |
end | |
function draw_velocity_arrow() | |
if Wvelocity then return end | |
if Wvelocitystart == nil then return end | |
love.graphics.setColor(1,1,0) | |
local x,y = love.mouse.getX(), love.mouse.getY() | |
love.graphics.line(Wposition.x,Wposition.y, Wposition.x+x-Wvelocitystart.x, Wposition.y+y-Wvelocitystart.y) | |
end | |
function love.update(dt) | |
update_sunspots(dt) | |
update_satellite(dt) | |
end | |
function update_satellite(dt) | |
if Wvelocity == nil then return end | |
local theta = geom.angle(Sunx,Suny, Wposition.x,Wposition.y) | |
local dist = geom.dist(Sunx,Suny, Wposition.x,Wposition.y) | |
if dist < Sunradius then | |
return | |
end | |
local accelx = K*math.cos(theta) / (dist*dist) | |
local accely = K*math.sin(theta) / (dist*dist) | |
Wvelocity.x = Wvelocity.x + dt*accelx | |
Wvelocity.y = Wvelocity.y + dt*accely | |
Wposition.x = Wposition.x - Wvelocity.x | |
Wposition.y = Wposition.y - Wvelocity.y | |
table.insert(Whistory, {x=Wposition.x, y=Wposition.y}) | |
end | |
function initialize_sunspots() | |
for i=1,20 do | |
local r = math.sqrt(love.math.random())*48 -- http://www.anderswallin.net/2009/05/uniform-random-points-in-a-circle-using-polar-coordinates | |
local theta = love.math.random()*2*math.pi | |
local radius = love.math.random()*SunspotRadius | |
table.insert(Sunspots, {x=r*math.cos(theta), y=r*math.sin(theta), orig_radius=radius, radius=radius, time=0}) | |
end | |
end | |
function update_sunspots(dt) | |
for i,spot in ipairs(Sunspots) do | |
spot.time = spot.time + dt | |
spot.radius = spot.orig_radius - spot.time/SunspotPeriod*SunspotRadius | |
if spot.radius <= 0 then | |
local r = math.sqrt(love.math.random())*(Sunradius-2) -- http://www.anderswallin.net/2009/05/uniform-random-points-in-a-circle-using-polar-coordinates | |
local theta = love.math.random()*2*math.pi | |
local radius = SunspotRadius/2 + love.math.random()*SunspotRadius/2 | |
spot.x = r*math.cos(theta) | |
spot.y = r*math.sin(theta) | |
spot.orig_radius = radius | |
spot.radius = radius | |
spot.time = 0 | |
end | |
end | |
end | |
geom = {} | |
-- result is from -π/2 to 3π/2, approximately adding math.atan2 from Lua 5.3 | |
-- (LÖVE is Lua 5.1) | |
function geom.angle(x1,y1, x2,y2) | |
local result = math.atan((y2-y1)/(x2-x1)) | |
if x2 < x1 then | |
result = result+math.pi | |
end | |
return result | |
end | |
function geom.dist(x1,y1, x2,y2) return ((x2-x1)^2+(y2-y1)^2)^0.5 end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment