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.
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.
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.
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
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.
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.
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)
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.
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.
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.
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.