Pointing part at player using constraint

Hello Fellow Developers,

I am currently in the process of making an robot using constraints. The problem is making the head rotate to face the player. However, I have encountered some issues in construction. Due to the nature of the robot, I am unable to use Vector3.new(Part.Position, Character.HumanoidRootPart.Position) as this needs to be compatible with constraints.

Some sample code I have tried includes:
Sample 1

-- Uses HingeConstraint, calculating angle to rotate to player from origin using a chord on an imaginary circle
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
RunService.RenderStepped:wait()

local LocalPlayer = Players.LocalPlayer
local character = script.Parent
local part = game.Workspace.Part

RunService.Heartbeat:Connect(function()
	local c = (part.Position + part.CFrame.LookVector * Vector3.new(character.HumanoidRootPart.Position*Vector3.new(1, 0, 1).Magnitude, 0, character.HumanoidRootPart.Position*Vector3.new(1, 0, 1).Magnitude) - character.HumanoidRootPart.Position*Vector3.new(1, 0, 1)).Magnitude
	local r = (part.Position*Vector3.new(1, 0, 1) - character.HumanoidRootPart.Position*Vector3.new(1, 0, 1)).Magnitude
	part.HingeConstraint.TargetAngle = 2 * math.deg(math.asin(c/(2*r)))
end)

Sample 2

-- Uses an SSS triangle calculated within an imaginary circle and uses The Law of Consines to find the angle of rotation
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
RunService.RenderStepped:wait()

local LocalPlayer = Players.LocalPlayer
local character = script.Parent
local part = game.Workspace.Part

RunService.Heartbeat:Connect(function()
	local a = (part.Position*Vector3.new(1, 0, 1) - character.HumanoidRootPart.Position*Vector3.new(1, 0, 1)).Magnitude
	local b = (part.Position*Vector3.new(1, 0, 1) - character.HumanoidRootPart.Position*Vector3.new(1, 0, 1)).Magnitude
	local c = (part.Position + part.CFrame.LookVector * Vector3.new(character.HumanoidRootPart.Position*Vector3.new(1, 0, 1).Magnitude, 0, character.HumanoidRootPart.Position*Vector3.new(1, 0, 1).Magnitude) - character.HumanoidRootPart.Position*Vector3.new(1, 0, 1)).Magnitude
	local ta = math.deg(math.acos(((a^2)+(b^2)-(c^2))/(2*a*b)))
	part.HingeConstraint.TargetAngle = ta
end)

Occasionally during debugging the HingeConstrant.TargetAngle will be set to -nan(ind), probably due to the player being (directly?) behind the part, therefore causing an “impossible” triangle (some speculation here, forgive me for my lack of knowledge). Not to mention you would also have to calculate the direction in which to rotate the constraint.

Any help on this would be appreciated. Maybe the amount of effort being put into this isn’t worth it and maybe I should just make it CFrame optimized.

Thanks in advance.

1 Like

I’m in a position where I can’t write much but I’m sure you’ll get this pretty quickly:

local hinge = script.Parent.HingeConstraint
local startPart = script.Parent
local targetPart = workspace:WaitForChild("SomeRandomPart")

function computeTargetAngle(target_pos, start_pos)
	local delta = target_pos - start_pos
	local new_delta = Vector3.new(delta.x, 0, delta.z)
	local unit_delta = new_delta.unit
	local angle = math.atan2(unit_delta.z, unit_delta.x)
	return (-math.deg(angle)+math.pi)
end

while wait() do
	hinge.TargetAngle = computeTargetAngle(targetPart.Position, startPart.Position) - startPart.Orientation.Y
end

Let me know if it works!

2 Likes

I’ll try it. Thanks for the help!

The brick rotates, but it always rotates too slowly and doesn’t lock onto the player for some strange reason.

Small mistake in the return value of the function I gave, it works perfectly on my end. The ‘90’ might change depending on your attachment rotations or something.

function computeTargetAngle(target_pos, start_pos)
...
return (-math.deg(angle) - 90)

You might need to AngularSpeed and ServoMaxTorque on your Servo HingeConstraint. My MaxTorque is like 100000000 and AngularSpeed is 5. Another possibility is the friction between the head on the part that it is resting on is too high, so just CustomPhysicalProperties that away. Or maybe the head is getting stuck while turning?

1 Like

Thanks for the help! It worked but I had to slightly modify the script and multiply the angle by 2, for some reason it only rotated halfway. I really appreciate your help!

1 Like

No problem at all, I literally had your exact same problem not too long ago and finally stumbled on math.atan2(), the code I sent you was pretty much a copy and paste