Help making servo hinges make a block face the mouse

Hello. I am trying to make a servo hingeconstraint make a part face the mouses vector3 position. I already have the mouse position provided, but I am facing many problems with making the servo hinge constraint work properly. this is my progress right now. code from another forum post

		local targetAngle = getMousePos()
		
		local HKpos = Vector2.new(block.Base.Attachment_NO.WorldCFrame.Position.X,block.Base.Attachment_NO.WorldCFrame.Position.Z)
		-- define position of target
		local XYpos = Vector2.new(targetAngle.X,targetAngle.Z)

		-- the ratio to get the triangle's width over the height
		local ratio = (XYpos.Y-HKpos.Y)/(XYpos.X-HKpos.X)
		local beta = math.atan(ratio) -- converting this to radians

		-- turn it from radians into degrees
		beta = beta*(180/math.pi)
		
		if beta < 0 then
			beta = beta + 360
		end

		print(beta)
		block.Base.HingeConstraint.TargetAngle = -beta -- beta has to be negative so it points at you

There are two problems with this code. One, it only supports the hingeconstraint if it is upright. If the motor is tilted sideways, nothing works anymore. Two, the servo decides to flip 180 degrees depending on the angle from the motor the mouse is.

1 Like

maybe the script is fine but u just didn t finish the script or something(btw don t take my advice since i am really new here too)

1 Like

Honestly not sure,
Maybe make sure the attachments also follow the same rotation whenever the servos target angle is changed?

A HingeConstraint allows two Attachments to rotate about one axis, constraining the two Attachments so that they both occupy the same position and that their X axes point in the same direction.

2 Likes

The world cframe of both attachments are congruent, though the secondary axis is not. Could this have to do with the problem?

1 Like

First thing you can do is switch over to using math.atan2(dy,dx) because this will automatically give you the target’s angle in the range [-π,π] without you having to manually figure out the quadrant.

Secondly, your ‘targetAngle’, is actually a 3D world-space position, and your math is all in world space, so the hinge angle is only going to be correct if the hinge’s secondary axis is always pointed in the world Z direction. If this hinge is fixed in world, fine. If it’s on a vehicle, not gonna work, you’re going to need to the transform the world target point into the coordinate frame of the hinge attachments first. The CFrame class has a pointToObjectSpace() function just for doing this.

Thirdly, don’t copy values to Vector2, you need a full Vector3 in order to handle any orientation of the hinge correctly.

Lastly, what do you expect to happen if the hinge is, as you say, “tilted sideways”. Hinges only rotate on one axis, so if the rotation axis is not aligned with world +Y, you won’t necessarily be able to point the block at a target position. If the hinge isn’t fully at a right angle from upright, you can get the projection of it’s pointing direction onto the world XZ-plane to align with the target position, but that’s not necesarily useful or anywhere near “pointing to” it.

1 Like

This is the code I used to make a turret (using 2 servos) point at a specific position

originBP is the root part that the hinge is connected to
toDeg is the number 180/math.pi
both yawH and pitchH are hinges

local rel: CFrame = originBP.CFrame.Rotation:Inverse() * CFrame.lookAt(originBP.Position, target.Position).Rotation
local x, y: number = rel:ToOrientation()
x *= toDeg; y *= toDeg
yawH.TargetAngle = y
pitchH.TargetAngle = x
2 Likes

I am highly unfamiliar of this general topic. I haven’t covered trigonometry in school yet, so it’s hard to understand fully what is going on here. My goal is to have a hingeconstraint point at a vector3 no matter what orientation or position the base attachment is at. Though your post did fill me in on a few things I didn’t exactly understand, I’m still pretty unfamiliar with this space. Is it possible if I could have help going in the right direction for achieving this?

Thank you. However, the motor runs on only one hinge constraint, and the orientation of its attachments are not static. (It’s an object in a sandbox game) Therefore, I don’t think your code would work for this.

1 Like

ok plane crazy clone :skull:

That’s fine, you just ignore the other hinge in my example code and only use the one for yaw control.

In that case, you can substitute originBP.CFrame with attachment.WorldCFrame or something similar to that. The whole point of doing this is to use that to offset the relative orientation between the hinge and whatever it’s trying to aim at (hence the :Inverse() operation)

Also, I don’t think the attachment’s orientation should be changing. A static attachment will rotate and move with whatever basepart it’s attached to. My code takes into account the orientation of that parent part.

If you would like here’s a quick demo, I think it’s everything you need


motorism.rbxl (56.9 KB)

local uis = game:GetService('UserInputService')
local rus = game:GetService('RunService')

