I need help getting a compass to work correctly

It’s easy to make a part pointing toward another part, as the only thing you have to do is:

Part.CFrame = CFrame.lookAt(Part.Position, Vector3.new(Target.Position.X, Part.Position.Y, Target.Position.Z))

But it is harder to do it in a tool, because the only way to do it without having physical bugs is by using a weld.

1 Like

I took note of your and @MilkyFiend’s suggestions to use a Weld instead of a HingeConstraint and ran tests. First by mistake I tried using WeldConstraints since I was under the impression that Welds are depreciated so I incorrectly assumed you both meant to use WeldConstraints but were shortening the name to weld, but then I realised that WeldConstraints unfortunately don’t allow you to edit its CFrame so I consulted the docs and found that Welds aren’t depreciated as I initially thought so I ran test using it like you both suggested and here’s my results:

  • Shaking when equip no longer a problem
  • Rotating the needle still is problematic, with one of the issues being in my compass’ case the needle needs to rotate from an offset instead of the needle part’s origin. An easy solution to this problem would be to use an illusion where I’m actually rotating an invisible part in the center of the compass’s handle, then weld the visible needle to that invisible part, but I’d still appreciate if someone would explain an alternative method to use that doesn’t require a new part and weld to be added to the compass

Is it possible to see a video of the work?

If you are able to share a place file with the tool and the script, I will take a look. Alternatively, you could make a free model or add me to TC.

@Hazania @MilkyFiend @Crygen54

Here’s the place file, it’s as show and configured in the video:
CurrentlyBrokenCompass.rbxl (44.2 KB)

I finally solved it!

Firstly, I changed the axis of Angle() to the Z-Axis because why would you get the Y-Axis when your compass rotates only in the x-z plane (horizontal plane)?

When I tried it out, it worked, but only in a specific angle.

I noticed that it only works when the LookVector (-ZVector) of the handle is equivalent to the X-Axis and the RightVector (XVector) of the handle is equivalent to the Z-Axis. (i put a model of the x-y-z axes/vectors to compare it to the x-y-z vectors of the handle)


model

So I changed the xAxis to handle.CFrame.LookVector and zVector to -handle.CFrame.RightVector (negative to make it work)

local RunService = game:GetService("RunService")

local tool = script.Parent

local connection: RBXScriptConnection?

tool.Equipped:Connect(function()
	local hinge = tool.HingeConstraint
	local handle = tool.Handle
	
	local deg = math.deg
	local targetPos = Vector3.zero
	local y0Axis = Vector3.new(1, 0, 1)
	
	connection = RunService.PostSimulation:Connect(function()
		local angle = deg(handle.CFrame.LookVector:Angle((targetPos - handle.Position).Unit * y0Axis, -handle.CFrame.XVector))
		print(angle)
		
		hinge.TargetAngle = angle
	end)
end)

tool.Unequipped:Connect(function()
	if connection ~= nil then
		connection = connection:Disconnect()
	end
	
	connection = nil
end)

and this is the result (sorry for the crappy video)

for the collision, i tried to fix it but didn’t work so gl with that

also here’s the place
CurrentlyBrokenCompass.rbxl (51.3 KB)

1 Like

Thank you, the pointer is now working correctly :grin:

I updated the main post to note that you solved the angle problem

1 Like

Is there still any problems left? If not please mark a solution.

The shaking problem hasn’t been solved yet when using a HingeConstraint

Are you still hoping to use a HingeConstraint? I don’t think it’s necessary and you have a solution. Lmk if there is a reason you need it to be a HingeConstraint.

Now that T3_MasterGamer found a solution for calculating the angle for the HingeConstraint, the only issue left is the shaking

As I already mentioned I did thoroughly experiment with Welds using the help and suggestions I received here, but unfortunately I faced two challenges:

  • Rotating the needle using CFrame was causing the character to teleport as well
  • Finding the correct method to rotate the needle using CFrame was proving to be much more of a challenge

Alright, so whether we find a solution for the HingeConstraint or the Weld; either works for you? I will take a look today, I’ll try the HingeConstraint first.

1 Like

Personally I don’t mind whether the compass works using Welds or HingeConstraints so long as the functionality is there

Thanks for giving it a go, but note that I won’t be able to test it until tomorrow unfortunately since it’s very late night where I live right now

1 Like

As far as I can tell, the file that @T3_MasterGamer shared doesn’t seem to be shaking. Please let me know what you mean by that. For me, it appears smooth and responsive. Perhaps the responsive turning actually may appear to jitter if you are turning back and forth or if the character is playing an animation, but the compass is only doing that because it is accurately pointing at the goal. At further distances, it won’t be reacting as quickly, but if you want it to appear less responsive then you can interpolate the angle rather than directly turning it to the target angle.

