Freecam angling weirdly

Hello.

So I’m trying to make a freecam for my game, but for some reason the freecam tilts its Z axis to the left.

This is how it looks:
https://gyazo.com/47a3edb21278666ceb49f90318e04c6d

Script:

local UserInputService = game:GetService("UserInputService")

local Camera = workspace.CurrentCamera

local rad = math.rad

local XDelta = 0
local ZDelta = 0

local XRot = 0
local YRot = 0

UserInputService.InputBegan:Connect(function(Input, Processed)
	if not Processed then
		if Input.KeyCode == Enum.KeyCode.W then
			ZDelta = ZDelta - 1
		elseif Input.KeyCode == Enum.KeyCode.S then
			ZDelta = ZDelta + 1
		elseif Input.KeyCode == Enum.KeyCode.A then
			XDelta = XDelta - 1
		elseif Input.KeyCode == Enum.KeyCode.D then
			XDelta = XDelta + 1
		elseif Input.KeyCode == Enum.KeyCode.Up then
			YRot = YRot + 1
		elseif Input.KeyCode == Enum.KeyCode.Down then
			YRot = YRot - 1
		elseif Input.KeyCode == Enum.KeyCode.Left then
			XRot = XRot + 1
		elseif Input.KeyCode == Enum.KeyCode.Right then
			XRot = XRot - 1
		end
	end
end)

UserInputService.InputEnded:Connect(function(Input)
	if Input.KeyCode == Enum.KeyCode.W then
		ZDelta = ZDelta + 1
	elseif Input.KeyCode == Enum.KeyCode.S then
		ZDelta = ZDelta - 1
	elseif Input.KeyCode == Enum.KeyCode.A then
		XDelta = XDelta + 1
	elseif Input.KeyCode == Enum.KeyCode.D then
		XDelta = XDelta - 1
	elseif Input.KeyCode == Enum.KeyCode.Up then
		YRot = YRot - 1
	elseif Input.KeyCode == Enum.KeyCode.Down then
		YRot = YRot + 1
	elseif Input.KeyCode == Enum.KeyCode.Left then
		XRot = XRot - 1
	elseif Input.KeyCode == Enum.KeyCode.Right then
		XRot = XRot + 1
	end
end)

function Freecam()
	Camera.CameraType = Enum.CameraType.Scriptable
	
	Camera.CFrame = Camera.CFrame * CFrame.Angles(rad(YRot), rad(XRot), 0) * CFrame.new(XDelta, 0, ZDelta)
end

If anyone could help, that would be appreciated.

3 Likes

I don’t think you can do something like rad = math.rad where you can set a function as a variable. Also, when setting variables, if they go blue (they means that it is a keyword), then use a different name or the script may not work.

Instead of setting math.rad as a variable, just write it in below.

1 Like

The reason this happens is because CFrame’s will rotate relative to the current rotation. This is what you want for the Y rotation, but not for the X rotation.
You’ll need to apply the X rotation before specifying any angle.

Example: (untested)

local Offset = Camera.CFrame * CFrame.new(XDelta, 0, ZDelta);
	
Camera.CFrame = CFrame.Angles(0, rad(XRot), 0) * Offset * CFrame.Angles(rad(YRot), 0, 0);
5 Likes

That’s not the problem. Setting rad to math.rad indeed works, as the function does not have parenthesis at the end of it.

Oh. That’s what I was missing. Thanks for your help!

1 Like

That’s not true. You can reference any function as a variable and call it as long as you have the right parameters. For a method like workspace:FindFirstChild(), you can do the following and it will still call correctly:

local findFirstChild = workspace.FindFirstChild

print(findFirstChild(workspace, “Baseplate”))

You can also overwrite blue colored variables without any issue, as so:

local p = print
local function print(...)
    p(“print override:”,...)
end

print(“Hello World!”)
3 Likes

Hey, sorry. I actually realized I made a mistake. That code will rotate around 0, 0, 0 world space, so if you freecam outward, it won’t rotate around your current position.

This code should fix that.

local Offset = Camera.CFrame * CFrame.new(XDelta, 0, ZDelta);
local CurrentRot = Camera.CFrame - Camera.CFrame.Position;
	
Camera.CFrame = CFrame.Angles(0, rad(XRot), 0) * CurrentRot * CFrame.Angles(rad(YRot), 0, 0) + Offset.Position;
	
1 Like

Thank you very much. Is there some way that I’m able to clamp the Y axis, though?
I’ve thought of using math.clamp, but for some reason it never seems to work.

You can use math.clamp, by using CFrame:ToOrientation() and clamping the X/Y axis.

1 Like

Ah, alright. Thank you for the help.

So I’m not really the best with math.clamp, and so some errors can happen.
I implemented the clamping feature, but now it does this.
https://gyazo.com/f9a361eb25c6513ac09523b2e1d15c87
Is there something I’m doing wrong?

function Freecam()
	Camera.CameraType = Enum.CameraType.Scriptable
	
	local Offset = Camera.CFrame * CFrame.new(XDelta, 0, ZDelta)
	local CurrentRot = Camera.CFrame - Camera.CFrame.Position
	local ToClamp = Camera.CFrame:ToOrientation()
	local ClampedY = clamp(ToClamp + YRot, 0, 180)
	Camera.CFrame = CFrame.Angles(0, rad(XRot), 0) * CurrentRot * CFrame.fromOrientation(rad(ClampedY), 0, 0) + Offset.Position
end

I don’t know how to solve this.

Yes, that is incorrect. ToOrientation returns a vararg (X, Y, Z)
If you want to clamp the tilting (up/down) then you’ll want to clamp the X axis;`

function Freecam()
	Camera.CameraType = Enum.CameraType.Scriptable
	
	local Offset = Camera.CFrame * CFrame.new(XDelta, 0, ZDelta);
	local CurrentRot = Camera.CFrame - Camera.CFrame.Position;
	
	local CF = CFrame.Angles(0, rad(XRot), 0) * CurrentRot * CFrame.Angles(rad(YRot), 0, 0) + Offset.Position;

	local ClampedX, Y, Z = CF:ToOrientation();
	ClampedX = math.clamp(ClampedX, -75, 75);

	workspace.CurrentCamera.CFrame = CFrame.new(CF.Position) * CFrame.fromOrientation(ClampedX, Y, Z)

end

I believe this could should work. (-75 and 75 being the min, max angles to clamp to.)

1 Like

Oh. Thank you for pointing out my errors.

Hm. For some reason, the clamped X is not angled correctly. It outputs this:
image
This is really weird.

Ah, my apologies.

Replace this line:
ClampedX = math.clamp(ClampedX, -75, 75);
with
ClampedX = math.clamp(ClampedX, rad(-75), rad(75));
I always forget to convert the degrees to radians when I clamp angles.

1 Like

It works beautifully now. Thank you for all your help.

1 Like