local model = script.Parent
local root = model:WaitForChild('Root')
local pivot = model:WaitForChild('Pivot')
local hinge = model:WaitForChild('HingeConstraint')

rus.RenderStepped:Connect(function()
	local cam = workspace.CurrentCamera
	local mPos = uis:GetMouseLocation()
	local mRay = cam:ViewportPointToRay(mPos.X, mPos.Y)
	local rcr: RaycastResult? = workspace:Raycast(mRay.Origin, mRay.Direction*1e3)

	local mPosWorld: Vector3 = if rcr then rcr.Position else mRay.Origin+mRay.Direction*1e3

	local rel = root.CFrame.Rotation:Inverse() * CFrame.lookAt(pivot.Position, mPosWorld).Rotation
	local _, yaw: number = rel:ToOrientation()
	hinge.TargetAngle = math.deg(yaw)
end)
4 Likes

I’ve made you a simple example of the 2-hinge “turret” case, just open the place file in Studio and Run (F8) it, or play solo (will be less smooth, since the example scripts are server scripts).

There are a bunch of turrets, randomly rotated and tilted, all with the same tiny script. They will all aim their lasers at the ball, no matter where it goes, because each turret is tracking the neon ball’s position in its own local spherical coordinate space. Notice: The exact orientation of the Hinge’s Attachments matter. The yellow axis of the attachment is it’s X axis, which the hinge rotates around. The way I set this up for the code, the attachment secondary (orange) axis sets where the “zero” angle is for each hinge.


TurretExample.rbxl (56.4 KB)

I’ve used this same setup for everything for the laser projectors in Club Raven to tank turrets and CIWS. For those not needing the full example, the aiming code looks like this:

local function Update()
	local pYaw = yawHinge.Attachment1.WorldCFrame:Inverse() * target.Position
	local pPitch = pitchHinge.Attachment1.WorldCFrame:Inverse() * target.Position
	local yaw = math.atan2(-pYaw.Z, pYaw.Y)
	local pitch = math.atan2(-pPitch.Z, pPitch.Y)
	yawHinge.TargetAngle = math.deg(yaw)
	pitchHinge.TargetAngle = math.deg(pitch)
end

Notice that there are two CFrame inverses because in my example, the yaw and pitch hinges are not at the same coordinates; they have their own attachments. But… the pitch hinge is on the rotation axis of the yaw hinge, which means turning the yaw hinge doesn’t move the position of the pitch hinge, and they can do their calculations independently. If the pitch hinge was not on the yaw rotation axis, it would need to factor the yaw hinge rotation update into its own calculation, since rotating the yaw hinge would move its world position. Hope that makes sense.

Does it need to run HingeConstraints?
How about using CFrames?

There are a few posts on the forums about aiming a part at the mouse position, or aiming your gun to the cursor, or making a part face the mouse.

You can use CFrame math, just don’t set Part or Model CFrames directly, that’s where people go wrong.You could connect the rotating part with a BallSocketConstraint and use an AlignOrientation to angle it, by setting the CFrame of one of the attachments, or setting AlignOrientation.CFrame (little known property) directly in one-attachment mode. This will get you smooth, consistent behavior.

For specific use cases though, the Hinge is the best. Especially for tanks and artillery turrets, since you normally want independent control over the angles, limits, and angular velocities.

It requires hinge constraints.

Ok, but please explain why it requires them.
On Roblox there are multiple ways of doing things and some work better than others.

(and @EmilyBendsSpace)
Lots of Constraints on unanchored Parts may cause lag because they are physics related. CFraming using Anchored Parts would make it more performant.

OP’s question requires one constraint, which has a single degree of freedom and will normally only have runtime cost when it’s actually moving because of how physics assemblies aggressively sleep.

There’s really only one scenario where doing animation by CFraming anchored parts has no significant problems: the parts exist only on the client, the code doing the CFraming is only running on the client, and the parts are CanCollide=false. An example would be a client-side sliding door, where you don’t want collisions with anything, and for gameplay reasons you deliberately want the door to open only on specific clients (not sync’d for all players). And even in this specific case, there are now options that will hugely outpeform even CFramed anchored parts.

For animating any collidable part, or anything animated server-side, setting part CFrames has big problems, including the potential for big performance and lag problems if lots of anchored parts are being moved every frame, because they will fill up the part replication queue, whereas a physics-driven assembly will not.

1 Like

I thought you said something else in my dms?

i was being more humorous in this forum
this is what i said in your DMS:
image
i meant the same thing in my message

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