I am working on a golf game right now, and I am currently trying to roate the character holding a golf club around the ball. However, everything I have tried is inconsistent or does not work.
The current way I am doing it is the client requests a rotation part to be made with a remote event. The server creates this rotation part, makes it the primary part of the character, positions it, welds it to the humanoid root part, gives ownership to the client, and returns the part. The client then anchors this part, and makes it so when the camera moves, this rotation part will only move on the y-axis.
The problem is that it is consistently rotating on the y-axis with weird offsets. Additionally, the rotation part’s rotation doesn’t automatically change when the client changes it, so I am also using a remote event to update the position of this part, which is inefficient.
Code
-- Local Script
-- creates the rotation part under the player
remoteEvent:FireServer("RotationPart")
local rotationPart = character:WaitForChild("RotationPart")
rotationPart.Anchored = true
local weld = rotationPart:WaitForChild("Weld")
-- set position of rotation part
local camRotation = camera.CFrame.Rotation
local rotationX, rotationY, rotationZ = camRotation:ToOrientation()
cameraConnection = camera:GetPropertyChangedSignal("CFrame"):Connect(function()
local camRotation = camera.CFrame.Rotation
local rotationX, rotationY, rotationZ = camRotation:ToOrientation()
-- only rotate on y axis
local orientation = CFrame.fromOrientation(0, rotationY - 1.75, 0) -- inconsistant
local newCFrame = CFrame.new(golfBall.Position) * orientation
rotationPart.CFrame = newCFrame
remoteEvent:FireServer("UpdateCFrame", newCFrame) -- inefficient
end)
-- Server Script
local offsetFromBall = CFrame.new( -- calculated from ToObjectSpace
-3.74243164, 2.61268568, 0.0940246582,
0, 0, -1.00000381,
0, 1, 0,
1.00000381, 0, 0
)
character:SetPrimaryPartCFrame(golfBall.CFrame * offsetFromBall)
character.PrimaryPart = rotationPart
rotationPart.Position = golfBall.Position
weld.Enabled = true
Screenshots
Offset from ball taken from DummyHumanoidRootPart.CFrame:ToObjectSpace(Ball.CFrame)
Inconsistent rotation angles (seems to depend on the rotation of your character when you start)
Found a solution, here was the final code with a lot of explanation. (Inside the local script). Big thanks to @5uphi for helping me out with this.
--[[
This offset was calculated using a dummy's humanoid root part, and getting the offset from
it to the ball. Example of how to get it:
print(workspace.Dummy.HumanoidRootPart.CFrame:ToObjectSpace(workspace.GolfBall.CFrame))
]]
local offsetFromBall = CFrame.new(
-3.74243164, 2.61268568, 0.0940246582, -- Only this part is needed, this is the Vector3 offset
0, 0, -1.00000381,
0, 1, 0,
1.00000381, 0, 0
)
-- anchor to avoid moving around
character.HumanoidRootPart.Anchored = true
cameraConnection = camera:GetPropertyChangedSignal("CFrame"):Connect(function()
-- get the direction the camera is facing
local cameraDirection = game.Workspace.CurrentCamera.CFrame.LookVector
-- remove the y axis from the look vector since we don't want to move up and down with the camera
cameraDirection = Vector3.new(cameraDirection.X, 0, cameraDirection.Z).Unit
-- get the right direction from the camera forward direction
local cameraRight = cameraDirection:Cross(Vector3.yAxis)
-- position of the golfBall
local position = golfBall.Position
-- move the position back 0.0940246582 studs the Z offset from the ball
position -= cameraDirection * 0.0940246582
-- move the position to the left 3.74243164 studs, the X offset from the ball
position -= cameraRight * 3.74243164
--[[
Move the position up so the player's legs are on the floor.
This was gotten from subtracting the animation dummy's hipheight
to the Y offset from the ball. Beaware if the hipheight is 0,
you may need to calculate it using a script.
print(workspace.Dummy.HipHeight - - 2.61268568)
]]
position += Vector3.new(0,character.Humanoid.HipHeight + 0.5126856799999997,0)
-- make the player face in the direction of the camera
local cframe = CFrame.lookAt(position, position + cameraDirection)
-- rotate the cframe to counter the animation rotation
cframe *= CFrame.Angles(0, math.rad(-90), 0)
-- set the character cframe
character.PrimaryPart.CFrame = cframe
end)
Additional resources: Vector3 Cross Explanation, How To Calculate Hip Height (The animated dummy may have a hip height of 0 since they don’t come with a humanoid)