CFrame clamp on turret?

I have gone through every article I can find for the past couple of days trying to figure out how to limit the rotation of an object, yes I have looked at the other articles and I’m not wrapping my head around it.

Currently, I Have and many variants of this.

render.Heartbeat:Connect(function()		
	local mousePos = Mouse.Hit.Position
	local rotate = Vector3.new(mousePos.X, turr.Position.Y, mousePos.Z)
	turma:SetPrimaryPartCFrame(CFrame.new(turr.Position, rotate))
end)

Looks like:


What id like to do is stop it from rotating over these red lines.
Capture.PNG
Basically limiting its Y rotation to only a couple of degrees.
If you could point me in the right direction that would be wonderful.

1 Like

First you can set up a vector which would bisect your vision triangle.

Then you can use the dot product, to get the angle between the vector which represents the direction towards the mouse point, and the vector I described up there.

If the angle between these two vectors exceeds a value, then you can clamp it or do something with it as necessary

local bisectingVector = ...
local totalAngle = ...
render.Heartbeat:Connect(function()		
	local mousePos = Mouse.Hit.Position
        local direction = (turr.Position - mousePos).unit
         local angle = math.acos(direction:Dot(bisectingVector);
        if angle > totalAngle * .5 then
         -- clamp it here
        end
  
	local rotate = Vector3.new(mousePos.X, turr.Position.Y, mousePos.Z)
	turma:SetPrimaryPartCFrame(CFrame.new(turr.Position, rotate))
end)
2 Likes

Yo

If you want to know how it works here is the clamping function, I convert the CFrame to orientation then clamp the orientation angles.

Code sniplet
--Inverse the part0 only for Motor6D's
--Set it to CFrame.new() for non Motor6ds
	local relativeToWorld = currentJointMotor6D.Part0.CFrame:Inverse()

	local lookAtWorld = CFrame.lookAt(turretPosition,lookAtPosition,baseCFrame.UpVector)--goal LookAt CFrame

	local goalCFrame

	if self.Constraints then
		local turretRelativeCF = baseCFrame:ToObjectSpace(lookAtWorld)
		local x , y , z = turretRelativeCF:ToOrientation()
		--print(math.deg(x),math.deg(y),math.deg(z))
		local constrainedX , constrainedY = self:EulerClampXY(x,y)

		--Detect quadrant of lookAt position
		local jointPosition = currentJointMotor6D.Part0.CFrame*originalC0Position
		local quadrantLookAtFromJointPosition = CFrame.lookAt(jointPosition,lookAtPosition,baseCFrame.UpVector)	
		local baseRelative = baseCFrame:ToObjectSpace(quadrantLookAtFromJointPosition)
		local _,y, _ = baseRelative:ToOrientation()
		constrainedY = math.abs(constrainedY)*math.sign(y)--use the quadrants of the lookAtFromJoint

		--print(math.deg(constrainedX),math.deg(constrainedY))
		--print(math.deg(constrainedY))
		goalCFrame = relativeToWorld*baseCFrame*CFrame.fromOrientation(constrainedX,constrainedY,z)*turretCFrameRotationOffset
	else
--Unconstrained use lookAtWorld
		goalCFrame = relativeToWorld*lookAtWorld*turretCFrameRotationOffset
	end

--Euler Clamp function:
-- negative z is front, x is rightvector
function TurretController:EulerClampXY(x,y)
	local Constraints =  self.Constraints
	local degY = math.deg(y)
	local degX = math.deg(x)
	local newY = math.clamp(degY,-Constraints.YawRight,Constraints.YawLeft)
	local newX = math.clamp(degX,-Constraints.DepressionAngle, Constraints.ElevationAngle)

	return math.rad(newX), math.rad(newY)
end

Edit: For your case do this,

render.Heartbeat:Connect(function()		
	local mousePos = Mouse.Hit.Position
	local rotate = Vector3.new(mousePos.X, turr.Position.Y, mousePos.Z)
local goalCFrame = CFrame.new(turr.Position, rotate)
local x,y,z = goalCFrame:ToOrientation()
print(math.deg(x),math.deg(y),math.deg(z))
--Notice the angles being changed
--Then you can clamp the angles
	turma:SetPrimaryPartCFrame(goalCFrame)
end)

1 Like

Thank you, but honestly, I have no idea what any of that means. I’ll need to look into clamps.

So if im not mistaken clamping where you noted will limit how much it can rotate.
from my understanding, I can use math.clamp(y,-20,20) and it would only let me move it by 40 degrees.
so it would look something like
turma:SetPrimaryPartCFrame(goalCFrame,math.clamp(y,-20,20)) ?

Well, here is a more simpler code snippet:

render.Heartbeat:Connect(function()		
	local mousePos = Mouse.Hit.Position
	local rotate = Vector3.new(mousePos.X, turr.Position.Y, mousePos.Z)
local goalCFrame = CFrame.new(turr.Position, rotate)
local x,y,z = goalCFrame:ToOrientation()
--print(math.deg(x),math.deg(y),math.deg(z))
--Notice the angles being changed
--Then you can clamp the angles, restrict it
--clamps between -30 to 30 degrees
clampedY = math.clamp(math.deg(y),-30,30)
--convert back to radian
clampedY = math.rad(clampedY)
--Create new clamped goalCFrame, using clamped angles
local clampedGoalCFrame = CFrame.fromOrientation(x,clampedY,z)+turr.Position--maintain the turret position so add it
--use the new clamped CFrame
	turma:SetPrimaryPartCFrame(clampedGoalCFrame)
end)

That is SOOO AMAZING!!! Im going to need to check up on your profile with those IK bones. Thank you so much I don’t know what to say.