How to get Head/Torso rotation to work and be viewable on other clients

So I am working on a Motion Captured Animation game and I have this Head/Torso Follow script but I can’t seem to get it to show anyone else looking around on the player.

Here’s the script



wait()

--[Pre-Funcs]:

local Ang = CFrame.Angles	--[Storing these as variables so I dont have to type them out.]
local aSin = math.asin
local aTan = math.atan

--[Constants]:

local Cam = game.Workspace.CurrentCamera

local Plr = game.Players.LocalPlayer
local Mouse = Plr:GetMouse()
local Body = Plr.Character or Plr.CharacterAdded:wait()
local Head = Body:WaitForChild("Head")
local Hum = Body:WaitForChild("Humanoid")
local Core = Body:WaitForChild("HumanoidRootPart")
local IsR6 = (Hum.RigType.Value==0)	--[Checking if the player is using R15 or R6.]
local Trso = (IsR6 and Body:WaitForChild("Torso")) or Body:WaitForChild("UpperTorso")
local Neck = (IsR6 and Trso:WaitForChild("Neck")) or Head:WaitForChild("Neck")	--[Once we know the Rig, we know what to find.]
local Waist = (not IsR6 and Trso:WaitForChild("Waist"))	--[R6 doesn't have a waist joint, unfortunately.]

--[[
	[Whether rotation follows the camera or the mouse.]
	[Useful with tools if true, but camera tracking runs smoother.]
--]]
local MseGuide = false
--[[
	[Whether the whole character turns to face the mouse.]
	[If set to true, MseGuide will be set to true and both HeadHorFactor and BodyHorFactor will be set to 0]
--]]
local TurnCharacterToMouse = false
--[[
	[Horizontal and Vertical limits for head and body tracking.]
	[Setting to 0 negates tracking, setting to 1 is normal tracking, and setting to anything higher than 1 goes past real life head/body rotation capabilities.]
--]]
local HeadHorFactor = 1
local HeadVertFactor = 0.6
local BodyHorFactor = 0.5
local BodyVertFactor = 0.4

--[[
	[How fast the body rotates.]
	[Setting to 0 negates tracking, and setting to 1 is instant rotation. 0.5 is a nice in-between that works with MseGuide on or off.]
	[Setting this any higher than 1 causes weird glitchy shaking occasionally.]
--]]
local UpdateSpeed = 0.5

local NeckOrgnC0 = Neck.C0	--[Get the base C0 to manipulate off of.]
local WaistOrgnC0 = (not IsR6 and Waist.C0)	--[Get the base C0 to manipulate off of.]

--[Setup]:

Neck.MaxVelocity = 1/3

-- Activation]:
if TurnCharacterToMouse == true then
	MseGuide = true
	HeadHorFactor = 0
	BodyHorFactor = 0
end

