Camera Panning using BindToRenderStep and CFrame

Alright, I’ll get straight to the point. I am trying to script a system where you can pan the camera depending on the mouse and is dependent on if you are holding shift or not. My problem doesn’t lie within getting a boolean to stay true when holding shift, my problem is about having the camera pan. I’ve tried to mess around with CFrame but it ends up glitching horribly (e.g. moving mouse results in the camera to go in every direction), stays in one position and only facing one position, orbiting the player when moving and not working at all. Also note that I have a top-down camera view system in place.

Any solutions? Also, CFrame is not really my forte in scripting, particularly this kind.

What I’ve currently tried recently:

function RenderStepShiftCamera()
	if Player.Character and HoldingShift then
		local PP = Player.Character.HumanoidRootPart.Position -- this was leftover from top-down view when positioning camera to look down onto the player
		local CP = PP + CAMERA_OFFSET
		Camera.CFrame = CFrame.new(Mouse.Hit.p.x, 40, Mouse.Hit.p.z)
	end
end

TL;DR: I am trying to get a camera panning system dependent on the mouse. Take Hotline Miami’s system for example, where you hold shift to see more.

1 Like

Try it out, works really well.

features: camera panning when you press shift, move with your mouse to move camera, lerp, character faces direction of your mouse.

local cam = workspace.CurrentCamera
local char = script.Parent
local humpart = char:WaitForChild("HumanoidRootPart")
local humpos
local mouse = game.Players.LocalPlayer:GetMouse()
local UIS = game:GetService("UserInputService")
local pancam = false
local xunit,yunit = 0,0
local charrot = Vector3.new(0,humpart.Position.Y,0)
local lerpcharrot = Vector3.new(0,humpart.Position.Y,0)
local sensitivity = 10

UIS.InputBegan:Connect(function(inputObject)
	if inputObject.KeyCode == Enum.KeyCode.LeftShift then
		pancam = true
	end
end)

UIS.InputEnded:Connect(function(inputObject)
	if inputObject.KeyCode == Enum.KeyCode.LeftShift then
		pancam = false
	end
end)

function lerp(a, b, t)
	return a + (b - a) * t
end

function pan()
	cam.CameraType = "Scriptable"
	local mouseX = mouse.X
	local mouseY = mouse.Y
	local viewportX = mouse.ViewSizeX
	local viewportY = mouse.ViewSizeY
	local mouseXcenter = mouseX-viewportX/2
	local mouseYcenter = mouseY-viewportY/2
	xunit = math.abs(mouseXcenter)/(viewportY/2)
	if mouseXcenter < 0 then xunit = -xunit end
	yunit = math.abs(mouseYcenter)/(viewportY/2)
	if mouseYcenter < 0 then yunit = -yunit end
	humpos = humpart.Position
	cam.CFrame = cam.CFrame:lerp(CFrame.new(humpos+(Vector3.new(sensitivity,0,0)*xunit+Vector3.new(0,0,sensitivity)*yunit)+Vector3.new(0,30,0))*CFrame.Angles(math.rad(-90),0,0),0.2)
end
    
function topdownview()
	cam.CameraType = "Scriptable"
	humpos = humpart.Position
	cam.CFrame = cam.CFrame:lerp(CFrame.new(humpos+Vector3.new(0,20,0))*CFrame.Angles(math.rad(-90),0,0),0.2)
end

game:GetService("RunService").RenderStepped:Connect(function()
	if pancam then
		pan()
	else
		topdownview()
	end
	charrot = Vector3.new(mouse.Hit.p.X,humpart.Position.Y,mouse.Hit.p.Z)
	lerpcharrot = Vector3.new(lerp(lerpcharrot.X,charrot.X,0.2),humpart.Position.Y,lerp(lerpcharrot.Z,charrot.Z,0.2))
	humpart.CFrame = CFrame.new(humpart.CFrame.p,lerpcharrot)
end)
4 Likes

Two things:

  1. Did you set the camera type to Scriptable?
  2. Are you setting the camera subject to nil?

Also note that I have a top-down camera view system in place.

TL;DR: I am trying to get a camera panning system dependent on the mouse. Take Hotline Miami’s system for example, where you hold shift to see more.

He only needs help with panning the camera aka allowing player to move the camera with their mouse.

Thanks, it works! Although I do have to sort of configure it so the angle isn’t diagonal, I can manage that.

I did set camera type to scriptable, since I know it wouldn’t have the top-down view work. Didn’t set camera subject to nil but didn’t seem it was necessary to do so.

how is the angle diagonal?

the script creates a new cframe without any angles then applies 90 degree angle for top down view. nothing is diagonal.

The topdown view function you added was conflicting with my topdown view. All fixed now though.