The character that equips the compass shakes when they do so, not the compass itself if that’s what you mean

I actually did some testing today because I thought: What if I weld the compass, then destroy the weld using Debris service after a short duration after the player equips the tool, then create a new weld when the tool is unequipped. The reason why I did this test is because of this reply I made when testing a suggestion by @MilkyFiend

This is how I modified the script to do the test:

game:GetService"Debris"
game:GetService"RunService"

local tool = script.Parent

local connection

tool.Equipped:Connect(function()
	local hinge = tool.HingeConstraint
	local handle = tool.Handle

	local deg = math.deg
	local zero = Vector3.zero
	local y0Axis = Vector3.new(1, 0, 1)

	game.Debris:AddItem(tool.WeldConstraint, 0.5)

	connection = game["Run Service"].PostSimulation:Connect(function()
		local angle = deg(handle.CFrame.LookVector:Angle((zero - handle.Position).Unit * y0Axis, -handle.CFrame.RightVector))
		print(angle)

		hinge.TargetAngle = angle
	end)
end)

tool.Unequipped:Connect(function()
	if connection then connection = connection:Disconnect() end
	

	local weldConstraint = Instance.new"WeldConstraint"
	weldConstraint.Part0 = tool.Handle
	weldConstraint.Part1 = tool.Needle
	weldConstraint.Parent = tool
end)

Unfortunately though even after I tried fine-tuning the debris duration there’s still strange behavior happening when I equip the compass, but I did make quite an important discovery as when I tried setting the debris value to a large number, I noticed that the needle seems to start behind the player character instead of the correct position. The force the needle generates while it travels to its correct position from behind the player character could be what’s causing the character to shake when they equip a tool but I don’t yet know how to combat it

Edit: Here’s a video that shows what I mean about the needle starting behind the character

Since you were able to fix the shaking with the WeldConstraint, a very simple yet effective solution is just to hide the needle for a brief moment until it gets into position and then change Transparency back to 0. Since this is for a simple project, I would wager this is a good solution.

game:GetService"Debris"
game:GetService"RunService"

local tool = script.Parent
tool.Needle.Transparency = 1

local connection

tool.Equipped:Connect(function()
	local hinge = tool.HingeConstraint
	local handle = tool.Handle

	local deg = math.deg
	local zero = Vector3.zero
	local y0Axis = Vector3.new(1, 0, 1)

	task.delay(0.1, function() --note that you should make sure the tool is still equipped since there is a delay
		tool.WeldConstraint.Enabled = false
		task.wait(0.4)
		tool.Needle.Transparency = 0
	end)

	connection = game["Run Service"].PostSimulation:Connect(function()
		local angle = deg(handle.CFrame.LookVector:Angle((zero - handle.Position).Unit * y0Axis, -handle.CFrame.RightVector))
		print(angle)

		hinge.TargetAngle = angle
	end)
end)

tool.Unequipped:Connect(function()
	tool.Needle.Transparency = 1
	tool.WeldConstraint.Enabled = true
	if connection then connection = connection:Disconnect() end
end)

If you want to have the arrow showing the whole time without facing this issue, I would recommend calculating the object space CFrame of where the needle should be and set it there each time the tool is equipped rather than relying on a WeldConstraint to hold it there (unlike a Weld, you cannot change the CFrame whatsoever).

Btw to set the CFrame of a weld you need to do something like this:

weld.C0 = weld.Part0.CFrame:ToObjectSpace(weld.Part1.CFrame)
-- this would weld the parts in their current orientation to eachother
-- you can additionally swap out the cooresponding CFrame with the CFrame you want it to be in as opposed to where it is currently
1 Like

Unfortunately I wasn’t able to fix the shaking using Welds, WeldConstraints, RodConstraints and RigidConstraints all while simultaneously using a HingeConstraint to rotate the needle

I suspect the cause of the shaking is a bug being caused by the HingeConstraint, so I’ve made a decision to mark @T3_MasterGamer’s reply as a solution since they provided the working angle formula and I will try submitting a bug report to Roblox about the shake problem

Thank you Hazania, T3_MasterGamer, @MilkyFiend and @Crygen54 for all of your help with my compass :slightly_smiling_face::+1:

1 Like

I told you multiple times that the shaking collision “bug” come from the hinge constaint, because it is a physical constraint so it isn’t really a bug, which is why you have to use a weld instead of it, not additionally to it.

@Crygen54

I honestly spent a lot of time testing a version of a compass that uses CFrame and 0 HingeConstraints and it would be rude to assume that I simply ignored your suggestions and narrowly insisted on using hinges

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