Limit CFrame Angles with Mouse.Hit.Position

I cannot figure out how to limit the CFrame angles for my turret.

I have spent hours reading and looking on the forum. I found bunch of post and tried to make use of them but cannot figure it out.

Here is the Client Script (sends Mouse Position):

local MouseLock = script.Parent:WaitForChild("RF_MouseLock")
local Mouse = game.Players.LocalPlayer:GetMouse()

function MouseLock.OnClientInvoke()
	return Mouse.Hit.Position
end

Here is the Server Script (that rotates the turret):

local seat = script.Parent:WaitForChild("Seat")
local housing = script.Parent:WaitForChild("Housing")
local occupied = false


seat:GetPropertyChangedSignal("Occupant"):Connect(function()
	if seat.Occupant then
		occupied = true
		while task.wait() do
			if occupied then
				-- find player and mouse postion
				local character = seat.Occupant.Parent
				local player = game.Players:WaitForChild(character.Name)
				local MouseLock = character:WaitForChild("RF_MouseLock")
				local MouseHitPosition = MouseLock:InvokeClient(player)
				-- rotate toward mouse
				if (MouseHitPosition-housing.Position).magnitude>3 then
					housing.CFrame = CFrame.new(housing.Position, MouseHitPosition)	
				end
			end			
		end
	else
		occupied = false
		return
	end
end)

The workspace contains only the two parts:

  1. a seat
  2. a part named “housing” that is welded to the seat.

Any help is appreciated.

You can convert the CFrame to orientation, clamp it, then reconvert it back to a CFrame.

I read that post and tried it but could not understand how to make it work for my case.

Very confusing. I also read a lot of other post about clamping.

No problem let me try to explain it step by step.

First I will assume you know how parts have an orientation property and that you can modify each angle in order to limit them in each axis using a function such as math.clamp.

local orientation = part.Orientation
local newYOrientation = math.clamp(orientation.Y, -45, 45) --Clamp y rotation between -45 to 45
local newOrientation = Vector3.new(orientation.X, newYOrientation, orientation.Z)

You can apply the same technique given a CFrame using the to orientation function. Orientation is used as it’s easier to visualize and the angles are applied

local x, y, z = part.CFrame:ToOrientation()
local newYAngle = math.clamp(y, math.rad(-45), math,rad(45)) --The function angles are given in radians so math.rad is needed to convert degrees into radians

In your case the CFrame you achieved is through CFrame.lookAt() or CFrame.new(pos1, pos2) so all you need to do is to limit it.

local rotationCFrame = CFrame.new(housing.Position, MouseHitPosition)	
local x, y, z = rotationCFrame:ToOrientation()
--limit angles
local newYAngle = math.clamp(y, math.rad(-45), math,rad(45)) --The function angles are given in radians so math.rad is needed to convert degrees into radians
local newRotationCFrame = CFrame.fromOrientation(x, newYAngle, z)

Awesome!

Thank you. I managed to get it to work with your help!

All but one thing, it moves the Housing to 0,0,0 when I use `housing.CFrame = newRotationCFrame.

I have been trying to figure out how to fix it, but cannot. I looked up a bunch of posts about rotating CFrames and keeping the original position but cannot figure it out.

I tried different things like housing.CFrame = housing.CFrame * newRotationCFrame but that just makes it spin like a top.

I don’t know why CFrames are so difficult for me to understand.

Current Code:

seat:GetPropertyChangedSignal("Occupant"):Connect(function()
	if seat.Occupant then
		occupied = true
		while task.wait() do
			if occupied then
				-- find player and mouse postion
				local character = seat.Occupant.Parent
				local player = game.Players:WaitForChild(character.Name)
				local MouseLock = character:WaitForChild("RF_MouseLock")
				local MouseHitPosition = MouseLock:InvokeClient(player)
				-- rotate toward mouse
				if (MouseHitPosition-housing.Position).magnitude > 3 then

					local rotationCFrame = CFrame.new(housing.Position, MouseHitPosition)	
					local x, y, z = rotationCFrame:ToOrientation()
					local newYAngle = math.clamp(y, math.rad(-90), math.rad(90)) --limit left/right
					local newXAngle = math.clamp(x, math.rad(-45), math.rad(45)) --limit up/down
					local newRotationCFrame = CFrame.fromOrientation(newXAngle, newYAngle, z)
					
					housing.CFrame = housing.CFrame * newRotationCFrame -- this line is not working
				end
			end
		end
	else
		occupied = false
		return
	end
end)
1 Like

This line of code housing.CFrame = newRotationCFrame sends the part to 0,0,0 before rotating it.

I looked up the documentation and a lot of examples and they all look like this:

housing.CFrame = housing.CFrame * newRotationCFrame

I even tried local newRotationCFrame = housing.CFrame * CFrame.fromOrientation(newXAngle, newYAngle, z)

But both of these still send the part to 0,0,0 before rotating it and also make it spin like a top.

Does anyone know why?

Oh yeah forgot that this creates a CFrame with only rotation component.

To solve this you can just add the original position of housing.

housing.CFrame = newRotationCFrame + housing.Position

Wow.

You make this look so easy.

Your awesome! Thank you for your help!

That worked perfectly.

1 Like

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