Hello, I’m currently struggling attempting to find a solution to make my hovercar suspension more stable.
Currently, even a slight nudge will cause the vehicle to move quickly into the abyss. I would appreciate any help proposed solution this issue.
A demonstraction:
https://gyazo.com/a486231d6d27598e8440eaa05458c45e
As you can see, the suspension tries to correct the orientation, but to of no success.
Here is the module responsible for the physics component of my hovercar class:
-- physics
-- UntitledProtocol
-- November 29, 2020
local physics = {}
local mt = {__index = physics}
local function make_force(force_name, parent_instance)
local attachement = Instance.new("Attachment")
attachement.Orientation = Vector3.new(0,0,0)
attachement.Position = parent_instance.Position
attachement.Parent = parent_instance
local force = Instance.new(force_name)
force.Force = Vector3.new(0, 0, 0)
force.Attachment0 = attachement
force.ApplyAtCenterOfMass = true
force.RelativeTo = Enum.ActuatorRelativeTo.Attachment0
force.Parent = parent_instance
return force
end
function physics.create(model, props)
local self = setmetatable({}, mt)
self.__model = model
self.__props = props
self.__contractions = {}
-- Set up some constants for the suspension:
local individual_mass = self.__model.com:GetMass() / #self.__model.suspension_points:GetChildren() -- mass divided by amount of suspension_points
self.__spring_constant = individual_mass * workspace.Gravity + self.__props.spring_constant
self.__damping_coefficient = 2 * (individual_mass * self.__spring_constant) ^ 0.5 -- find damping coefficient (critical damping) : 2 * sqrt(springConst * mass)
-- Create a force for each of the suspensionPoints
self.__suspension_forces = {}
for _, v in ipairs(model.suspension_points:GetChildren()) do
self.__suspension_forces[v] = make_force("VectorForce", v)
end
return self
end
function physics:__update(delta)
self:__handle_suspension(delta)
end
function physics:__handle_suspension(delta)
for part, force_object in pairs(self.__suspension_forces) do
-- find how much the suspension has contracted:
local was_grounded, height_from_ground = self:__get_height_off_ground(part)
if not was_grounded then
force_object.Force = Vector3.new(0,0,0)
return
end
local contraction = self.__props.suspension_height - height_from_ground
if not self.__contractions[part] then
self.__contractions[part] = contraction
end
-- calculate derivative:
local dx = (contraction - self.__contractions[part]) / delta
self.__contractions[part] = contraction
-- find force:
local f = self.__spring_constant * contraction + dx * self.__damping_coefficient
-- apply:
force_object.Force = Vector3.new(0, f, 0)
end
end
function physics:__get_height_off_ground(part)
if not self.__raycast_params then
local p = RaycastParams.new()
p.FilterDescendantsInstances = {self.__model}
p.FilterType = Enum.RaycastFilterType.Blacklist
self.__raycast_params = p
end
local origin_cf = part.CFrame * CFrame.new(0, -part.size.Y / 2, 0)
local destination_cf = origin_cf * CFrame.new(0, -self.__props.suspension_height, 0)
local direction = destination_cf.Position - origin_cf.Position
local raycast_result = workspace:Raycast(origin_cf.Position, direction, self.__raycast_params)
if raycast_result then
return true, (origin_cf.Position - raycast_result.Position).Magnitude
end
end
return physics