Advertisement
YourMain12

Realistic Physics Engine

Jul 17th, 2023 (edited)
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.71 KB | None | 0 0
  1. Particle = {}
  2. Particle.__index = Particle
  3.  
  4. function Particle.new(x, y, mass)
  5.     local self = setmetatable({}, Particle)
  6.     self.position = {x = x, y = y}
  7.     self.velocity = {x = 0, y = 0}
  8.     self.force = {x = 0, y = 0}
  9.     self.mass = mass
  10.     self.radius = math.sqrt(mass) * 10
  11.     self.color = {r = love.math.random(), g = love.math.random(), b = love.math.random()}
  12.     self.lifetime = love.math.random(1, 5)
  13.     self.timer = self.lifetime
  14.     return self
  15. end
  16.  
  17. function Particle:applyForce(force)
  18.     self.force.x = self.force.x + force.x
  19.     self.force.y = self.force.y + force.y
  20. end
  21.  
  22. function Particle:update(dt)
  23.     local acceleration = {x = self.force.x / self.mass, y = self.force.y / self.mass}
  24.     self.velocity.x = self.velocity.x + acceleration.x * dt
  25.     self.velocity.y = self.velocity.y + acceleration.y * dt
  26.     self.position.x = self.position.x + self.velocity.x * dt
  27.     self.position.y = self.position.y + self.velocity.y * dt
  28.     self.force.x = 0
  29.     self.force.y = 0
  30.  
  31.     self.timer = self.timer - dt
  32. end
  33.  
  34. PhysicsEngine = {}
  35. PhysicsEngine.__index = PhysicsEngine
  36.  
  37. function PhysicsEngine.new()
  38.     local self = setmetatable({}, PhysicsEngine)
  39.     self.particles = {}
  40.     return self
  41. end
  42.  
  43. function PhysicsEngine:addParticle(particle)
  44.     table.insert(self.particles, particle)
  45. end
  46.  
  47. function PhysicsEngine:update(dt)
  48.     for i = #self.particles, 1, -1 do
  49.         local particle = self.particles[i]
  50.         particle:applyForce({x = 0, y = particle.mass * 9.8})
  51.         particle:update(dt)
  52.         self:applyBoundary(particle)
  53.         self:applyDrag(particle)
  54.  
  55.         if particle.timer <= 0 then
  56.             table.remove(self.particles, i)
  57.         end
  58.     end
  59. end
  60.  
  61. function PhysicsEngine:applyBoundary(particle)
  62.     local bounce = 0.8
  63.     local radius = particle.radius
  64.  
  65.     if particle.position.x < radius then
  66.         particle.position.x = radius
  67.         particle.velocity.x = -particle.velocity.x * bounce
  68.     elseif particle.position.x > love.graphics.getWidth() - radius then
  69.         particle.position.x = love.graphics.getWidth() - radius
  70.         particle.velocity.x = -particle.velocity.x * bounce
  71.     end
  72.  
  73.     if particle.position.y < radius then
  74.         particle.position.y = radius
  75.         particle.velocity.y = -particle.velocity.y * bounce
  76.     elseif particle.position.y > love.graphics.getHeight() - radius then
  77.         particle.position.y = love.graphics.getHeight() - radius
  78.         particle.velocity.y = -particle.velocity.y * bounce
  79.     end
  80. end
  81.  
  82. function PhysicsEngine:applyDrag(particle)
  83.     local dragCoefficient = 0.01
  84.     local dragForce = {
  85.         x = -particle.velocity.x * dragCoefficient,
  86.         y = -particle.velocity.y * dragCoefficient
  87.     }
  88.     particle:applyForce(dragForce)
  89. end
  90.  
  91. function PhysicsEngine:applyGravity(mass)
  92.     for _, particle in ipairs(self.particles) do
  93.         local force = {x = 0, y = particle.mass * mass}
  94.         particle:applyForce(force)
  95.     end
  96. end
  97.  
  98. function PhysicsEngine:applyAttraction(targetParticle, G)
  99.     for _, particle in ipairs(self.particles) do
  100.         if particle ~= targetParticle then
  101.             local direction = {
  102.                 x = targetParticle.position.x - particle.position.x,
  103.                 y = targetParticle.position.y - particle.position.y
  104.             }
  105.             local distance = math.sqrt(direction.x ^ 2 + direction.y ^ 2)
  106.             local magnitude = G * particle.mass * targetParticle.mass / (distance ^ 2)
  107.             direction.x = direction.x / distance
  108.             direction.y = direction.y / distance
  109.             local force = {x = direction.x * magnitude, y = direction.y * magnitude}
  110.             particle:applyForce(force)
  111.         end
  112.     end
  113. end
  114.  
  115. function PhysicsEngine:applyCollisionDetection()
  116.     for i = 1, #self.particles - 1 do
  117.         local particleA = self.particles[i]
  118.         for j = i + 1, #self.particles do
  119.             local particleB = self.particles[j]
  120.             self:checkCollision(particleA, particleB)
  121.         end
  122.     end
  123. end
  124.  
  125. function PhysicsEngine:checkCollision(particleA, particleB)
  126.     local direction = {
  127.         x = particleB.position.x - particleA.position.x,
  128.         y = particleB.position.y - particleA.position.y
  129.     }
  130.     local distance = math.sqrt(direction.x ^ 2 + direction.y ^ 2)
  131.     local combinedRadius = particleA.radius + particleB.radius
  132.  
  133.     if distance < combinedRadius then
  134.         local overlap = combinedRadius - distance
  135.         local displacement = {
  136.             x = direction.x / distance * overlap * 0.5,
  137.             y = direction.y / distance * overlap * 0.5
  138.         }
  139.  
  140.         particleA.position.x = particleA.position.x - displacement.x
  141.         particleA.position.y = particleA.position.y - displacement.y
  142.         particleB.position.x = particleB.position.x + displacement.x
  143.         particleB.position.y = particleB.position.y + displacement.y
  144.  
  145.         self:resolveCollision(particleA, particleB, direction)
  146.     end
  147. end
  148.  
  149. function PhysicsEngine:resolveCollision(particleA, particleB, direction)
  150.     local relativeVelocity = {
  151.         x = particleB.velocity.x - particleA.velocity.x,
  152.         y = particleB.velocity.y - particleA.velocity.y
  153.     }
  154.  
  155.     local velocityAlongNormal = direction.x * relativeVelocity.x + direction.y * relativeVelocity.y
  156.  
  157.     if velocityAlongNormal > 0 then
  158.         return
  159.     end
  160.  
  161.     local restitution = 0.8
  162.     local impulseMagnitude = -(1 + restitution) * velocityAlongNormal
  163.     impulseMagnitude = impulseMagnitude / (1 / particleA.mass + 1 / particleB.mass)
  164.  
  165.     local impulse = {
  166.         x = impulseMagnitude * direction.x,
  167.         y = impulseMagnitude * direction.y
  168.     }
  169.  
  170.     particleA.velocity.x = particleA.velocity.x - impulse.x / particleA.mass
  171.     particleA.velocity.y = particleA.velocity.y - impulse.y / particleA.mass
  172.  
  173.     particleB.velocity.x = particleB.velocity.x + impulse.x / particleB.mass
  174.     particleB.velocity.y = particleB.velocity.y + impulse.y / particleB.mass
  175. end
  176.  
  177. for i = 1, numParticles do
  178.     local mass = love.math.random(1, 5)
  179.     local x = love.math.random(50, love.graphics.getWidth() - 50)
  180.     local y = love.math.random(50, love.graphics.getHeight() - 50)
  181.     local particle = Particle.new(x, y, mass)
  182.     physics:addParticle(particle)
  183. end
  184.  
  185. function love.update(dt)
  186.     physics:update(dt)
  187.     physics:applyCollisionDetection()
  188.     physics:applyGravity(9.8)
  189.     physics:applyAttraction(physics.particles[attractionParticleIndex], 10)
  190. end
  191.  
  192. function love.draw()
  193.     for _, particle in ipairs(physics.particles) do
  194.         love.graphics.setColor(particle.color.r, particle.color.g, particle.color.b, particle.timer / particle.lifetime)
  195.         love.graphics.circle("fill", particle.position.x, particle.position.y, particle.radius)
  196.     end
  197. end
  198.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement