Your solution is really good!
There’s still one (minor) problem, though: I edited your script to test certain things, and I discovered that the rotation isn’t very sharp at high speeds:
I would like to make it as sharp as possible, like this:
Here is my current script (it’s a local script inside StarterCharacterScripts)
local char = script.Parent
local hrp = char:WaitForChild("HumanoidRootPart")
local wedge = workspace:WaitForChild("PartToMove") --wedge is the part I want to rotate around
local randomAxis = Vector3.new(1, 0 ,0)
local rs = game:GetService("RunService")
local function getRotationBetween(u, v, axis)
local dot, uxv = u:Dot(v), u:Cross(v)
if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
end
rs.Heartbeat:Connect(function()
local params = RaycastParams.new()
params.FilterDescendantsInstances = {char}
params.FilterType = Enum.RaycastFilterType.Blacklist
local hit = workspace:Raycast(wedge.Position, -1000 * hrp.CFrame.UpVector, params)
if hit then
local rotateToFloorCFrame = getRotationBetween(hrp.CFrame.UpVector, hit.Normal, randomAxis)
local goalCF = rotateToFloorCFrame * hrp.CFrame
wedge.CFrame = wedge.CFrame:Lerp(goalCF, 1).Rotation + hrp.CFrame.Position
else
wedge.Position = hrp.Position
end
end)
EDIT: Since the cause of the sharpness issue is external and not caused by your code, I’m marking your message as the solution
EDIT 2: I figured out by myself how to fix the issue.
Here is the final code:
local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local head = char:WaitForChild("Head")
local hrp = char:WaitForChild("HumanoidRootPart")
local wedge = workspace:WaitForChild("PartToMove") --wedge is the part I want to rotate around
local randomAxis = Vector3.new(1, 0 ,0)
local rs = game:GetService("RunService")
local uis = game:GetService("UserInputService")
local fast = false
--Bless EgoMoose for his advanced CFrame tutorial on the DevForum! :D https://devforum.roblox.com/t/a-couple-of-advanced-cframe-tricks/337682
local function getRotationBetween(u, v, axis)
local dot, uxv = u:Dot(v), u:Cross(v)
if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
end
rs.RenderStepped:Connect(function()
local camCF = workspace.CurrentCamera.CFrame
--Detect if player is in first person mode or has shift lock enabled.
if (camCF.Position - head.Position).Magnitude < 0.8 or uis.MouseBehavior == Enum.MouseBehavior.LockCenter then
fast = true
else
fast = false
end
local params = RaycastParams.new()
params.FilterDescendantsInstances = {char}
params.FilterType = Enum.RaycastFilterType.Blacklist
local hit = workspace:Raycast(wedge.Position, -1000 * hrp.CFrame.UpVector, params)
local lv = camCF.LookVector
local uv = Vector3.new(0, 1, 0)
local rv = lv:Cross(uv)
local orientation = CFrame.fromMatrix(hrp.Position, rv, uv, -lv)
if hit then
local rotateToFloorCFrame = getRotationBetween(hrp.CFrame.UpVector, hit.Normal, randomAxis)
local goalCF = CFrame.new()
if fast == true then
goalCF = rotateToFloorCFrame * orientation
wedge.CFrame = wedge.CFrame:Lerp(goalCF, 1).Rotation + hrp.CFrame.Position
else
goalCF = rotateToFloorCFrame * hrp.CFrame
wedge.CFrame = wedge.CFrame:Lerp(goalCF, 1).Rotation + hrp.CFrame.Position
end
else
wedge.Position = hrp.Position
end
end)