Limit CFrame for turrets

Hello everyone, I have a working turret, which points to the mouse. Now, the problem is that when you point the gun to the floor, the camera bugs because the gun goes into other meshes and terrain. I want to limit it so it doesn’t go down further than a part.
image

I have tried reading other devforum posts about similar problems, but I just can’t understand how all these math things work.

I hope there is a simple solution for this.
Thank you.

2 Likes

You could put all of those parts into a folder then you could use Mouse.TargetFilter

Example:

local plr = game.Players.Localplayer
local mouse = plr:GetMouse()

mouse.TargetFilter = workspace.Folder --(a folder than contains meshes you want it to ignore) (you could try it with **Terrain** too I guess.)
1 Like

There is indeed a simple solution. Wherever you have the turret face the mouse position, you can use math.clamp() to do so. But, you’ll need to break down the position into individual components, X, Y, and Z.

local validX = math.clamp(mouse.Hit.P.X, min, max) --change min and max to what you need
--do that for Y and Z

Also, how are you exactly making the turret face the mouse? Are you using Mouse.UnitRay? If so, something similar to the above can also work.

3 Likes

Hello!!!

What’s Mouse.UnitRay?
I don’t qutie get it

1 Like

Hi!

It’s basically a ray that points to where the mouse is compared to the physical world. Basically, it’s to get from 2D to 3D.

Read more here.

2 Likes

Refer to this topic, it’ll give you some insight on how to achieve this

Im just looping the CFrame to face the mouse.

1 Like

But I dont understand how that works and how to implement it into my script.

Are you looking for a way to automate the values so that it doesn’t exceed the part? Or are you looking for a way so that you can manually set a limit?

1 Like

I want to set a horizontal limit so the player cannot point the turret down to the floor, but can point to the sky.

Are you using motors or cframe for the turning mechanism for the turret?

1 Like

image

If you record the original CFrame and use that to compare, you can use the offset from the new and original, and if it overextends the max angle, you can set it to be the max angle.

1 Like

How do I set the max angle?

30chars

The mouse object has and I quote from the deb hub:

Mouse, by and large, has been superseded by UserInputService which offers wider additional functionality for interacting with the mouse as well as other input types.

To do this you need to use the GetMouseLocation() method from UserInputService, this will get the 2D position of the mouse relative to the top left corner of the screen.

So your code will look something like this:

local UserInputService = game:GetService("UserInputService")
local MousePos = UserInputService:GetMouseLocation()

But this will only ever get the mouse position once, when the script first runs, to get around this we will use BindToRenderStep, because we are wanting the user input to have occured before we get the location and the camera not to have updated yet, the priority should be between 100-200 according to the render priority of render stepped.

The code should now look something like this:

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local function foo()
	local MousePos = UserInputService:GetMouseLocation()
end

RunService:BindToRenderStep("foo", 150, foo)

This is only getting the 2D position of the mouse, to turn this into a 3D position we can use the method ViewportPointToRay from the Camera object, this returns a Ray object, from that Ray object we can get its origin and direction to make a CFrame!

The code should now look like this:

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Camera = game:GetService("Workspace").CurrentCamera

local function foo()
	local MousePos = UserInputService:GetMouseLocation()
	local ray = Camera:ViewportPointToRay(MousePos.X, MousePos.Y, 5) -- Mouse pos x,y, offset from camera
	local CF = CFrame.new(ray.Origin, ray.Origin + ray.Direction)
end

RunService:BindToRenderStep("foo", 150, foo)

Now all we need to do is find the angle between the players Humanoid Root part and this CFrame. To do this we need to get the lookvector (direction the Humanoid Root Part is facing) and use the :Dot method of Vector 3 to find the angle between the Humanoid Root Part and the CFrame from the ray. However, just doing this is not enough - it will output the opposite angle because the point we are getting the angle to is by the camera, so we need to move the point along the ray by just over the max camera zoom distance to get the correct angle.

That will look something like this:

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Camera = game:GetService("Workspace").CurrentCamera
local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer

local function foo()
	local Character = workspace:FindFirstChild(LocalPlayer.Name)
	if not (Character) then return end
	
	local MousePos = UserInputService:GetMouseLocation()
	local ray = Camera:ViewportPointToRay(MousePos.X, MousePos.Y, 5) -- Mouse pos x,y, offset from camera
	
	local rayEnd = ray.Origin + (LocalPlayer.CameraMaxZoomDistance + 5) * ray.Direction.unit
	local CF = CFrame.new(rayEnd, rayEnd + ray.Direction)
	
	local Facing = Character.HumanoidRootPart.CFrame.LookVector
	local Angle = math.acos(Facing:Dot(CF.LookVector))
	print(math.deg(Angle))
end

RunService:BindToRenderStep("foo", 150, foo)

Now all you need is a little more code to limit the rotation of the turret! We will check the angle, if it is too big or small then we will not move the turret otherwise we can!

local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local Camera = game:GetService("Workspace").CurrentCamera
local Players = game:GetService("Players")
local LocalPlayer = Players.LocalPlayer

local Max = 100
local Min = -100

local function foo()
	local Character = workspace:FindFirstChild(LocalPlayer.Name)
	if not (Character) then return end
	
	local MousePos = UserInputService:GetMouseLocation()
	local ray = Camera:ViewportPointToRay(MousePos.X, MousePos.Y, 5) -- Mouse pos x,y, offset from camera
	
	local rayEnd = ray.Origin + (LocalPlayer.CameraMaxZoomDistance + 5) * ray.Direction.unit
	local CF = CFrame.new(rayEnd, rayEnd + ray.Direction)
	
	local Facing = Character.HumanoidRootPart.CFrame.LookVector
	local Angle = math.acos(Facing:Dot(CF.LookVector))
	
	if Angle < Max and Angle > Min then -- Move turret
		-- Move turret
	end
end

RunService:BindToRenderStep("foo", 150, foo)
1 Like