Custom Camera System Offset

I’m programming an OTS Gun System, and within it, I have a custom camera system to zoom in and out during aiming and holding the gun (idling)

However, I’m having an issue with the offset of the camera. Once the gun is equipped, the function Camera:Enable() runs which is in the following module script. However, my camera is wonky and slightly put off to the right. This is due to the offset being set to Vector2.new(0,0).

My question is: instead of making a new vector, how would I keep the camera offset the same?

-- This module is responsible for the control of the player camera.
-- Will need to strap on stuff for camera effect modifiers and stuff later
local Camera = {}

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

local LocalPlayer = Players.LocalPlayer
local CurrentCamera = workspace.CurrentCamera
local Config = require(script:WaitForChild("Configuration"))

-- Runtime camera variables
Camera.Enabled = false
Camera.LastConfiguration = nil
Camera.CurrentOffset = Vector2.new(0, 0)

-- Runtime variables intended for external modification
Camera.MovePlayer = true -- variable used to determine whether or not we move the player
Camera.ForceScriptable = false -- variable used to make sure the camera is forced to be scriptable type
Camera.TransitionStartTime = -10000

Camera.CurrentTweens = {
	["Camera"] = nil,
	["HRP"] = nil
}

-- utility functions, only available when camera is disabled
function Camera:TweenLocation()
	
end

function Camera:SetLocation()
	
end

-- Set up our functions used to ensure the camera is in the right state (if enabled) and to detect if the camera is changed
local function AttachCameraType(CameraObject)
	CurrentCamera:GetPropertyChangedSignal("CameraType"):Connect(function()
		if CurrentCamera.CameraType ~= Enum.CameraType.Scriptable and Camera.ForceScriptable and Camera.Enabled then
			CurrentCamera.CameraType = Enum.CameraType.Scriptable
		end
	end)
end

local AncestryChanged = CurrentCamera.AncestryChanged:Connect(function()
	if Camera.Enabled then
		Camera:Disable()
		Camera:Enable()
		Camera.CurrentOffset = Vector2.new(0, 0)
		CurrentCamera = workspace.CurrentCamera
		AttachCameraType(CurrentCamera)
	end
end)

AttachCameraType(CurrentCamera)

-- Set up our function for listening to mobile camera movement
local LastPanTranslation
local CurrentPanOffset = Vector2.new(0, 0)

--[[
LastTranslation is the old Vector2 since the last update by TouchPan, and the CurrentOffset
is a Vector2 that is updated back to 0, 0 whenever GetCameraDelta is called.
]]
UserInputService.TouchPan:Connect(function(TouchPositions, TotalTranslation, _, State, GPE)
	if not GPE then
		if State == Enum.UserInputState.Begin then
			LastPanTranslation = TouchPositions[1]
		elseif State == Enum.UserInputState.Change or State == Enum.UserInputState.End then
			CurrentPanOffset = Vector2.new(
				CurrentPanOffset.X + (TotalTranslation.X - LastPanTranslation.X),
				CurrentPanOffset.Y + (TotalTranslation.Y - LastPanTranslation.Y)
				)
		end
	end
end)

-- utility function
function Camera:GetCameraDelta(DeltaTime) -- deltatime isn't used, but is passed in the case of future console support
	local TotalDeltaX, TotalDeltaY = 0,0
	if UserInputService.MouseEnabled then
		local Delta = UserInputService:GetMouseDelta()
		TotalDeltaX += (self.MouseSensitivityModifier * Delta.X/CurrentCamera.ViewportSize.X)
		TotalDeltaY += (self.MouseSensitivityModifier * Delta.Y/CurrentCamera.ViewportSize.Y)
	end
	
	if UserInputService.TouchEnabled then
		TotalDeltaX += self.MobileSensitivityModifier * CurrentPanOffset.X
		TotalDeltaY += self.MobileSensitivityModifier * CurrentPanOffset.Y
		CurrentPanOffset = Vector2.new(0, 0)
	end
	
	return TotalDeltaX, TotalDeltaY
end

