Hey. I was making code where a player’s head will follow it’s camera, as well as replicate it to the server. I know I’m not the best programmer, and there is definitely room for improvement in terms of optimization. Right now it works with two modules, one for the client and one for the server.
CLIENT:
local headFollow = {}
--// Constants
local services = require(game:GetService("ReplicatedStorage"):WaitForChild("Common"):WaitForChild("Services"))
local common = services.replicatedStorage:WaitForChild("Common")
local clientModules = common:WaitForChild("ClientModules")
local utility = common:WaitForChild("Utility")
local remotes = common:WaitForChild("Remotes")
local headMovement = remotes:WaitForChild("HeadMovement")
local characterUtil = require(utility:WaitForChild("CharacterUtility"))
local player = services.players.LocalPlayer
local camera = workspace.CurrentCamera
headFollow.updateTask = nil
headFollow.C0 = nil
local CFnew, CFang = CFrame.new, CFrame.Angles
local asin = math.asin
--[[ Main ]]--
function headFollow.characterSpawned()
if headFollow.updateTask then
headFollow.updateTask:Disconnect()
end
local character = characterUtil.getCharacter(player)
local root: BasePart = character:FindFirstChild("HumanoidRootPart")
local neck: Motor6D = characterUtil.getObj("Neck", character, true)
local yOffset: number = neck.C0.Y
local lastUpdate = tick()
headFollow.updateTask = services.runService.RenderStepped:Connect(function(deltaTime)
local cameraDirection = root.CFrame:ToObjectSpace(camera.CFrame).LookVector
if character and root and neck then
headFollow.C0 = CFnew(0, yOffset, 0) * CFang(3 * math.pi / 2, 0, math.pi) * CFang(0, 0, -asin(cameraDirection.X)) * CFang(-asin(cameraDirection.Y), 0, 0)
end
if tick() - (lastUpdate + deltaTime) >= 0.1 then
headMovement:FireServer(headFollow.C0)
lastUpdate = tick()
end
end)
end
function headFollow.updatePlayerNeck(characterToUpdate, neckCFrame)
if characterToUpdate and neckCFrame then
local neck: Motor6D = characterUtil.getObj("Neck", characterToUpdate, true)
if neck then
--neck.C0 = neckCFrame
if neck.C0 == neckCFrame then
return
end
local tween = services.tweenService:Create(neck, TweenInfo.new(0.25), {C0 = neckCFrame})
tween:Play()
end
end
end
function headFollow.main()
warn("| HEAD MOVEMENT CLIENT CALLED |")
player.CharacterAppearanceLoaded:Connect(headFollow.characterSpawned)
remotes:WaitForChild("HeadMovement").OnClientEvent:Connect(headFollow.updatePlayerNeck)
end
headFollow.main()
return headFollow
SERVER:
local headFollow = {}
--// Constants
local services = require(game:GetService("ReplicatedStorage"):WaitForChild("Common"):WaitForChild("Services"))
local common = services.replicatedStorage.Common
local utility = common.Utility
local remotes = common.Remotes
local characterUtil = require(utility.CharacterUtility)
function headFollow.getMagnitude(player1, player2)
local character1 = characterUtil.getCharacter(player1)
local character2 = characterUtil.getCharacter(player2)
if not character1 or not character2 then return end
return (character1:GetPivot().Position - character2:Pivot().Position).Magnitude
end
function headFollow.updateHead(player, neckCFrame)
remotes.HeadMovement:FireClient(player, characterUtil.getCharacter(player), neckCFrame)
for _, playerToSend in pairs(services.players:GetPlayers()) do
if playerToSend ~= player and characterUtil.getCharacter(player) and headFollow.getMagnitude(player, playerToSend) and headFollow.getMagnitude(player, playerToSend) <= 30 then
remotes.HeadMovement:FireClient(playerToSend, characterUtil.getCharacter(player), neckCFrame)
end
end
end
function headFollow.main()
warn("| HEAD FOLLOW SERVER CALLED |")
remotes.HeadMovement.OnServerEvent:Connect(headFollow.updateHead)
end
headFollow.main()
return headFollow
Thanks for reading this post!