Camera movement restrictions

Hi, like the title says, I want to restrict the player’s camera movement.
Let me explain: I have a script that moves the camera using WASD. It works perfectly, however, I want to restrict it so it can only go 75 studs to the left and right, 150 studs forward, and 10 studs backwards.

Here is my script:

local limits = {
	Forward = 150,
	Left = 75, 
	Right = 75, 
	Back = 10 
}


local RunS = game:GetService("RunService")
local TagS = game:GetService("CollectionService")
local InputS = game:GetService("UserInputService")

local camera = game.Workspace.CurrentCamera
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local originalPos = camera.CFrame

local screen = Instance.new("ScreenGui", player.PlayerGui)

local CAMERA_MOVE_SPEED_MAX = 30
local CAMERA_MOVE_FORCE = 150
local cameraVelocity = Vector3.zero

function getCameraMoveDirInput(): Vector3
	local dir = Vector3.zero

	if InputS:IsKeyDown(Enum.KeyCode.D) then dir += Vector3.xAxis end
	if InputS:IsKeyDown(Enum.KeyCode.A) then dir -= Vector3.xAxis end
	if InputS:IsKeyDown(Enum.KeyCode.S) then dir += Vector3.zAxis end
	if InputS:IsKeyDown(Enum.KeyCode.W) then dir -= Vector3.zAxis end

	if dir ~= Vector3.zero then
		dir = dir.Unit
	end

	return dir	
end

function clampV3Magnitude(v: Vector3, min: number, max:number): Vector3
	return v.Unit * math.clamp(v.Magnitude, min,  max)
end

function updateCameraMovement(dt)
	local accelDir = getCameraMoveDirInput()

	if accelDir ~= Vector3.zero then
		cameraVelocity += CAMERA_MOVE_FORCE * accelDir * dt
		cameraVelocity = clampV3Magnitude(cameraVelocity, 0, CAMERA_MOVE_SPEED_MAX)
	else
		cameraVelocity *= math.clamp(1 - (15 * dt), 0, 1)
	end

	camera.CFrame += cameraVelocity * dt 
end


function updateCamera(dt)
	updateCameraMovement(dt)
end


camera.CameraType = Enum.CameraType.Scriptable
camera:GetPropertyChangedSignal("CameraType"):Connect(function()
	camera.CameraType = Enum.CameraType.Scriptable
end)

RunS.RenderStepped:Connect(updateCamera)
2 Likes

To restrict the camera’s movement within the specified limits, you should use a clamping function to constrain the camera’s position based on the limits before applying the movement.

function clampPosition(pos, originalPos, limits)
local x = math.clamp(pos.X, originalPos.X - limits.Left, originalPos.X + limits.Right)
local y = pos.Y – assuming you don’t want to clamp Y movement
local z = math.clamp(pos.Z, originalPos.Z - limits.Back, originalPos.Z + limits.Forward)
return Vector3.new(x, y, z)
end

function updateCameraMovement(dt)
local accelDir = getCameraMoveDirInput()

if accelDir ~= Vector3.zero then
    cameraVelocity += CAMERA_MOVE_FORCE * accelDir * dt
    cameraVelocity = clampV3Magnitude(cameraVelocity, 0, CAMERA_MOVE_SPEED_MAX)
else
    cameraVelocity *= math.clamp(1 - (15 * dt), 0, 1)
end

local newPosition = camera.CFrame.Position + cameraVelocity * dt
newPosition = clampPosition(newPosition, originalPos.Position, limits)
camera.CFrame = CFrame.new(newPosition)

end

2 Likes

Alright, thanks for your response.

2 Likes

Could you possibly apply it in the script I put? I don’t know how I should use this.

1 Like

Sure:

local limits = {
    Forward = 150,
    Left = 75,
    Right = 75,
    Back = 10
}

local RunS = game:GetService("RunService")
local TagS = game:GetService("CollectionService")
local InputS = game:GetService("UserInputService")

local camera = game.Workspace.CurrentCamera
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()
local originalPos = camera.CFrame

local screen = Instance.new("ScreenGui", player.PlayerGui)

local CAMERA_MOVE_SPEED_MAX = 30
local CAMERA_MOVE_FORCE = 150
local cameraVelocity = Vector3.zero

function getCameraMoveDirInput(): Vector3
    local dir = Vector3.zero

    if InputS:IsKeyDown(Enum.KeyCode.D) then dir += Vector3.xAxis end
    if InputS:IsKeyDown(Enum.KeyCode.A) then dir -= Vector3.xAxis end
    if InputS:IsKeyDown(Enum.KeyCode.S) then dir += Vector3.zAxis end
    if InputS:IsKeyDown(Enum.KeyCode.W) then dir -= Vector3.zAxis end

    if dir ~= Vector3.zero then
        dir = dir.Unit
    end

    return dir    
end

function clampV3Magnitude(v: Vector3, min: number, max:number): Vector3
    return v.Unit * math.clamp(v.Magnitude, min,  max)
end

function clampPosition(pos, originalPos, limits)
    local x = math.clamp(pos.X, originalPos.X - limits.Left, originalPos.X + limits.Right)
    local y = pos.Y -- assuming you don't want to clamp Y movement
    local z = math.clamp(pos.Z, originalPos.Z - limits.Back, originalPos.Z + limits.Forward)
    return Vector3.new(x, y, z)
end

function updateCameraMovement(dt)
    local accelDir = getCameraMoveDirInput()

    if accelDir ~= Vector3.zero then
        cameraVelocity += CAMERA_MOVE_FORCE * accelDir * dt
        cameraVelocity = clampV3Magnitude(cameraVelocity, 0, CAMERA_MOVE_SPEED_MAX)
    else
        cameraVelocity *= math.clamp(1 - (15 * dt), 0, 1)
    end

    local newPosition = camera.CFrame.Position + cameraVelocity * dt
    newPosition = clampPosition(newPosition, originalPos.Position, limits)
    camera.CFrame = CFrame.new(newPosition) * CFrame.Angles(camera.CFrame:ToOrientation())
end


function updateCamera(dt)
    updateCameraMovement(dt)
end

camera.CameraType = Enum.CameraType.Scriptable
camera:GetPropertyChangedSignal("CameraType"):Connect(function()
    camera.CameraType = Enum.CameraType.Scriptable
end)

RunS.RenderStepped:Connect(updateCamera)
1 Like

Thank you so much, it works. Although there is one issue, the camera is rotated 90 degrees to the left for some reason. I’ll try to fix it.

I edited the script, try it now.

1 Like


It’s glitching a lot now

Sorry for the delay, Roblox Studio was acting up. You might want to try replacing this line:

with this:

camera.CFrame = CFrame.new(newPosition) * CFrame.fromMatrix(Vector3.new(), camera.CFrame.RightVector, camera.CFrame.UpVector, camera.CFrame.LookVector)

Sorry in advance if it doesn’t work, I’m trying my best since Roblox studio is bugging out for me.

1 Like

Thanks for the response, I tried it out and It’s still glitching.

What’s happening is that it’s switching between 2 views every milisecond