Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Particle = {}
- Particle.__index = Particle
- function Particle.new(x, y, mass)
- local self = setmetatable({}, Particle)
- self.position = {x = x, y = y}
- self.velocity = {x = 0, y = 0}
- self.force = {x = 0, y = 0}
- self.mass = mass
- self.radius = math.sqrt(mass) * 10
- self.color = {r = love.math.random(), g = love.math.random(), b = love.math.random()}
- self.lifetime = love.math.random(1, 5)
- self.timer = self.lifetime
- return self
- end
- function Particle:applyForce(force)
- self.force.x = self.force.x + force.x
- self.force.y = self.force.y + force.y
- end
- function Particle:update(dt)
- local acceleration = {x = self.force.x / self.mass, y = self.force.y / self.mass}
- self.velocity.x = self.velocity.x + acceleration.x * dt
- self.velocity.y = self.velocity.y + acceleration.y * dt
- self.position.x = self.position.x + self.velocity.x * dt
- self.position.y = self.position.y + self.velocity.y * dt
- self.force.x = 0
- self.force.y = 0
- self.timer = self.timer - dt
- end
- PhysicsEngine = {}
- PhysicsEngine.__index = PhysicsEngine
- function PhysicsEngine.new()
- local self = setmetatable({}, PhysicsEngine)
- self.particles = {}
- return self
- end
- function PhysicsEngine:addParticle(particle)
- table.insert(self.particles, particle)
- end
- function PhysicsEngine:update(dt)
- for i = #self.particles, 1, -1 do
- local particle = self.particles[i]
- particle:applyForce({x = 0, y = particle.mass * 9.8})
- particle:update(dt)
- self:applyBoundary(particle)
- self:applyDrag(particle)
- if particle.timer <= 0 then
- table.remove(self.particles, i)
- end
- end
- end
- function PhysicsEngine:applyBoundary(particle)
- local bounce = 0.8
- local radius = particle.radius
- if particle.position.x < radius then
- particle.position.x = radius
- particle.velocity.x = -particle.velocity.x * bounce
- elseif particle.position.x > love.graphics.getWidth() - radius then
- particle.position.x = love.graphics.getWidth() - radius
- particle.velocity.x = -particle.velocity.x * bounce
- end
- if particle.position.y < radius then
- particle.position.y = radius
- particle.velocity.y = -particle.velocity.y * bounce
- elseif particle.position.y > love.graphics.getHeight() - radius then
- particle.position.y = love.graphics.getHeight() - radius
- particle.velocity.y = -particle.velocity.y * bounce
- end
- end
- function PhysicsEngine:applyDrag(particle)
- local dragCoefficient = 0.01
- local dragForce = {
- x = -particle.velocity.x * dragCoefficient,
- y = -particle.velocity.y * dragCoefficient
- }
- particle:applyForce(dragForce)
- end
- function PhysicsEngine:applyGravity(mass)
- for _, particle in ipairs(self.particles) do
- local force = {x = 0, y = particle.mass * mass}
- particle:applyForce(force)
- end
- end
- function PhysicsEngine:applyAttraction(targetParticle, G)
- for _, particle in ipairs(self.particles) do
- if particle ~= targetParticle then
- local direction = {
- x = targetParticle.position.x - particle.position.x,
- y = targetParticle.position.y - particle.position.y
- }
- local distance = math.sqrt(direction.x ^ 2 + direction.y ^ 2)
- local magnitude = G * particle.mass * targetParticle.mass / (distance ^ 2)
- direction.x = direction.x / distance
- direction.y = direction.y / distance
- local force = {x = direction.x * magnitude, y = direction.y * magnitude}
- particle:applyForce(force)
- end
- end
- end
- function PhysicsEngine:applyCollisionDetection()
- for i = 1, #self.particles - 1 do
- local particleA = self.particles[i]
- for j = i + 1, #self.particles do
- local particleB = self.particles[j]
- self:checkCollision(particleA, particleB)
- end
- end
- end
- function PhysicsEngine:checkCollision(particleA, particleB)
- local direction = {
- x = particleB.position.x - particleA.position.x,
- y = particleB.position.y - particleA.position.y
- }
- local distance = math.sqrt(direction.x ^ 2 + direction.y ^ 2)
- local combinedRadius = particleA.radius + particleB.radius
- if distance < combinedRadius then
- local overlap = combinedRadius - distance
- local displacement = {
- x = direction.x / distance * overlap * 0.5,
- y = direction.y / distance * overlap * 0.5
- }
- particleA.position.x = particleA.position.x - displacement.x
- particleA.position.y = particleA.position.y - displacement.y
- particleB.position.x = particleB.position.x + displacement.x
- particleB.position.y = particleB.position.y + displacement.y
- self:resolveCollision(particleA, particleB, direction)
- end
- end
- function PhysicsEngine:resolveCollision(particleA, particleB, direction)
- local relativeVelocity = {
- x = particleB.velocity.x - particleA.velocity.x,
- y = particleB.velocity.y - particleA.velocity.y
- }
- local velocityAlongNormal = direction.x * relativeVelocity.x + direction.y * relativeVelocity.y
- if velocityAlongNormal > 0 then
- return
- end
- local restitution = 0.8
- local impulseMagnitude = -(1 + restitution) * velocityAlongNormal
- impulseMagnitude = impulseMagnitude / (1 / particleA.mass + 1 / particleB.mass)
- local impulse = {
- x = impulseMagnitude * direction.x,
- y = impulseMagnitude * direction.y
- }
- particleA.velocity.x = particleA.velocity.x - impulse.x / particleA.mass
- particleA.velocity.y = particleA.velocity.y - impulse.y / particleA.mass
- particleB.velocity.x = particleB.velocity.x + impulse.x / particleB.mass
- particleB.velocity.y = particleB.velocity.y + impulse.y / particleB.mass
- end
- for i = 1, numParticles do
- local mass = love.math.random(1, 5)
- local x = love.math.random(50, love.graphics.getWidth() - 50)
- local y = love.math.random(50, love.graphics.getHeight() - 50)
- local particle = Particle.new(x, y, mass)
- physics:addParticle(particle)
- end
- function love.update(dt)
- physics:update(dt)
- physics:applyCollisionDetection()
- physics:applyGravity(9.8)
- physics:applyAttraction(physics.particles[attractionParticleIndex], 10)
- end
- function love.draw()
- for _, particle in ipairs(physics.particles) do
- love.graphics.setColor(particle.color.r, particle.color.g, particle.color.b, particle.timer / particle.lifetime)
- love.graphics.circle("fill", particle.position.x, particle.position.y, particle.radius)
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement