Advertisement
1m1m0

Orbit 1.2.3 (No Polygons) Archive

May 9th, 2024 (edited)
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 18.35 KB | Software | 0 0
  1. -- | Orbit (Interactive Celestial Body Simulator Program) Complete Release v1.2.3 [5/8/2024], written by 1m1m0 & several AI models | --
  2.  
  3. -- (Quick Settings/Variables) --
  4. local scale = math.random(0.8, 1.5) -- Factor to propotionally resize objects, size and mass included
  5. local trailLifeTime = 1 -- How long a trail will last (seconds)
  6. local trailSize = 0.25 -- How wide trails will be proportional to their parent circle's radius
  7. local trailOpaqueness = 0.5 -- How see-through trails will be
  8. local trailGradient = 0 -- Determines if trails fade out or not
  9. local numRandomCircles = math.random(2, 75) -- Amount of circles can randomly spawn
  10. local circleMass = math.random(1, 12) -- Mass of circles while being randomized
  11. local radiusMax = math.random(15, 25) -- Maximum random radius of circles while being randomized
  12. local radiusMin = math.random(8, 13) -- Minimum random radius of circles while being randomized
  13. local throwAmplifier = 0.075 -- Factor in which how fast an object will be after throwing or flicking it
  14. local velocityRate = 1 -- Time (seconds) to calculate the velocity of the circle while thrown (pix/s)
  15. local dampingAmplifier = 0.25 -- Factor to simulate drag or air resistance (set to 0 for cosmic simulations)
  16. local randomCirclesBounce = math.random(0.0, 0.535) -- Elasticity of the Randomized Circles
  17. local wrapBuffer = 0.5 -- Ensures the circle is fully off-screen to wrap around the screen
  18. -- (Togglables) --
  19. local toggleWalls = true -- Toggle to have bounderies to the simulation
  20. local toggleBodyWrap = true -- Toggle teleporting objects across the screen when crossing the walls
  21. local toggleStartingCircle = true -- Toggle to spawn a starting circle
  22. local toggleCustomCircles = true -- Toggle to spawn more starting circles which can be changed in 'local customCircles = 4'
  23. local toggleRandomCircles = true -- Toggle randomized circles
  24. local toggleTrails = true -- Toggle trails on/off
  25. local toggleForces = true -- Toggle gravitational forces on the circles
  26. local toggleGravity = false -- Toggle gravity of the simulation
  27. -- (Do not Touch) --
  28. local screenW = display.contentWidth
  29. local screenH = display.contentHeight
  30.  
  31. -- (Starting Circle quick settings) --
  32. local customCircles = 1 -- Number of custom starting circles to spawn
  33. local startingCircleBounce = 0.25 -- Elasticity of the circle
  34. local startingCircleXpos = screenW/2 -- Center of screen
  35. local startingCircleYpos = screenH/2
  36. local startingCircleRadius = 50 -- Size of circle
  37. local startingCircleMass = 500 -- Mass of circle
  38. local startingColorR = 255 -- Red value (Maximum 255)
  39. local startingColorG = 255 -- Green value (Maximum 255)
  40. local startingColorB = 255 -- Blue value (Maximum 255)
  41.  
  42.     ----> | Main Program | <----
  43.  
  44. -- Initialize physics
  45. local physics = require("physics")
  46. physics.start()
  47. if toggleGravity == false then
  48.     physics.setGravity(0, 0) -- Set gravity to 0
  49. end
  50.  
  51. local spheres = {} -- Table to keep track of spheres
  52.  
  53. -- [[ Starting Circle with fixed size & mass for experimentations
  54. local function createCircle(x, y, radius, mass, r, g, b)
  55.     local circle = display.newCircle(x, y, radius)
  56.     -- Prevent color errors
  57.     if startingColorR <= 0 or startingColorR >= 255 then
  58.         startingColorR = 1
  59.     elseif startingColorG <= 0 or startingColorG >= 255 then
  60.         startingColorG = 1
  61.     elseif startingColorB <= 0 or startingColorB >= 255 then
  62.         startingColorB = 1
  63.     end
  64.     circle:setFillColor(startingColorR, startingColorG, startingColorB)
  65.     physics.addBody(circle, {radius=radius, density=mass/(math.pi*radius*radius), bounce=startingCircleBounce})
  66.     circle.mass = mass
  67.     table.insert(spheres, circle)
  68.  
  69.     -- Combined function with improved throwing and double-click locking mechanism
  70.     function circle:touch(event)
  71.         if event.phase == "began" then
  72.             -- Initial touch
  73.             display.getCurrentStage():setFocus(self, event.id)
  74.             self.isFocus = true
  75.             self.markX = self.x
  76.             self.markY = self.y
  77.             self.startTime = system.getTimer()
  78.             self.movementHistory = {}
  79.             -- Stop the sphere's movement (only if not locked)
  80.             if not self.isLocked then
  81.                 self:setLinearVelocity(0, 0)
  82.                 self.angularVelocity = 0
  83.             end
  84.         elseif self.isFocus then
  85.             if event.phase == "moved" then
  86.                 -- Dragging (only if not locked)
  87.                 if not self.isLocked then
  88.                     self.x = event.x - event.xStart + self.markX
  89.                     self.y = event.y - event.yStart + self.markY
  90.                     -- Record movement history
  91.                     table.insert(self.movementHistory, {time = system.getTimer(), x = event.x, y = event.y})
  92.                     -- Clean up old movement history
  93.                     local currentTime = system.getTimer()
  94.                     local cutOffTime = currentTime - (velocityRate*1000)
  95.                     for i, record in ipairs(self.movementHistory) do
  96.                         if record.time < cutOffTime then
  97.                             table.remove(self.movementHistory, i)
  98.                         end
  99.                     end
  100.                 end
  101.             elseif event.phase == "ended" or event.phase == "cancelled" then
  102.                 if not self.isLocked then  -- Don't apply a throw if locked
  103.                     -- Released
  104.                     local endTime = system.getTimer()
  105.                     local distance = 0
  106.                     local throwForce = 0
  107.                     local timeDiff = 0
  108.                     if #self.movementHistory >= 2 then
  109.                         local lastRecord = self.movementHistory[#self.movementHistory]
  110.                         local prevRecord = self.movementHistory[#self.movementHistory - 1]
  111.                         distance = math.sqrt((lastRecord.x - prevRecord.x) ^ 2 + (lastRecord.y - prevRecord.y) ^ 2)
  112.                         timeDiff = lastRecord.time - prevRecord.time
  113.                         throwForce = distance * throwAmplifier / timeDiff
  114.                         -- Apply decay to the throw force to simulate energy loss
  115.                         throwForce = throwForce * math.exp(-timeDiff * dampingAmplifier)
  116.                         local vx = (event.x - self.markX) * throwForce
  117.                         local vy = (event.y - self.markY) * throwForce
  118.                         self:applyLinearImpulse(vx, vy, self.x, self.y)
  119.                     end
  120.                 end
  121.                 display.getCurrentStage():setFocus(self, nil)
  122.                 self.isFocus = false
  123.             end
  124.         elseif event.phase == "ended" and not self.isFocus then
  125.             -- Detect double click
  126.             if self.lastClickTime and (system.getTimer() - self.lastClickTime) < 300 then
  127.                 -- Double click detected within 300 milliseconds
  128.                 self.isLocked = not self.isLocked
  129.                 self.body:setType(self.isLocked and "static" or "dynamic")
  130.                 self.lastClickTime = nil
  131.             else
  132.                 -- Single click, start timer
  133.                 self.lastClickTime = system.getTimer()
  134.             end
  135.         end
  136.         return true
  137.     end
  138.    
  139.     circle:addEventListener("touch", circle)
  140.     return circle
  141. end
  142. --]]
  143. -- Function to spawn multiple starting circles
  144. local function spawnStartingCircles()
  145.     if customCircles <= 0 then -- Prevents negative starting circles
  146.         customCircles = 1
  147.     end
  148.     if startingCircleRadius <= 0 then -- Prevents negative radius
  149.         startingCircleRadius = 25
  150.     end
  151.     for i = 1, (customCircles-1) do
  152.         local xPosition = math.random(startingCircleRadius, screenW - startingCircleRadius)
  153.         local yPosition = math.random(startingCircleRadius, screenH - startingCircleRadius)
  154.         createCircle(xPosition, yPosition, startingCircleRadius, startingCircleMass)
  155.     end
  156. end
  157. -- Function to create a new sphere with a random color and trail
  158. local function createSphere(x, y, radius, mass)
  159.     -- Random color components
  160.     local r = math.random()
  161.     local g = math.random()
  162.     local b = math.random()
  163.  
  164.     local sphere = display.newCircle(x, y, radius)
  165.     sphere:setFillColor(r, g, b) -- Set the random color
  166.     physics.addBody(sphere, {radius=radius, density=mass/(math.pi*radius*radius), bounce=randomCirclesBounce})
  167.     sphere.mass = mass
  168.     table.insert(spheres, sphere)
  169.  
  170.     -- [[ Trail effect
  171.     if toggleTrails == true then
  172.         local trailGroup = display.newGroup()
  173.  
  174.         function sphere:enterFrame(event)
  175.             local trail = display.newCircle(trailGroup, self.x, self.y, radius * trailSize)
  176.             trail:setFillColor(r, g, b, trailOpaqueness) -- Slightly transparent version of the sphere's color
  177.             transition.to(trail, {time=(trailLifeTime*1000), alpha=trailGradient, onComplete=function() display.remove(trail) end})
  178.         end
  179.     elseif toggleTrails == false then
  180.         trailGradient = 1
  181.         trailLifeTime = 0
  182.         trailOpaqueness = 0
  183.         trailSize = 0
  184.     end
  185.     --]]
  186.     Runtime:addEventListener("enterFrame", sphere)
  187.  
  188.     -- Combined function with improved throwing and double-click locking mechanism
  189.     function sphere:touch(event)
  190.         if event.phase == "began" then
  191.             -- Initial touch
  192.             display.getCurrentStage():setFocus(self, event.id)
  193.             self.isFocus = true
  194.             self.markX = self.x
  195.             self.markY = self.y
  196.             self.startTime = system.getTimer()
  197.             self.movementHistory = {}
  198.             -- Stop the sphere's movement (only if not locked)
  199.             if not self.isLocked then
  200.                 self:setLinearVelocity(0, 0)
  201.                 self.angularVelocity = 0
  202.             end
  203.         elseif self.isFocus then
  204.             if event.phase == "moved" then
  205.                 -- Dragging (only if not locked)
  206.                 if not self.isLocked then
  207.                     self.x = event.x - event.xStart + self.markX
  208.                     self.y = event.y - event.yStart + self.markY
  209.                     -- Record movement history
  210.                     table.insert(self.movementHistory, {time = system.getTimer(), x = event.x, y = event.y})
  211.                     -- Clean up old movement history
  212.                     local currentTime = system.getTimer()
  213.                     local cutOffTime = currentTime - (velocityRate*1000)
  214.                     for i, record in ipairs(self.movementHistory) do
  215.                         if record.time < cutOffTime then
  216.                             table.remove(self.movementHistory, i)
  217.                         end
  218.                     end
  219.                 end
  220.             elseif event.phase == "ended" or event.phase == "cancelled" then
  221.                 if not self.isLocked then  -- Don't apply a throw if locked
  222.                     -- Released
  223.                     local endTime = system.getTimer()
  224.                     local distance = 0
  225.                     local throwForce = 0
  226.                     local timeDiff = 0
  227.                     if #self.movementHistory >= 2 then
  228.                         local lastRecord = self.movementHistory[#self.movementHistory]
  229.                         local prevRecord = self.movementHistory[#self.movementHistory - 1]
  230.                         distance = math.sqrt((lastRecord.x - prevRecord.x) ^ 2 + (lastRecord.y - prevRecord.y) ^ 2)
  231.                         timeDiff = lastRecord.time - prevRecord.time
  232.                         throwForce = distance * throwAmplifier / timeDiff
  233.                         -- Apply decay to the throw force to simulate energy loss
  234.                         throwForce = throwForce * math.exp(-timeDiff * dampingAmplifier)
  235.                         local vx = (event.x - self.markX) * throwForce
  236.                         local vy = (event.y - self.markY) * throwForce
  237.                         self:applyLinearImpulse(vx, vy, self.x, self.y)
  238.                     end
  239.                 end
  240.                 display.getCurrentStage():setFocus(self, nil)
  241.                 self.isFocus = false
  242.             end
  243.         elseif event.phase == "ended" and not self.isFocus then
  244.             -- Detect double click
  245.             if self.lastClickTime and (system.getTimer() - self.lastClickTime) < 300 then
  246.                 -- Double click detected within 300 milliseconds
  247.                 self.isLocked = not self.isLocked
  248.                 self.body:setType(self.isLocked and "static" or "dynamic")
  249.                 self.lastClickTime = nil
  250.             else
  251.                 -- Single click, start timer
  252.                 self.lastClickTime = system.getTimer()
  253.             end
  254.         end
  255.         return true
  256.     end
  257.  
  258.     sphere:addEventListener("touch", sphere)
  259.     return sphere
  260. end
  261.  
  262. -- [[ Function to update gravitational forces
  263. local function updateGravity()
  264.     for i = 1, #spheres do
  265.         for j = i+1, #spheres do
  266.             local sphere1 = spheres[i]
  267.             local sphere2 = spheres[j]
  268.             local dx = sphere2.x - sphere1.x
  269.             local dy = sphere2.y - sphere1.y
  270.             local distance = math.sqrt(dx*dx + dy*dy)
  271.             local force = (sphere1.mass * sphere2.mass) / (distance * distance)
  272.             local forceX = force * (dx / distance)
  273.             local forceY = force * (dy / distance)
  274.            
  275.             sphere1:applyForce(forceX, forceY, sphere1.x, sphere1.y)
  276.             sphere2:applyForce(-forceX, -forceY, sphere2.x, sphere2.y)
  277.         end
  278.     end
  279. end
  280. --]]
  281. -- Create screen boundaries that fit any screen size
  282. local function createWalls()
  283.     local leftWall = display.newRect(display.screenOriginX, display.contentCenterY, 1, display.actualContentHeight)
  284.     local rightWall = display.newRect(display.actualContentWidth + display.screenOriginX, display.contentCenterY, 1, display.actualContentHeight)
  285.     local topWall = display.newRect(display.contentCenterX, display.screenOriginY, display.actualContentWidth, 1)
  286.     local bottomWall = display.newRect(display.contentCenterX, display.actualContentHeight + display.screenOriginY, display.actualContentWidth, 1)
  287.    
  288.     physics.addBody(leftWall, "static")
  289.     physics.addBody(rightWall, "static")
  290.     physics.addBody(topWall, "static")
  291.     physics.addBody(bottomWall, "static")
  292. end
  293.  
  294. -- Function to create a Portal-like wrap-around effect
  295. local function wrapAroundScreen(object)
  296.     local buffer = object.width * wrapBuffer -- Buffer to ensure the circle is fully off-screen before wrapping
  297.     local leftBoundary = display.screenOriginX
  298.     local rightBoundary = display.actualContentWidth + display.screenOriginX
  299.     local topBoundary = display.screenOriginY
  300.     local bottomBoundary = display.actualContentHeight + display.screenOriginY
  301.  
  302.     -- Check if any part of the object is beyond the screen boundary
  303.     if object.x - buffer > rightBoundary then
  304.         object.x = leftBoundary - buffer + (object.x - buffer - rightBoundary)
  305.     elseif object.x + buffer < leftBoundary then
  306.         object.x = rightBoundary + buffer - (leftBoundary - (object.x + buffer))
  307.     end
  308.     if object.y - buffer > bottomBoundary then
  309.         object.y = topBoundary - buffer + (object.y - buffer - bottomBoundary)
  310.     elseif object.y + buffer < topBoundary then
  311.         object.y = bottomBoundary + buffer - (topBoundary - (object.y + buffer))
  312.     end
  313. end
  314.  
  315. -- Background touch listener for panning
  316. local function backgroundTouch(event)
  317.     local background = event.target
  318.     if event.phase == "began" then
  319.         -- Double-click detection
  320.         if background.lastClickTime and (system.getTimer() - background.lastClickTime) < 300 then
  321.             -- Begin panning
  322.             background.isPanning = true
  323.             background.startX = event.x - background.x
  324.             background.startY = event.y - background.y
  325.         end
  326.         background.lastClickTime = system.getTimer()
  327.     elseif event.phase == "moved" then
  328.         if background.isPanning then
  329.             -- Perform panning
  330.             background.x = event.x - background.startX
  331.             background.y = event.y - background.startY
  332.         end
  333.     elseif event.phase == "ended" or event.phase == "cancelled" then
  334.         background.isPanning = false
  335.     end
  336.     return true
  337. end
  338.  
  339. -- Modify the enterFrame event to include the Portal-like wrap-around logic
  340. local function onEnterFrame(event)
  341.     for _, sphere in ipairs(spheres) do
  342.         wrapAroundScreen(sphere)
  343.     end
  344.     --[[
  345.     updateGravity() -- Keep the original gravity update logic if needed
  346.     --]]
  347. end
  348.  
  349. -- Function to generate a random number of circles with random properties
  350. local function generateRandomCircles()
  351.     -- Prevent weird math from occuring
  352.     if radiusMin <= 0 then
  353.         radiusMin = 10
  354.     elseif radiusMax <= radiusMin or radiusMax <= 0 then
  355.         radiusMax = 20
  356.     end
  357.     local numCircles = numRandomCircles -- Random number of circles
  358.     for i = 1, numCircles do
  359.         local radius = (math.random(radiusMin, radiusMax))*scale -- Random radius
  360.         local mass = (radius * circleMass)*scale -- Mass proportional to radius, adjust as needed
  361.         local x = math.random(radius, screenW - radius) -- Random x position, ensuring circle stays on screen
  362.         local y = math.random(radius, screenH - radius) -- Random y position, ensuring circle stays on screen
  363.         createSphere(x, y, radius, mass)
  364.     end
  365. end
  366.  
  367. -- Togglable Functions
  368. -- Call the function to generate random circles
  369. if toggleRandomCircles == true then
  370.     generateRandomCircles()
  371. end
  372. -- Create walls
  373. if toggleWalls == true then
  374.     createWalls() -- Disable for portal-like wrapping
  375. end
  376. -- Create starting circle
  377. if toggleStartingCircle == true then
  378.     createCircle(startingCircleXpos, startingCircleYpos, startingCircleRadius, startingCircleMass)
  379. end
  380. -- Call the function to spawn the starting circles
  381. if toggleCustomCircles == true then
  382.     spawnStartingCircles()
  383. end
  384. -- Update gravity every frame
  385. if toggleForces == true then
  386.     Runtime:addEventListener("enterFrame", updateGravity)
  387. end
  388. -- [[ Object wrapping (Infinite space)
  389. if toggleBodyWrap == true then
  390.     Runtime:addEventListener("enterFrame", onEnterFrame)
  391. end
  392.  
  393.     ----< | End of Main Program | >----
  394.  
  395. print("Orbit Beta v1.2.3 May 8 2024 Edition has initialized. Updates are available on the Pastbin: https://pastebin.com/qixBZPLH")
  396.  
  397. -- [ This code primarily uses Lua and runs on Solar2D or Corona Simulator 2024. This program is not yet an application and is still in prototype stages. Updates will occasionally be made with additional features and debugging. ] --
Tags: archive
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement