Increasing NPC's torso rotation range

Currently my NPC works fine but there’s one small problem: my NPC’s torso seems to rotate too little in terms of pitch, and it makes shooting players at an elevated position seem weird:

Is there a quick fix, that also corrects the torso’s position?
My code is modified from this thread.

local RunService = game:GetService("RunService")

local Character = script.Parent.Parent
--Old R15 code
local Head = Character:WaitForChild("Head")
--local Neck = Head:WaitForChild("Neck")

--local Torso = Character:WaitForChild("UpperTorso")
--local Waist = Torso:WaitForChild("Waist")

--New R6 stuff
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

local Torso = Character:WaitForChild("Torso")
local Neck = Torso:WaitForChild("Neck")

local Waist = HumanoidRootPart:WaitForChild("RootJoint")

local RHip = Torso:WaitForChild("Right Hip")
local LHip = Torso:WaitForChild("Left Hip")

local LHipOriginC0 = LHip.C0
local RHipOriginC0 = RHip.C0

local NeckOriginC0 = Neck.C0
local WaistOriginC0 = Waist.C0

Neck.MaxVelocity = 1/3

while wait(0.1) do
	local CameraCFrame = Character.Head.CFrame

	if Character:FindFirstChild("Torso") and Character:FindFirstChild("Head") then
		local TorsoLookVector = Torso.CFrame.lookVector
		local HeadPosition = Head.CFrame.p

		if Neck and Waist then
			if script.Parent.LineOfSight.Value then
				local Point = script.Parent.TargetPosition.Value

				local Distance = (Head.CFrame.p - Point).magnitude
				local Difference = Head.CFrame.Y - Point.Y

				local goalNeckCFrame = CFrame.Angles(math.clamp(-(math.atan(Difference / Distance) * 0.5), 0, math.rad(360)), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 1, 0)
				Neck.C0 = Neck.C0:lerp(goalNeckCFrame*NeckOriginC0, 0.5 / 2).Rotation + NeckOriginC0.Position

				local xAxisWaistRotation = -(math.atan(Difference / Distance) * 0.5)
				local yAxisWaistRotation = (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 0.5
				local rotationWaistCFrame = CFrame.Angles(xAxisWaistRotation, yAxisWaistRotation, 0)
				local goalWaistCFrame = rotationWaistCFrame*WaistOriginC0
				Waist.C0 = Waist.C0:lerp(goalWaistCFrame, 0.5 / 2).Rotation + WaistOriginC0.Position

				local currentLegCounterCFrame = Waist.C0*WaistOriginC0:Inverse()
				local legsCounterCFrame = currentLegCounterCFrame:Inverse()

				RHip.C0 =  legsCounterCFrame*RHipOriginC0
				LHip.C0 = legsCounterCFrame*LHipOriginC0
			end
		end
	end	
end
2 Likes

local xAxisWaistRotation = -(math.atan(Difference / Distance) * 2)
just replace that line with this (the multiplication is how much it should move the torso) do note itll look weird if you aim straight down

1 Like

You use math.atan(Difference / Distance), Distance is the full 3D magnitude (includes Y).That makes the ratio (and thus the pitch) much smaller than it should be. Use horizontal distance instead:

flat = (Point - Head.Position); horiz = (Vector3.new(flat.X,0,flat.Z)).Magnitude;

pitch = atan2(flat.Y, math.max(horiz, 1e-3))`.

animations might be fighting it it constantly wants to set the position of the limb too with the slow update rate at 0.1 seconds too

3 Likes

i dont know what all that means but this is probably a better solution
also for the 0.1 update rate use runservice.stepped so that it moves it smoother

local Distance = (Head.CFrame.p - Point).magnitude
local Difference = Head.CFrame.Y - Point.Y
local pitch = math.atan(Difference / Distance)

Distance here is the full 3D distance between head and target.
That includes the vertical difference in Y.

So when the target is high above or low below, your Difference / Distance ratio gets shrunk, because the denominator already contains that same Y difference.

therefore the angle from atan(Difference / Distance) is smaller than reality, so the torso hardly tilts up/down.

let me know if this works or not

I see – but how do I implement this? (Apologies as I’m rather unfamiliar with CFrames and 3D angles)
What do flat, horiz, and pitch correspond to, and do I set their CFrame rotations in:

				local flat = point - head.Position
				local horiz = Vector3.new(flat.X, 0, flat.Z).Magnitude
				local pitch = math.atan2(flat.Y, math.max(horiz, 1e-3))

				local xAxisWaistRotation = -(math.atan(diff / dist) * 0.5)
				local yAxisWaistRotation = (((headPos - point).Unit):Cross(torsoLookVector)).Y * 0.5
				local rotationWaistCFrame = CFrame.Angles(pitch, horiz, 0)
				local goalWaistCFrame = rotationWaistCFrame * waistOriginC0
				waist.C0 = waist.C0:lerp(goalWaistCFrame, 0.5 / 2).Rotation + waistOriginC0.Position

…in rotationWaistCFrame?
I’ve tried this, and it doesn’t seem to function correctly.

just do local xAxisWaistRotation = pitch
also i recommend changing
local Character = script.Parent.Parent
to
local Character = game.Players.LocalPlayer.Character
that actually made me confused for a while since it couldnt find the character for me

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.