However I’ve noticed when my goal is set to +/-90 degrees along the Y axis and if the X and Z axis are not set to 0 the part becomes unstable like this. https://gyazo.com/c8772700a1354ca056b0cb0c01716c1a
This is my script and explorer layout.
local RunService = game:GetService("RunService")
local Part = script.Parent
local AngularVelocity = Part.Attachment.AngularVelocity
local GoalAngle = workspace.GoalAngle
AngularVelocity.MaxTorque = math.huge
RunService.Heartbeat:Connect(function()
local goalX, goalY, goalZ = math.rad(GoalAngle.Value.X), math.rad(GoalAngle.Value.Y), math.rad(GoalAngle.Value.Z)
local curX, curY, curZ = Part.CFrame:ToEulerAnglesXYZ()
local diffX, diffY, diffZ = goalX - curX, goalY - curY, goalZ - curZ
AngularVelocity.AngularVelocity = Vector3.new(diffX, diffY, diffZ) * Part.Mass
end)
Doesn’t AlignOrientation already have an option to disable controls on an axis via the following bool setting:
PrimaryAxisOnly If set to true, then the AlignOrientation will only apply torque if the primary axis of its Attachment0 becomes unaligned with Attachment1. This means that any rotation about the Attachment0’s primary axis will not create a torque.
Moreover, you can change the axis of the primary axis by modifying the orientation or CFrame of attachment 0 and attachment 1.
Currently, I believe two things can be wrong with your script.
Rotation axis could be incorrect
Vector3.new(diffX, diffY, diffZ)
Angular velocity needed to apply to the target angles are incorrect and leads to overshooting the goal which leads to the unstable spin. This can be possibly resolved by looking into Proportional-Integral-Derivatives PID like within Aero framework provided in order to adjust the angular velocity in order to adjust the velocity in order to reach the target.
I would suggest visually debugging the issues with these as it’s hard to exactly tell why it’s unstable.
Maybe I can suggest looking into further mimicking what AlignOrientation does which is to find the angle between the attachment axis and applying a rotation in the cross product of that direction which is what I believe after some experimentation in the screenshot below:
But yeah it seems like a lot of work to debug and fix when you can just use AlignOrientation since it already has an option to control the axis of rotation through that bool option.
ToEulerAngles was not reliable enough. This is the solution I found following a ScriptingHelpers post. The modulus statements are for instances when traversing between <-90 and >90 degrees as by default it’ll take the longer route >180 degrees rotation.
local RunService = game:GetService("RunService")
local Part = script.Parent
local AngularVelocity = Part.Attachment.AngularVelocity
local GoalAngle = Part.GoalAngle
AngularVelocity.MaxTorque = math.huge
local pi = math.pi
RunService.Heartbeat:Connect(function()
local goalX, goalY, goalZ = math.rad(GoalAngle.Value.X), math.rad(GoalAngle.Value.Y), math.rad(GoalAngle.Value.Z)
local x, y, z, m00, m01, m02, m10, m11, m12, m20, m21, m22 = Part.CFrame:components()
local curX, curY, curZ = math.asin(-m12), math.atan2(m02, m22), math.atan2(m10, m11)
local diffX, diffY, diffZ = goalX - curX, goalY - curY, goalZ - curZ
if math.abs(diffX) > pi then
diffX %= pi
end
if math.abs(diffY) > pi then
diffY %= pi
end
if math.abs(diffZ) > pi then
diffZ %= pi
end
AngularVelocity.AngularVelocity = Vector3.new(diffX, diffY, diffZ) * Part.Mass
end)