game:GetService("RunService").RenderStepped:Connect(function()
	local CamCF = Cam.CoordinateFrame
	if ((IsR6 and Body["Torso"]) or Body["UpperTorso"])~=nil and Body["Head"]~=nil then	--[Check for the Torso and Head...]
		local TrsoLV = Trso.CFrame.lookVector
		local HdPos = Head.CFrame.p
		if IsR6 and Neck or Neck and Waist then	--[Make sure the Neck still exists.]
			if Cam.CameraSubject:IsDescendantOf(Body) or Cam.CameraSubject:IsDescendantOf(Plr) then
				local Dist = nil;
				local Diff = nil;
				if not MseGuide then	--[If not tracking the Mouse then get the Camera.]
					Dist = (Head.CFrame.p-CamCF.p).magnitude
					Diff = Head.CFrame.Y-CamCF.Y
					if not IsR6 then	--[R6 and R15 Neck rotation C0s are different; R15: X axis inverted and Z is now the Y.]
						Neck.C0 = Neck.C0:lerp(NeckOrgnC0*Ang((aSin(Diff/Dist)*HeadVertFactor), -(((HdPos-CamCF.p).Unit):Cross(TrsoLV)).Y*HeadHorFactor, 0), UpdateSpeed/2)
						Waist.C0 = Waist.C0:lerp(WaistOrgnC0*Ang((aSin(Diff/Dist)*BodyVertFactor), -(((HdPos-CamCF.p).Unit):Cross(TrsoLV)).Y*BodyHorFactor, 0), UpdateSpeed/2)
					else	--[R15s actually have the properly oriented Neck CFrame.]
						Neck.C0 = Neck.C0:lerp(NeckOrgnC0*Ang(-(aSin(Diff/Dist)*HeadVertFactor), 0, -(((HdPos-CamCF.p).Unit):Cross(TrsoLV)).Y*HeadHorFactor),UpdateSpeed/2)
					end
				else
					local Point = Mouse.Hit.p
					Dist = (Head.CFrame.p-Point).magnitude
					Diff = Head.CFrame.Y-Point.Y
					if not IsR6 then
						Neck.C0 = Neck.C0:lerp(NeckOrgnC0*Ang(-(aTan(Diff/Dist)*HeadVertFactor), (((HdPos-Point).Unit):Cross(TrsoLV)).Y*HeadHorFactor, 0), UpdateSpeed/2)
						Waist.C0 = Waist.C0:lerp(WaistOrgnC0*Ang(-(aTan(Diff/Dist)*BodyVertFactor), (((HdPos-Point).Unit):Cross(TrsoLV)).Y*BodyHorFactor, 0), UpdateSpeed/2)
					else
						Neck.C0 = Neck.C0:lerp(NeckOrgnC0*Ang((aTan(Diff/Dist)*HeadVertFactor), 0, (((HdPos-Point).Unit):Cross(TrsoLV)).Y*HeadHorFactor), UpdateSpeed/2)
					end
				end
			end
		end
	end
	if TurnCharacterToMouse == true then
		Hum.AutoRotate = false
		Core.CFrame = Core.CFrame:lerp(CFrame.new(Core.Position, Vector3.new(Mouse.Hit.p.x, Core.Position.Y, Mouse.Hit.p.z)), UpdateSpeed / 2)
	else
		Hum.AutoRotate = true
	end
end)```
1 Like

The best option would probably be to call a remote event over to the server with the newly set rotation data for your rig. You could then call another remote event from the server to each client. And at that point, you could test and see if the client isn’t the one who called the remote to begin with, and if that’s so, then you could update that character’s rig with the new rotation data passed in as a parameter.

Hope that’s helpful to some degree. I’m not an expert when it comes to this stuff though. d:

I’m not an expert when it comes to remote events so…

Here’s an article from the dev forum that explains remote events quite well: Custom Events and Callbacks | Documentation - Roblox Creator Hub

I actually never really specified as to why you would need to use remote events in the first place. Any changes you make on the client, typically won’t affect other clients by any means. What I mean by this is since you’re editing the player’s rotation on the joints, this is a change that will only be rendered for your client and for nobody else. (This is due to FilteringEnabled, which has been optional for a long time but now it’s mandatory pretty much.) The way to bypass this is to use remote events to communicate with the server and make changes that every other client will see.

1 Like

I’m still semi-new to coding LUA, as some examples help me I’m still confused by remote events.

1 Like

Remote events allow you to communicate from the server to client and client to server. You can use this so that after you make changes on the first client, you have that client fire a remote event to the server where the server then fires to all the clients except for the first one and replicates the changes you made locally on the first client on the other clients.

My secret:
Give each starter character a single anchored part that the respective player has network ownership of. Everyone controls their own “Look Part” and points it where they need it to point. Now everyone knows where everyone else is looking, from which everyone can point each other’s heads client sided.

Edit: Anchored parts apparently don’t replicate(?) I’m guilty of never using an anchored part for this so sorry for misinforming. I usually stick in bodymovers to hold it in place as well as point the lookpart. Apologies if this bumps the topic, I’ve never edited a post so late after the fact.

6 Likes

How would I be able to do that? I’m not very firm with LUA.

It’s as simple as calling SetNetworkOwner on a BasePart. Just a forewarning though that Dynamese’s solution has one misconception; network ownership cannot be used on anchored parts.

2 Likes