Something like in the images, but by script, I researched a lot in the dev forum but I only found stuff about rotating in an object in world space or its own, nothing about rotating in another object’s space.
I also tried doing:
local partA = workspace.partA
local partB = workspace.partB
partA.CFrame = (partA.CFrame * CFrame.Angles(math.rad(45), 0, 0)):ToObjectSpace(partB.CFrame)
However, although I gave this example with parts I’m actually trying to do this with motor6Ds, I used this tutorial:
to make my character’s torso rotate and it works but I have some animations that rotate the upper and lower torso, thus, the waist C0 must rotate on the HumanoidRootPart’s space because it’s the only body part that is always facing where the camera is facing:
local neckC0 = CFrame.new(0, 0.8, 0)
local waistC0 = CFrame.new(0, 0.2, 0)
tilt.OnServerEvent:Connect(function(player, angle)
local tiltMotor = player.Character.Head:FindFirstChild("tiltCharacter")
if not tiltMotor then return end
tiltMotor.DesiredAngle = angle
end)
setup.OnServerEvent:Connect(function(player)
local character = player.Character
local tiltMotor = character.Head.tiltCharacter
local neck = character.Head.Neck
local waist = character.UpperTorso.Waist
runService.Heartbeat:Connect(function()
local angle = tiltMotor.CurrentAngle
neck.C0 = neckC0 * CFrame.Angles(angle * 0.45, 0, 0)
if math.deg(angle) > 45 or math.deg(angle) < -60 then return end
waist.C0 = waistC0 * CFrame.Angles(angle, 0, 0)
end)
end)
Tilt is fired in time intervals, and “setup” is called when a player is added.
edit: when I try to apply the same logic as the parts, changing:
converting everything to orientation and degrees, this CFrame is correct, but when applying to waist.C0 it goes to the local space of upperTorso or lowerTorso (?), how can I apply rotation to the motor waist in world space?
EDIT: only in this case, where CFrame.fromAxisAngle(rootPart.CFrame.XVector, angle) is mostly on Z, if I turn my character to face global X then those prints on output change form ~-0, ~0, rotationAmount to rotationAmount, ~0, ~0, but it always should be in global space.
The rotation printed should be applied in world space, when I apply it in a C0 the effect on the image above happens (not intended, and varies depending on where the character is facing) because it’s not really rotating on world space.
code:
local neckC0 = CFrame.new(0, 0.8, 0)
local waistC0 = CFrame.new(0, 0.2, 0)
tilt.OnServerEvent:Connect(function(player, angle)
local tiltMotor = player.Character.Head:FindFirstChild("tiltCharacter")
if not tiltMotor then return end
tiltMotor.DesiredAngle = angle
end)
startReplicating.OnServerEvent:Connect(function(player)
local character = player.Character
local tiltMotor = character.Head.tiltCharacter
local neck = character.Head.Neck
local waist = character.UpperTorso.Waist
local rootPart = character.HumanoidRootPart
runService.Heartbeat:Connect(function()
local angle = tiltMotor.CurrentAngle
neck.C0 = neckC0 * CFrame.Angles(angle * 0.45, 0, 0)
if math.deg(angle) > 45 or math.deg(angle) < -60 then return end
local rotation = CFrame.fromAxisAngle(rootPart.CFrame.XVector, angle)
local x, y, z = rotation:ToEulerAnglesXYZ()
print("x: " .. math.deg(x))
print("y: " .. math.deg(y))
print("z: " .. math.deg(z))
print("-----------------------------")
waist.C0 = waistC0 * rotation
end)
end)
mostly fixes it, but if an animation rotates lower or upper torso it completely messes up, as I explained here:
Giving a better explanation to these images: basically, I want the character’s left arm to always point to humanoidRootPart’s direction, while also considering if the camera is pointing down or up, ignoring the lower and upper torso’s rotation on Y, so:
In image 1: waist is rotated as I want, even though lower and upper torso are rotated on Y, but it works because the camera is facing forward, not up and not down.
In image 2: waist isn’t rotated as I want, it’s rotating the correct amount but on upperTorso’s local Z axis, when I want it to rotate this same amount but on humanoidRootPart’s local Z axis.
I partially understand this happens because c0 is an offset, so applying 45 degrees on Z will be on motor6D.part1’s local Z axis, but I don’t know any way around it.
I played around with it a bit and looks like I’m in the right path, but there are some problems:
changing C0 with C0 = Part0.CFrame:Inverse()*CFrame.lookAt(part1, part2) * C1 to make upperTorso CFrame equal to some CFrame causes this:
and the same old problem:
here’s the current code:
local neckC0 = CFrame.new(0, 0.8, 0)
local waistC0 = CFrame.new(0, 0.2, 0)
tilt.OnServerEvent:Connect(function(player, angle)
local tiltMotor = player.Character.Head:FindFirstChild("tiltCharacter")
if not tiltMotor then return end
tiltMotor.DesiredAngle = angle
end)
startReplicating.OnServerEvent:Connect(function(player)
local character = player.Character
local tiltMotor = character.Head.tiltCharacter
local neck = character.Head.Neck
local waist = character.UpperTorso.Waist
local rootPart = character.HumanoidRootPart
local part0 = waist.Part0
local upperTorso = character.UpperTorso
runService.Heartbeat:Connect(function()
local angle = tiltMotor.CurrentAngle
neck.C0 = neckC0 * CFrame.Angles(angle * 0.45, 0, 0)
if math.deg(angle) > 45 or math.deg(angle) < -60 then return end
local cf = rootPart.CFrame * CFrame.Angles(angle, 0, 0)
waist.C0 = part0.CFrame:Inverse() * cf * waist.C1
end)
end)
Is it even possible to achieve world space rotation with C0s? If not, should I just apply upperTorso.CFrame directly, using an angle from rootPart local X axis? This would mess up torso animations, right?
I know I could use lookAt to make the torso point to camera’s direction using the equation you provided but this would make the left arm point extremely to the left when I want it to point forward.
After some days working on other stuff, I decided to pick this again and I just realized there’s no way to do what I was trying to, C0 will always be on local space.
But what I can do is split rotation on X and Z based on how far away we’re from root part rotation Y to achieve the same effect, if anyone didn’t understand the effect I was talking about here it is:
and here’s the code, just in case future readers need it:
local neckC0 = CFrame.new(0, 0.8, 0)
local waistC0 = CFrame.new(0, 0.2, 0)
tilt.OnServerEvent:Connect(function(player, angle)
local tiltMotor = player.Character.Head:FindFirstChild("tiltCharacter")
if not tiltMotor then return end
tiltMotor.DesiredAngle = angle
end)
startReplicating.OnServerEvent:Connect(function(player)
local character = player.Character
local tiltMotor = character.Head.tiltCharacter
local neck = character.Head.Neck
local waist = character.UpperTorso.Waist
local rootPart = character.HumanoidRootPart
local lowerTorso = character.LowerTorso
local upperTorso = character.UpperTorso
runService.Heartbeat:Connect(function()
local angle = tiltMotor.CurrentAngle
local lX, lY, lZ = lowerTorso.CFrame:ToObjectSpace(rootPart.CFrame):ToEulerAnglesXYZ()
local uX, uY, uZ = upperTorso.CFrame:ToObjectSpace(rootPart.CFrame):ToEulerAnglesXYZ()
local differenceFromRootPartRotationY = (lY + uY)/2
local rotationXratio = 1 - differenceFromRootPartRotationY/math.rad(90)
local rotationZratio = differenceFromRootPartRotationY/math.rad(90)
neck.C0 = neckC0 * CFrame.Angles(angle*.5*rotationXratio, 0, -angle*.5*rotationZratio)
if math.deg(angle) > 45 or math.deg(angle) < -60 then return end
waist.C0 = waistC0 * CFrame.Angles(angle*rotationXratio, 0, -angle*rotationZratio)
end)
end)
lY = lower torso rotation difference from root part on Y, in radians. uY = same thing but for the upper torso.
and the same for other axes, just changing, of course, the respective axis.