function Camera:Enable()
	if self.Enabled then
		warn("Attempt to enable camera stopped as camera is already enabled.")
		return
	end
	
	local CameraX, CameraY = CurrentCamera.CFrame:ToOrientation()
	
	-- set our properties
	CurrentCamera.CameraType = Enum.CameraType.Scriptable
	
	-- reset current offset, need to change this to figure it out based upon current scriptable camera position
	self.CurrentOffset = Vector2.new(0,0)
	
	-- Reset our PanOffset so that old panning doesn't apply
	CurrentPanOffset = Vector2.new(0, 0)
	
	-- get our starting values
	local CameraX, CameraY = CurrentCamera.CFrame:ToOrientation()
	
	-- start the actual function
	RunService:BindToRenderStep(
		"YPlayerCamera",
		Enum.RenderPriority.Camera.Value - 5,
		function(DeltaTime)
			local MouseDown = UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton2)
			local Horizontal, Vertical, Angle
			local DeltaModifier = DeltaTime / (1/60)
			
			if time() < (self.TransitionStartTime + Config.TransitionTime) then
				local Modifier = ((self.TransitionStartTime + Config.TransitionTime) - time()) / Config.TransitionTime
				Horizontal = self.HorizontalOffset - ((self.HorizontalOffset - MouseDown and self.HorizontalOffset or self.HorizontalOffset + 3) * Modifier)
				Vertical = self.VerticalOffset - ((self.VerticalOffset - self.VerticalOffset or self.VerticalOffset + 1) * Modifier)
				Angle = self.OffsetAngle - ((self.OffsetAngle - self.LastConfiguration.OffsetAngle) * Modifier)
			else
				Horizontal = MouseDown and self.HorizontalOffset or self.HorizontalOffset + 3
				Vertical = MouseDown and self.VerticalOffset or self.VerticalOffset + 1
				Angle = self.OffsetAngle
			end

			-- force LockCenter
			UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
			
			local CurrentPosition, HRP
			if LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then
				HRP = LocalPlayer.Character.HumanoidRootPart
				CurrentPosition = HRP.Position
			else
				CurrentPosition = CurrentCamera.CFrame.Position
			end
			
			local DeltaX, DeltaY = self:GetCameraDelta(DeltaTime)
			self.CurrentOffset = Vector2.new(self.CurrentOffset.X - DeltaX, math.clamp(self.CurrentOffset.Y - DeltaY, -0.8, 0.8))
			local X, Y = self.CurrentOffset.X, self.CurrentOffset.Y

			local CameraTween = TweenService:Create(
				CurrentCamera,
				TweenInfo.new(DeltaTime * 2, Enum.EasingStyle.Linear, Enum.EasingDirection.In),

				{CFrame = CFrame.new(CurrentPosition)
				* CFrame.Angles(0, X, 0) 
				* CFrame.Angles(Y, 0, 0)
				* CFrame.new(Horizontal * math.sin(math.rad(Angle)),
					Vertical, 
					Horizontal * math.cos(math.rad(Angle)))}
			)
			if self.CurrentTweens["Camera"] then
				self.CurrentTweens["Camera"]:Cancel()
			end

			self.CurrentTweens["Camera"] = CameraTween
			CameraTween:Play()

			local HRPTween = TweenService:Create(
				HRP,
				TweenInfo.new(DeltaTime * 2, Enum.EasingStyle.Linear, Enum.EasingDirection.In),

				{CFrame = CFrame.new(CurrentPosition)
				* CFrame.Angles(0, X, 0)}
			)
			if self.CurrentTweens["HRP"] then
				self.CurrentTweens["HRP"]:Cancel()
			end

			self.CurrentTweens["HRP"] = HRPTween
			if MouseDown then
				HRPTween:Play()
			end

			--[[
			CurrentCamera.CFrame = CurrentCamera.CFrame:Lerp(CFrame.new(CurrentPosition) 
				* CFrame.Angles(0, X, 0) 
				* CFrame.Angles(Y, 0, 0)
				* CFrame.new(Horizontal * math.sin(math.rad(Angle)), 
					Vertical, 
					Horizontal * math.cos(math.rad(Angle)))
			, math.clamp(Config.CameraSpeed * DeltaModifier, 0, 1))
			
			if HRP then
				HRP.CFrame = CFrame.new(CurrentPosition)
					* CFrame.Angles(0, X, 0)
			end
			]]
		end
	)
end

function Camera:Disable()
	RunService:UnbindFromRenderStep("YPlayerCamera")
	CurrentCamera.CameraType = Enum.CameraType.Custom
	self.Enabled = false
end

function Camera:SetConfiguration(Data)
	if typeof(Data) == "string" then
		Data = Config["Presets"][Data]
	elseif typeof(Data) ~= "table" then
		warn("Invalid data sent to SetConfiguration")
		return
	end
	
	if self.LastConfiguration ~= nil then
		self.TransitionStartTime = time()
	else
		self.LastConfiguration = {}
	end
	
	for _, Name in pairs({"MouseSensitivityModifier", "MobileSensitivityModifier", "OffsetAngle", "HorizontalOffset", "VerticalOffset"}) do
		self.LastConfiguration[Name] = self[Name]
		self[Name] = Data[Name] or Config["Presets"]["Default"][Name]
	end
end

Camera:SetConfiguration("Default")

return Camera

Any help would be appreciated.

2 Likes

maybe try getting the current camera offset before running the part of the script that makes that problem happen, you can set the offset you had gotten beforehand as the current offset, just make a local variable with the current camera offset before running the script

2 Likes

How would I go about getting the current camera offset? I’ve tried this:

CurrentCamera.CFrame.LookVector

But this hasn’t seemed to work. It only seems to take Vector2 values.

im not very sure but i recommend you watch some videos on this subject