Help Making Camera Rotate System Based On Mouse

Basically, I want to recreate the Roblox camera rotation system that moves your camera about your character when you hold down right click. It’s kind of weird right now and it seems like it rotates about the head and it looks weird.

Video:

Code:

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")

local Player = Players.LocalPlayer

local Mouse = Player:GetMouse()

local StatsFrame = script.Parent

local camera = Instance.new("Camera")
camera.Parent = StatsFrame.Viewport.ViewportFrame
StatsFrame.Viewport.ViewportFrame.CurrentCamera = camera

local mouseInDisplay = false
local holdInDisplay = false

local currentX = 0
local currentY = 0

local diffX = 0
local diffY = 0

local lastX = 0
local lastY = 0

StatsFrame.Viewport.TextButton.MouseMoved:Connect(function(x, y)
	if holdInDisplay == false then
		return
	end
	diffX = x-currentX
	diffY = y-currentY
	currentX = x
	currentY = y
end)

StatsFrame.Viewport.TextButton.MouseEnter:Connect(function()
	mouseInDisplay = true
end)

StatsFrame.Viewport.TextButton.MouseLeave:Connect(function()
	mouseInDisplay = false
	holdInDisplay = false
end)

UserInputService.InputBegan:Connect(function(input)
	if mouseInDisplay and (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
		currentX = Mouse.X
		currentY = Mouse.Y
		holdInDisplay = true
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
		holdInDisplay = false
	end
end)

RunService.RenderStepped:Connect(function()
	if Player.Character == nil or Player.Character:FindFirstChild("HumanoidRootPart") == nil or Player.Character:FindFirstChild("Humanoid") == nil then
		return
	end
	
	local old = StatsFrame.Viewport.ViewportFrame:FindFirstChildWhichIsA("Model")
	if old then
		old:Destroy()
	end
	
	Player.Character.Archivable = true
	local c = Player.Character:Clone()
	c.Name = "Character"
	Player.Character.Archivable = false
	
	for _, v in pairs(c:GetDescendants()) do
		if v:IsA("Humanoid") then
			v.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
		end
		if v:IsA("BaseScript") or v:IsA("SelectionBox") then
			v:Destroy()
		end
	end
	
	c.Parent = StatsFrame.Viewport.ViewportFrame
	lastX += diffX
	lastY += diffY
	diffX = 0
	diffY = 0
	c:PivotTo(c:GetPivot() * CFrame.fromEulerAnglesXYZ(0, math.rad(lastX), math.rad(lastY)))
	  
	--StatsFrame.Viewport.ViewportFrame.Character:PivotTo(StatsFrame.Viewport.ViewportFrame.Character:GetPivot() * CFrame.Angles(0, rawAngle, 0))
	
	--StatsFrame.Viewport.ViewportFrame.Character:PivotTo(StatsFrame.Viewport.ViewportFrame.Character:GetPivot() * CFrame.Angles(0, -math.rad(Player.Character.HumanoidRootPart.Orientation.Y), 0))
	
	local size = Player.Character:GetExtentsSize()
	
	--local x, y, z = workspace.CurrentCamera.CFrame:ToOrientation()
	
	--x -= math.rad(Player.Character.HumanoidRootPart.Orientation.X)
	--y -= math.rad(Player.Character.HumanoidRootPart.Orientation.Y)
	--z -= math.rad(Player.Character.HumanoidRootPart.Orientation.Z)
	
	--StatsFrame.Viewport.ViewportFrame.Character:PivotTo(StatsFrame.Viewport.ViewportFrame.Character:GetPivot()*CFrame.Angles(0, y, 0))
	
	StatsFrame.Viewport.ViewportFrame.CurrentCamera = camera
	local maxSize = math.sqrt(size.X^2 + size.Y^2 + size.Z^2)
	local depth = maxSize / math.tan(math.rad(camera.FieldOfView))
	local center = Player.Character.HumanoidRootPart.Position
	local direction = workspace.CurrentCamera.CFrame.Position-Player.Character.HumanoidRootPart.Position
	--camera.CFrame = CFrame.new(center.X, center.Y-0.5, center.Z - depth^1.65) * CFrame.Angles(0, math.pi, 0)
	local dir = (Player.Character.HumanoidRootPart.Position - workspace.CurrentCamera.CFrame.Position).Unit
	local x, y, z = workspace.CurrentCamera.CFrame:ToOrientation()
	camera.CFrame = CFrame.lookAt(Player.Character.HumanoidRootPart.Position+dir*-((depth/1.15)^2), Player.Character.HumanoidRootPart.Position)
	--camera.CFrame = Player.Character.HumanoidRootPart.CFrame * CFrame.new(1.25, 4.5/1.75, -8/1.75) * CFrame.Angles(math.rad(30), math.rad(165), math.rad(-7.5))
end)

StatsFrame.Parent.LoadoutDisplay.CurrentSlot.Changed:Connect(function(number)
	if StatsFrame.Parent.LoadoutDisplay:FindFirstChild(tostring(number)) == nil or StatsFrame.Parent.LoadoutDisplay:FindFirstChild(tostring(number)):GetAttribute("WeaponName") == nil then
		StatsFrame.Equipped.Text = "[ None ]"
		return
	end
1 Like

you can detect the mouse clcik and calculate the mouse position when moved using delta or something it’s hard to explain but I made a whole new camera system for one of my games before and it was pretty simple but it was only first person since that was whle poijtn of the game

Ok I’ll try that, thanks!
Btw did you enjoy the music in the background of the video? Isn’t the song pretty good?

1 Like

ngl that was the best song i heard in a while :skull:

yes it truly changed my life honestly

In case this isn’t yet solved, I had to make a system like this for a game. I’ll put the snippet here so you can use it as a reference because I’m lazy.

In this example I left out the vertical rotation because I didn’t find it necessary for what I was making.

local UserInputService = game:GetService("UserInputService")
local Mouse = game:GetService("Players").LocalPlayer:GetMouse()
local camera = Instance.new("Camera")
local Rotate = false
local LastMousePosition = Vector2.new(Mouse.X, Mouse.Y)
local Model = script.Parent:FindFirstChildOfClass("Model")

local Zoom = 1
local DefaultZoom = 1
local MaxZoom = 2
local MinZoom = 0.5

camera.Parent = script.Parent
script.Parent.CurrentCamera = camera
camera.CFrame = CFrame.new(0, 0, 0)

local Sensitivity = 2

script.Parent.ChildAdded:Connect(function(child)
	if child:IsA("Model") then
		Model = child
		
		Zoom = DefaultZoom
	end
end)

script.Parent.ChildRemoved:Connect(function(child)
	if child:IsA("Model") then
		Model = nil
		
		camera.CFrame = CFrame.new(0, 0, 0)
		
		Zoom = DefaultZoom
	end
end)

UserInputService.PointerAction:Connect(function(wheel, pan, pinch, processed)
	if not script:FindFirstAncestorOfClass("ScreenGui").Enabled then return end
	
	if processed then return end
	
	if wheel >= 0 then
		Zoom = math.clamp(Zoom - 0.1, MinZoom, MaxZoom)
	end
	
	if wheel <= 0 then
		Zoom = math.clamp(Zoom + 0.1, MinZoom, MaxZoom)
	end
end)

UserInputService.InputBegan:Connect(function(input, gameProcessed)
	if not script:FindFirstAncestorOfClass("ScreenGui").Enabled then return end
	
	if gameProcessed then return end
	
	if input.UserInputType == Enum.UserInputType.MouseButton3 then
		Zoom = DefaultZoom
	end
	
	if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
		Rotate = true
	end

end)

UserInputService.InputEnded:Connect(function(input, gameProcessed)
if not script:FindFirstAncestorOfClass(“ScreenGui”).Enabled then return end

if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
	Rotate = false
end

end)

game:GetService(“RunService”).RenderStepped:Connect(function()
if not script:FindFirstAncestorOfClass(“ScreenGui”).Enabled then return end

if not Model then return end

camera.CFrame = CFrame.Angles(0, if Rotate then UserInputService:GetMouseLocation().X * math.pi / (-180 * Sensitivity) else 0, 0) * CFrame.new(0, -1, 5 * Zoom) + Model:GetPivot().Position

end)

It might not look like it but it does actually work on mobile. Mine has zoom control too, if you want that then you can have it but I don’t think it’s part of your example.

Also, I made it to where it will reset every time you let go of the turn, if this is undesired I can elaborate.

Hope this helps!

EDIT: Unsure why it won’t let me put it all in one, so sorry about that but the script should still be alright.

I’ll check this out, thanks!
Make sure you watch the video btw, I really mess with the song and I think you will as well.