SyntaxGameServer/RCCService2020/ExtraContent/scripts/PlayerScripts/StarterPlayerScripts_NewStr.../PlayerModule.module/CameraModule/ClassicCamera.lua

372 lines
12 KiB
Lua

--[[
ClassicCamera - Classic Roblox camera control module
2018 Camera Update - AllYourBlox
Note: This module also handles camera control types Follow and Track, the
latter of which is currently not distinguished from Classic
--]]
-- Local private variables and constants
local ZERO_VECTOR2 = Vector2.new(0,0)
local tweenAcceleration = math.rad(220) -- Radians/Second^2
local tweenSpeed = math.rad(0) -- Radians/Second
local tweenMaxSpeed = math.rad(250) -- Radians/Second
local TIME_BEFORE_AUTO_ROTATE = 2 -- Seconds, used when auto-aligning camera with vehicles
local INITIAL_CAMERA_ANGLE = CFrame.fromOrientation(math.rad(-15), 0, 0)
local ZOOM_SENSITIVITY_CURVATURE = 0.5
local FFlagUserCameraToggle do
local success, result = pcall(function()
return UserSettings():IsUserFeatureEnabled("UserCameraToggle")
end)
FFlagUserCameraToggle = success and result
end
local FFlagUserCameraInputRefactor do
local success, result = pcall(function()
return UserSettings():IsUserFeatureEnabled("UserCameraInputRefactor2")
end)
FFlagUserCameraInputRefactor = success and result
end
--[[ Services ]]--
local PlayersService = game:GetService("Players")
local VRService = game:GetService("VRService")
local CameraInput = require(script.Parent:WaitForChild("CameraInput"))
local Util = require(script.Parent:WaitForChild("CameraUtils"))
--[[ The Module ]]--
local BaseCamera = require(script.Parent:WaitForChild("BaseCamera"))
local ClassicCamera = setmetatable({}, BaseCamera)
ClassicCamera.__index = ClassicCamera
function ClassicCamera.new()
local self = setmetatable(BaseCamera.new(), ClassicCamera)
self.isFollowCamera = false
self.isCameraToggle = false
self.lastUpdate = tick()
self.cameraToggleSpring = Util.Spring.new(5, 0)
return self
end
function ClassicCamera:GetCameraToggleOffset(dt)
assert(FFlagUserCameraToggle)
if self.isCameraToggle then
local zoom = self.currentSubjectDistance
if CameraInput.getTogglePan() then
self.cameraToggleSpring.goal = math.clamp(Util.map(zoom, 0.5, self.FIRST_PERSON_DISTANCE_THRESHOLD, 0, 1), 0, 1)
else
self.cameraToggleSpring.goal = 0
end
local distanceOffset = math.clamp(Util.map(zoom, 0.5, 64, 0, 1), 0, 1) + 1
return Vector3.new(0, self.cameraToggleSpring:step(dt)*distanceOffset, 0)
end
return Vector3.new()
end
-- Movement mode standardized to Enum.ComputerCameraMovementMode values
function ClassicCamera:SetCameraMovementMode(cameraMovementMode)
BaseCamera.SetCameraMovementMode(self, cameraMovementMode)
self.isFollowCamera = cameraMovementMode == Enum.ComputerCameraMovementMode.Follow
self.isCameraToggle = cameraMovementMode == Enum.ComputerCameraMovementMode.CameraToggle
end
function ClassicCamera:Update()
local now = tick()
local timeDelta = now - self.lastUpdate
local camera = workspace.CurrentCamera
local newCameraCFrame = camera.CFrame
local newCameraFocus = camera.Focus
local overrideCameraLookVector = nil
if self.resetCameraAngle then
local rootPart = self:GetHumanoidRootPart()
if rootPart then
overrideCameraLookVector = (rootPart.CFrame * INITIAL_CAMERA_ANGLE).lookVector
else
overrideCameraLookVector = INITIAL_CAMERA_ANGLE.lookVector
end
self.resetCameraAngle = false
end
local player = PlayersService.LocalPlayer
local humanoid = self:GetHumanoid()
local cameraSubject = camera.CameraSubject
local isInVehicle = cameraSubject and cameraSubject:IsA("VehicleSeat")
local isOnASkateboard = cameraSubject and cameraSubject:IsA("SkateboardPlatform")
local isClimbing = humanoid and humanoid:GetState() == Enum.HumanoidStateType.Climbing
if self.lastUpdate == nil or timeDelta > 1 then
self.lastCameraTransform = nil
end
local rotateInput
if FFlagUserCameraInputRefactor then
rotateInput = CameraInput.getRotation()
else
rotateInput = self.rotateInput
end
if FFlagUserCameraInputRefactor then
local zoom = self.currentSubjectDistance
local zoomDelta = CameraInput.getZoomDelta()
if math.abs(zoomDelta) > 0 then
local newZoom
if self.inFirstPerson and zoomDelta < 0 then
newZoom = 0.5
else
if zoomDelta > 0 then
newZoom = zoom + zoomDelta*(1 + zoom*ZOOM_SENSITIVITY_CURVATURE)
else
newZoom = (zoom + zoomDelta) / (1 - zoomDelta*ZOOM_SENSITIVITY_CURVATURE)
end
end
self:SetCameraToSubjectDistance(newZoom)
end
end
if self.lastUpdate and not FFlagUserCameraInputRefactor then
local gamepadRotation = self:UpdateGamepad()
if self:ShouldUseVRRotation() then
self.rotateInput = self.rotateInput + self:GetVRRotationInput()
else
-- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from
local delta = math.min(0.1, timeDelta)
if gamepadRotation ~= ZERO_VECTOR2 then
self.rotateInput = self.rotateInput + (gamepadRotation * delta)
end
local angle = 0
if not (isInVehicle or isOnASkateboard) then
angle = angle + (self.turningLeft and -120 or 0)
angle = angle + (self.turningRight and 120 or 0)
end
if angle ~= 0 then
self.rotateInput = self.rotateInput + Vector2.new(math.rad(angle * delta), 0)
end
end
end
local cameraHeight = self:GetCameraHeight()
-- Reset tween speed if user is panning
if FFlagUserCameraInputRefactor then
if CameraInput.getRotation() ~= Vector2.new() then
tweenSpeed = 0
self.lastUserPanCamera = tick()
end
else
if self.userPanningTheCamera then
tweenSpeed = 0
self.lastUserPanCamera = tick()
end
end
local userRecentlyPannedCamera = now - self.lastUserPanCamera < TIME_BEFORE_AUTO_ROTATE
local subjectPosition = self:GetSubjectPosition()
if subjectPosition and player and camera then
local zoom = self:GetCameraToSubjectDistance()
if zoom < 0.5 then
zoom = 0.5
end
if self:GetIsMouseLocked() and not self:IsInFirstPerson() then
-- We need to use the right vector of the camera after rotation, not before
local newLookCFrame
if FFlagUserCameraInputRefactor then
newLookCFrame = self:CalculateNewLookCFrameFromArg(overrideCameraLookVector, rotateInput)
else
newLookCFrame = self:CalculateNewLookCFrame(overrideCameraLookVector)
end
local offset = self:GetMouseLockOffset()
local cameraRelativeOffset = offset.X * newLookCFrame.rightVector + offset.Y * newLookCFrame.upVector + offset.Z * newLookCFrame.lookVector
--offset can be NAN, NAN, NAN if newLookVector has only y component
if Util.IsFiniteVector3(cameraRelativeOffset) then
subjectPosition = subjectPosition + cameraRelativeOffset
end
else
local userPanningTheCamera
if FFlagUserCameraInputRefactor then
userPanningTheCamera = CameraInput.getRotation() ~= Vector2.new()
else
userPanningTheCamera = self.userPanningTheCamera == true
end
if not userPanningTheCamera and self.lastCameraTransform then
local isInFirstPerson = self:IsInFirstPerson()
if (isInVehicle or isOnASkateboard or (self.isFollowCamera and isClimbing)) and self.lastUpdate and humanoid and humanoid.Torso then
if isInFirstPerson then
if self.lastSubjectCFrame and (isInVehicle or isOnASkateboard) and cameraSubject:IsA("BasePart") then
local y = -Util.GetAngleBetweenXZVectors(self.lastSubjectCFrame.lookVector, cameraSubject.CFrame.lookVector)
if Util.IsFinite(y) then
if FFlagUserCameraInputRefactor then
rotateInput = rotateInput + Vector2.new(y, 0)
else
self.rotateInput = self.rotateInput + Vector2.new(y, 0)
end
end
tweenSpeed = 0
end
elseif not userRecentlyPannedCamera then
local forwardVector = humanoid.Torso.CFrame.lookVector
if isOnASkateboard and not FFlagUserCameraInputRefactor then
forwardVector = cameraSubject.CFrame.lookVector
end
tweenSpeed = math.clamp(tweenSpeed + tweenAcceleration * timeDelta, 0, tweenMaxSpeed)
local percent = math.clamp(tweenSpeed * timeDelta, 0, 1)
if self:IsInFirstPerson() and not (self.isFollowCamera and self.isClimbing) then
percent = 1
end
local y = Util.GetAngleBetweenXZVectors(forwardVector, self:GetCameraLookVector())
if Util.IsFinite(y) and math.abs(y) > 0.0001 then
if FFlagUserCameraInputRefactor then
rotateInput = rotateInput + Vector2.new(y * percent, 0)
else
self.rotateInput = self.rotateInput + Vector2.new(y * percent, 0)
end
end
end
elseif self.isFollowCamera and (not (isInFirstPerson or userRecentlyPannedCamera) and not VRService.VREnabled) then
-- Logic that was unique to the old FollowCamera module
local lastVec = -(self.lastCameraTransform.p - subjectPosition)
local y = Util.GetAngleBetweenXZVectors(lastVec, self:GetCameraLookVector())
-- This cutoff is to decide if the humanoid's angle of movement,
-- relative to the camera's look vector, is enough that
-- we want the camera to be following them. The point is to provide
-- a sizable dead zone to allow more precise forward movements.
local thetaCutoff = 0.4
-- Check for NaNs
if Util.IsFinite(y) and math.abs(y) > 0.0001 and math.abs(y) > thetaCutoff * timeDelta then
rotateInput = rotateInput + Vector2.new(y, 0)
end
end
end
end
if not self.isFollowCamera then
local VREnabled = VRService.VREnabled
if VREnabled then
newCameraFocus = self:GetVRFocus(subjectPosition, timeDelta)
else
newCameraFocus = CFrame.new(subjectPosition)
end
local cameraFocusP = newCameraFocus.p
if VREnabled and not self:IsInFirstPerson() then
local vecToSubject = (subjectPosition - camera.CFrame.p)
local distToSubject = vecToSubject.magnitude
local flaggedRotateInput
if FFlagUserCameraInputRefactor then
flaggedRotateInput = rotateInput
else
flaggedRotateInput = self.rotateInput
end
-- Only move the camera if it exceeded a maximum distance to the subject in VR
if distToSubject > zoom or flaggedRotateInput.x ~= 0 then
local desiredDist = math.min(distToSubject, zoom)
if FFlagUserCameraInputRefactor then
vecToSubject = self:CalculateNewLookFromArg(nil, rotateInput) * desiredDist
else
vecToSubject = self:CalculateNewLookVector() * desiredDist
end
local newPos = cameraFocusP - vecToSubject
local desiredLookDir = camera.CFrame.lookVector
if flaggedRotateInput.x ~= 0 then
desiredLookDir = vecToSubject
end
local lookAt = Vector3.new(newPos.x + desiredLookDir.x, newPos.y, newPos.z + desiredLookDir.z)
if not FFlagUserCameraInputRefactor then
self.rotateInput = ZERO_VECTOR2
end
newCameraCFrame = CFrame.new(newPos, lookAt) + Vector3.new(0, cameraHeight, 0)
end
else
local newLookVector
if FFlagUserCameraInputRefactor then
newLookVector = self:CalculateNewLookVectorFromArg(overrideCameraLookVector, rotateInput)
else
newLookVector = self:CalculateNewLookVector(overrideCameraLookVector)
self.rotateInput = ZERO_VECTOR2
end
newCameraCFrame = CFrame.new(cameraFocusP - (zoom * newLookVector), cameraFocusP)
end
else -- is FollowCamera
local newLookVector
if FFlagUserCameraInputRefactor then
newLookVector = self:CalculateNewLookVectorFromArg(overrideCameraLookVector, rotateInput)
else
newLookVector = self:CalculateNewLookVector(overrideCameraLookVector)
self.rotateInput = ZERO_VECTOR2
end
if VRService.VREnabled then
newCameraFocus = self:GetVRFocus(subjectPosition, timeDelta)
else
newCameraFocus = CFrame.new(subjectPosition)
end
newCameraCFrame = CFrame.new(newCameraFocus.p - (zoom * newLookVector), newCameraFocus.p) + Vector3.new(0, cameraHeight, 0)
end
if FFlagUserCameraToggle then
local toggleOffset = self:GetCameraToggleOffset(timeDelta)
newCameraFocus = newCameraFocus + toggleOffset
newCameraCFrame = newCameraCFrame + toggleOffset
end
self.lastCameraTransform = newCameraCFrame
self.lastCameraFocus = newCameraFocus
if (isInVehicle or isOnASkateboard) and cameraSubject:IsA("BasePart") then
self.lastSubjectCFrame = cameraSubject.CFrame
else
self.lastSubjectCFrame = nil
end
end
self.lastUpdate = now
return newCameraCFrame, newCameraFocus
end
function ClassicCamera:EnterFirstPerson()
self.inFirstPerson = true
self:UpdateMouseBehavior()
end
function ClassicCamera:LeaveFirstPerson()
self.inFirstPerson = false
self:UpdateMouseBehavior()
end
return ClassicCamera