local camera = game.Workspace.CurrentCamera
local neck = character.Head.Neck
local baseNeckCFrameOffset = neck.C0:Inverse()
game:GetService("RunService").Heartbeat:Connect(function()
neck.C0 = camera.CFrame * baseNeckCFrameOffset-- or baseNeckCFrameOffset * camera.CFrame if it's backwards
end)
Perhaps you could create a clone of the character’s head (along with their head accessories) and make their actual head (and head accessories) transparent, so it creates the illusion that this new head is the player’s real head. You’d have to constantly position it correctly (I don’t believe any constraints would work) and use the logic from the above replies (assuming they work I haven’t checked to see).
Disable the head’s collision so it doesn’t collide with the torso.
Roblox might automatically re-enable the head’s collision, so you’ll want to use a collision group.
-- on server
local physicsService = game:GetService("PhysicsService")
physicsService:CreateCollisionGroup("Head")
physicsService:CollisionGroupSetCollidable("Head", "Head", false)
-- on client in head rotation script
character.Head.CollisionGroup = "Head"
Could you show me your code so I can try it out on my end and experiment?
Wait, the upper torso is probably still using the default collision group.
local physicsService = game:GetService("PhysicsService")
physicsService:CreateCollisionGroup("Character")
physicsService:CollisionGroupSetCollidable("Character", "Character", false)
-- on client in head rotation script
for _, part in ipairs(character:GetChildren()) do
if part:IsA("BasePart") then
part.CollisionGroup = "Character"
end
end
local camera = workspace.CurrentCamera
local neck = script.Parent:WaitForChild('Torso'):WaitForChild('Neck')
local head = script.Parent:WaitForChild('Head')
local baseNeckCFrameOffset = neck.C0:Inverse()
game:GetService("RunService").RenderStepped:Connect(function()
head.CollisionGroup = "Head"
neck.C0 = camera.CFrame * baseNeckCFrameOffset
end)
Server
local physicsService = game:GetService("PhysicsService")
physicsService:CreateCollisionGroup("Head")
physicsService:CollisionGroupSetCollidable("Head", "Head", false)
Also, your edited code does the same thing unfortunately.
Figured it out! I ended up just using a fake head like xendatro suggested, and setting the fake head’s CFrame to the camera’s. You could probably make this work with the joints too, but I won’t bother since this works for my use case.
local Camera = workspace.CurrentCamera
local RealHead = script.Parent:WaitForChild('Head')
local FakeHead = RealHead:Clone()
FakeHead.Name = 'FakeHead'
FakeHead.Transparency = 1
FakeHead.CanCollide = false
FakeHead.Anchored = true
FakeHead.Parent = script.Parent
game:GetService("RunService"):BindToRenderStep('FakeHeadMovement', 2000, function()
FakeHead.CFrame = CFrame.new(RealHead.CFrame.Position) * Camera.CFrame.Rotation
end)
If anyone’s curious, this is how the camera sway looks now (A LOT BETTER.):