Likely what you were doing is using the position of the mouse and directly converting it to a point in world space. What I did was use how close the mouse was to the edge of the screen to decide how much to move the camera each frame. As for the math, here is my detailed explanation of each part, and it now works with any percentage as the margin of activation.
First, you need some sort of value to represent the minimum percentage of the screen away the mouse must be to activate the camera. It’ll look something like this:
local minPerX, minPerZ = 1 / 3, 1 / 4
This will be used later to decide when to move the camera based on the position of the mouse.
(Shows what a few places of activation are based on your minPerX. Just flip vertically for Y)
You also need the reciprocal of those two numbers minus 1 for later:
local minXActivation = 1 / minPerX - 1
local minZActivation = 1 / minPerZ - 1
From here on out, this will be in a render stepped loop.
You need the viewportSize and the mousePosition:
local viewport = camera.ViewportSize
local mousePos = uis:GetMouseLocation()
You need to get the ratio of the viewport size and the minPerX
and minPerZ
by doing something like this:
local viewX, viewZ = viewport.X * minPerX, viewport.Y * minPerZ
This gives the viewport as if it was only 1/3 or 1/4 (or whatever ratio you chose) the size. That means that if the mouse is at the far edge of the screen and you divide the mouse location by it as is done later, you will get a number near the reciprocal of the ratio.
Now is where the real math comes in.
You need to know what percent of the way the mouse is based on the percent of the viewport. If it is less than one, it is on the left side ready to activate, but if it is more than the reciprocal of the ratio-1 then it is on the right side.
The code for this would look like this:
local perX = mousePos.X / viewX
Now there are just some checks to see which side of the screen it is on.
if perX < 1 then
-- on the left side
elseif perX > minXActivation then
-- on the right side
end
Now to find the actual percent away from there, it depends on which side of the screen it is at. For the left side it will just be equal to 1-perX
because perX
is one when it is exactly on the viewX
ratio. 1-perX
flips it and gives the distance from the boundary not the screen.
If it is on the left side, there is a different step. It will be perX - minXActivation
. This means that we take the perX
, which is going to be more than the minXActivation
, but less than the full reciprocal, and subtract minXActivation
from it to get a number between 0 and 1, where 1 is at the far-right edge, and 0 is on the boundary line.
Now just multiply the perX
by the speed value, clamp the value, and apply!
(Then do the same thing for the Horizontal axis.)
local uis = game:GetService("UserInputService")
local camera = workspace.CurrentCamera
local maxDist = 500
local camSpeed = 100 -- in studs/sec
local angle = math.rad(-75)
local minPerX, minPerZ = 1 / 3, 1 / 4
local x, z = 0, 0
local minXActivation = 1 / minPerX - 1
local minZActivation = 1 / minPerZ - 1
game:GetService("RunService").RenderStepped:Connect(function(dt)
camera.CameraType = Enum.CameraType.Scriptable
local viewport = camera.ViewportSize
local mousePos = uis:GetMouseLocation()
local viewX, viewZ = viewport.X * minPerX, viewport.Y * minPerZ
local perX = mousePos.X / viewX
if perX < 1 then
-- it is on the left side of the margin
perX = (1 - perX) * (camSpeed * dt)
x = math.clamp(x - perX, -maxDist, maxDist)
elseif perX > minXActivation then
-- right side
perX = (perX - minXActivation) * (camSpeed * dt)
x = math.clamp(x + perX, -maxDist, maxDist)
end
local perZ = mousePos.Y / viewZ
if perZ < 1 then
perZ = (1 - perZ) * (camSpeed * dt)
z = math.clamp(z - perZ, -maxDist, maxDist)
elseif perZ > minZActivation then
perZ = (perZ - minZActivation) * (camSpeed * dt)
z = math.clamp(z + perZ, -maxDist, maxDist)
end
local currentPos = CFrame.new(x, 50, z)
camera.CFrame = currentPos * CFrame.Angles(angle, 0, 0)
end)