Skip to content

Instantly share code, notes, and snippets.

@akkartik
Created June 1, 2022 03:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akkartik/001dcd31aa0e042df0b0a0408f99d742 to your computer and use it in GitHub Desktop.
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.
-- 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