How would you go about creating a CCTV Camera system that moves the Camera with your mouse (just like when playing in first person)? Below is an example of what I’m looking for… I haven’t had the best of luck finding or thinking of ways to make this system so any ideas or knowledge would be great!
Inside a run service loop, using CFrame.lookAt
and update the CFrame of the camera to look at the mouse position, here is an example:
RunService.Heartbeat:Connect(function(dt)
camera.CFrame = CFrame.lookAt(camera.CFrame.Position,mouse.Hit.Position)
end)
although this does make the camera follow the mouse it doesn’t work like how first person works… the sensitivity is wayyy too high and the mouse still freely moves on the players screen…
I am giving you the layout to start from, you cannot ask for a full working script here sadly.
Here is some guidance:
- Lock the mouse using
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
(You might need to call this often so it doesn’t get overridden.) - Create a camera overlay (e.g. the box above, time stamps in the corner, etc) in a ScreenGui and add it to the player’s GUI when they use the camera
- You can get mouse movement with something like:
angleX = 0 -- Some starting angle
angleY = 0 -- Some starting angle
lastTime = tick()
local function onMouseMovement (actionName, inputState, inputObject)
currTime = tick()
dt = currTime - lastTime
angleY += inputObject.Delta.X * dt * ySensitivity
angleX += inputObject.Delta.Y * dt * xSensitivity
lastTime = currTime
end
ContextActionService:BindAction("MouseMovement", onMouseMovement, false, Enum.UserInputType.MouseMovement, Enum.UserInputType.Touch)
- You can make the camera feel more real by adding interpolation, since real cameras can’t move instantly:
-- Get the target CFrame based on the angle variables
--targetCFrame = CFrame.Angles(math.rad(angleX), math.rad(angleY), 0) + camPosition
-- Edit: the rotations need to be done separately, with the Y axis rotation first, as @SquarePapyrus12 pointed out:
local targetCFrame = CFrame.Angles(0, math.rad(angleY), 0) * CFrame.Angles(math.rad(angleX), 0, 0) + cameraPart.Position
-- Move the camera towards the target each frame
camera.CFrame = camera.CFrame:Lerp(targetCFrame, 0.05) -- Change 0.05 based on how "snappy" you want it to be, though note this speed will depend on frame rate with this equation
- Finally, you can limit the rotation by simply locking the angle variables before setting the camera CFrame:
-- For example, to lock the horizontal rotation between 100 degrees and 25 degrees:
if angleY > 100 then angleY = 100 end
if angleY < 25 then angleY = 25 end
I appreciate the guidance into this however, I only want the camera to be able to pan on the X and Y axis, why are we getting the Z axis and the position of the Camera? apart from that, I understand this and will play around with things!
Whoops, you’re right. I meant the x axis. I’ll fix that in the post.
okay so after some playing around and a handful of confusion I’ve ran into a problem with this system which is shown in the video below:
ISSUE
as you can probably see… the panning of the camera works just right when you’re looking at the Front face of the Camera Part but the second you rotate to the Right, Back or Left face the entire upwards and downwards rotation of the Camera starts going a bit… whacky
CODE
local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local camera = workspace.CurrentCamera
local cameraPart = workspace:WaitForChild("CameraPart")
game["Run Service"].Heartbeat:Connect(function(deltaTime)
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
end)
camera.CameraType = Enum.CameraType.Scriptable
camera.CFrame = workspace.CameraPart.CFrame
--[[ disabled for the sake of the video
local limitLR = 50
local limitUD = 50
]]
local angleY = 0
local angleX = 0
local function onMouseMovement(actionName, inputState, inputObject)
angleY += inputObject.Delta.X * -1
angleX += inputObject.Delta.Y * -1
local targetCFrame = CFrame.Angles(math.rad(angleX), math.rad(angleY), 0) + cameraPart.Position
camera.CFrame = camera.CFrame:Lerp(targetCFrame, 0.4) -- Change 0.05 based on how "snappy" you want it to be, though note this speed will depend on frame rate with this equation
cameraPart.CFrame = camera.CFrame
print(angleX, angleY)
--[[ disabled for the sake of the video
if angleY > limitLR then angleY = limitLR end
if angleY < -limitLR then angleY = -limitLR end
if angleX > limitUD then angleX = limitUD end
if angleX < -limitUD then angleX = -limitUD end
]]
end
ContextActionService:BindAction("MouseMovement", onMouseMovement, false, Enum.UserInputType.MouseMovement, Enum.UserInputType.Touch)
I couldn’t find anything about creating a Camera system like this until now and i’m grateful for the help I’ve recieved, I’m sure this post will be useful for others looking for such a specific mechanic
hopefully someone can help with this problem!
you need to first rotate on the y axis and then on the x axis, not both at the same time:
local targetCFrame = CFrame.Angles(0, math.rad(angleY), 0) * CFrame.Angles(math.rad(angleX), 0, 0) + cameraPart.Position
I believe @SquarePapyrus12 has the fix for this.
The code @SquarePapyrus12 provided first creates a CFrame rotated around the Y axis, then rotates that CFrame around the X axis relatively.
You can also manually remove the roll by doing:
local cframe = ...
cframe = CFrame.lookAt(cframe.Position, cframe.Position + cframe.LookAt)
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.