Hi I’m trying to figure out how to predict the motion of a regular ball part. I’ve gotten the prediction for the bouncing part of the ball (thanks to this post: Modeling a projectile's motion) but I’m not really sure how to predict the rolling motion of the ball.
This is what I have for my code so far:
local BallSimulation = {}
BallSimulation.__index = BallSimulation
local function reflect(velocity, normal)
return -2 * velocity:Dot(normal) * normal + velocity
end
local function angularToLinear(w0, r)
return w0:Cross(Vector3.new(0, r, 0))
end
local function linearToAngular(v0, r)
return Vector3.new(0, r, 0):Cross(v0) / (r * r)
end
function BallSimulation.new(radius, gravity, raycastParams)
local self = setmetatable({}, BallSimulation)
self.gravity = gravity
self.radius = radius
self.timeStep = 1/240
self.maxBounceInterval = 10
self.raycastParams = raycastParams
self.material = Enum.Material.Plastic
return self
end
-- Rolling
function BallSimulation:getAcceleration(p0)
local result = workspace:Raycast(p0, p0 - Vector3.new(0, self.radius, 0), self.raycastParams)
if result then
local normal = result.Normal
local gravityComponent = self.gravity:Dot(normal)
return self.gravity - normal * gravityComponent
end
return self.gravity
end
function BallSimulation:nextVelocity(v0, a)
return a * self.timeStep + v0
end
function BallSimulation:nextPosition(p0, v0, a)
return 0.5 * a * self.timeStep * self.timeStep + v0 * self.timeStep + p0
end
function BallSimulation:nextStep(p0, v0)
local a = self:getAcceleration(p0)
local p1 = self:nextPosition(p0, v0, a)
local v1 = self:nextVelocity(v0, a)
local direction = p1 - p0
local result = workspace:Raycast(p0, direction + direction.Unit * self.radius, self.raycastParams)
if result then
local nextPosition = result.Position + result.Normal * self.radius
local pA = PhysicalProperties.new(self.material)
local pB = PhysicalProperties.new(result.Material)
local normal = result.Normal
local elast = (pA.Elasticity*pA.ElasticityWeight + pB.Elasticity*pB.ElasticityWeight)/(pA.ElasticityWeight+pB.ElasticityWeight)
local frict = (pA.Friction*pA.FrictionWeight + pB.Friction*pB.FrictionWeight)/(pA.FrictionWeight+pB.FrictionWeight)
local dot = 1 - math.abs(v0.Unit:Dot(normal))
local nextVelocity = reflect(v1, normal) * elast + v0 * frict * dot
return nextPosition, nextVelocity
end
return p1, v1
end
-- Simulate
function BallSimulation:Simulate(p0, v0)
local pA = PhysicalProperties.new(self.material)
local path = {}
for i = 1, 1000 do
local p1, v1 = self:nextStep(p0, v0)
table.insert(path, {p0, v0})
p0, v0 = p1, v1
end
for i = 1, 1000, 10 do
local ball = Instance.new("Part")
ball.Shape = Enum.PartType.Ball
ball.Size = Vector3.one * 4
ball.Transparency = 0.9
ball.Color = Color3.fromRGB(255, 0, 0)
ball.Material = Enum.Material.Neon
ball.CanCollide = false
ball.Anchored = true
ball.Position = path[i][1]
ball.Parent = workspace.Balls
end
return path
end
return BallSimulation
As you can see above, when the ball should be rolling, what happens instead is the ball just keeps bouncing up and down and losing speed due to the elasticity coefficient.
I appreciate any help!