Hello! In my project, I have a rectangular prism part that interacts with the world and acts as something of a vehicle hitbox. I also have a union operation that looks like a scooter and is just decoration, per say since it does not interact with the world; it is just constrained to the rectangular prism (which is invisible). I want to add something of a tilt effect so when the rectangular prism turns, the union operation tilts in the direction the rectangular prism is turning. I already have the information necessary to detect when the rectangular prism is turning; I just need to make it turn. I will also note that I am using an AlignOrientation constraint to handle the orientation of the rectangular prism, but for some reason it requires that the PrimaryAxes of both the rectangular prism attachment and union operation attachment are <1, 0, 0>. I tried using a HingeConstraint, but to make the union operation tilt on the correct axes, the PrimaryAxes of both aforementioned attachments need to be <0, 0, -1>. This messes with the AlignOrientation constraint and does not allow the scooter to move correctly. How can I add the tilt effect, preferably with constraints, so that the union operation tilts appropriately?
In case it helps:
Code that handles tilting the union operation (scooterAppearance) with HingeConstraint
Function that updates scooter tilt (called every frame)
local function updateScooterTilt(deltaTime: number)
local neutralState: CFrame = scooterPhysicsBox.CFrame + scooterPhysicsBox.CFrame.UpVector * appearanceOffsetFromPhysicsBox
local currentTurnDirection: string = scooter:GetAttribute("turnDirection")
if not scooter:GetAttribute("isGrounded") or currentTurnDirection == turnDirections.none then
--scooterTiltConstraint.TargetAngle = 0
scooterAppearance.CFrame = scooterAppearance.CFrame:Lerp(neutralState, coordinateFrameInterpolationAlpha * deltaTime)
elseif currentTurnDirection == turnDirections.right then
--scooterTiltConstraint.TargetAngle = -math.deg(maxTiltAngle)
scooterAppearance.CFrame = scooterAppearance.CFrame:Lerp(neutralState * CFrame.Angles(0, 0, -maxTiltAngle), coordinateFrameInterpolationAlpha * deltaTime)
elseif currentTurnDirection == turnDirections.left then
--scooterTiltConstraint.TargetAngle = math.deg(maxTiltAngle)
scooterAppearance.CFrame = scooterAppearance.CFrame:Lerp(neutralState * CFrame.Angles(0, 0, maxTiltAngle), coordinateFrameInterpolationAlpha * deltaTime)
end
end
Code that handles orienting the rectangular prism (scooterPhysicsModel)
Helper function to calculate reorientation angle given alignment vector
local function calculateReorientationAngle(alignment: Vector3): number
return math.acos(prism.CFrame.UpVector:Dot(alignment))
end
Helper function to calculate reorientation axis given alignment vector and angle
local function determineReorientationAxis(alignment: Vector3, angle: number): Vector3
local axis = nil
if angle < 0.00001 or angle > math.pi + 0.00001 then
axis = Vector3.xAxis
else
axis = prism.CFrame.UpVector:Cross(alignment)
end
return axis
end
Function called every frame to align prism up vector w/ surface normal
local function updateScooterOrientation()
local targetCFrame: CFrame = scooterPhysicsBox.CFrame
if surfaceNormal then
local angle = calculateReorientationAngle(surfaceNormal)
local axis = determineReorientationAxis(surfaceNormal, angle)
targetCFrame = CFrame.fromAxisAngle(axis, angle) * prism.CFrame.Rotation + prism.Position
else
local targetUpVector: Vector3 = Vector3.new(0, 1, 0)
local angle = calculateReorientationAngle(targetUpVector)
local axis = determineReorientationAxis(targetUpVector, angle)
targetCFrame = CFrame.fromAxisAngle(axis, angle) * prism.CFrame.Rotation + prism.Position
end
alignOrientation.CFrame = targetCFrame
end