Guest User

Untitled

a guest
May 9th, 2018
720
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 48.45 KB | None | 0 0
  1.  
  2. local PlayersService = game:GetService('Players')
  3. local UserInputService = game:GetService('UserInputService')
  4. local StarterGui = game:GetService('StarterGui')
  5. local GuiService = game:GetService('GuiService')
  6. local ContextActionService = game:GetService('ContextActionService')
  7. local VRService = game:GetService("VRService")
  8.  
  9. local LocalPlayer = PlayersService.LocalPlayer
  10. local PlayerGui = nil
  11. if LocalPlayer then
  12.     PlayerGui = PlayersService.LocalPlayer:WaitForChild("PlayerGui")
  13. end
  14.  
  15. local PortraitMode = false
  16.  
  17. local CameraScript = script.Parent
  18. local ShiftLockController = require(CameraScript:WaitForChild('ShiftLockController'))
  19.  
  20. local Settings = UserSettings()
  21. local GameSettings = Settings.GameSettings
  22.  
  23. local function clamp(low, high, num)
  24.     return (num > high and high or num < low and low or num)
  25. end
  26.  
  27. local math_atan2 = math.atan2
  28. local function findAngleBetweenXZVectors(vec2, vec1)
  29.     return math_atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z)
  30. end
  31.  
  32. local function IsFinite(num)
  33.     return num == num and num ~= 1/0 and num ~= -1/0
  34. end
  35.  
  36. local THUMBSTICK_DEADZONE = 0.2
  37.  
  38. local LANDSCAPE_DEFAULT_ZOOM = 12.5
  39. local PORTRAIT_DEFAULT_ZOOM = 25
  40.  
  41. local humanoidCache = {}
  42. local function findPlayerHumanoid(player)
  43.     local character = player and player.Character
  44.     if character then
  45.         local resultHumanoid = humanoidCache[player]
  46.         if resultHumanoid and resultHumanoid.Parent == character then
  47.             return resultHumanoid
  48.         else
  49.             humanoidCache[player] = nil -- Bust Old Cache
  50.             local humanoid = character:FindFirstChildOfClass("Humanoid")
  51.             if humanoid then
  52.                 humanoidCache[player] = humanoid
  53.             end
  54.             return humanoid
  55.         end
  56.     end
  57. end
  58.  
  59. local MIN_Y = math.rad(-80)
  60. local MAX_Y = math.rad(80)
  61.  
  62. local VR_ANGLE = math.rad(15)
  63.  
  64. local VR_LOW_INTENSITY_ROTATION = Vector2.new(math.rad(15), 0)
  65. local VR_HIGH_INTENSITY_ROTATION = Vector2.new(math.rad(45), 0)
  66. local VR_LOW_INTENSITY_REPEAT = 0.1
  67. local VR_HIGH_INTENSITY_REPEAT = 0.4
  68.  
  69. local ZERO_VECTOR2 = Vector2.new(0, 0)
  70. local ZERO_VECTOR3 = Vector3.new(0, 0, 0)
  71.  
  72. local TOUCH_SENSITIVTY = Vector2.new(math.pi*2.25, math.pi*2)
  73. local MOUSE_SENSITIVITY = Vector2.new(math.pi*4, math.pi*1.9)
  74.  
  75. local MAX_TIME_FOR_DOUBLE_TAP = 1.5
  76. local MAX_TAP_POS_DELTA = 15
  77. local MAX_TAP_TIME_DELTA = 0.75
  78.  
  79. local SEAT_OFFSET = Vector3.new(0,5,0)
  80. local VR_SEAT_OFFSET = Vector3.new(0, 4, 0)
  81. local HEAD_OFFSET = Vector3.new(0, 1.5, 0)
  82. local R15_HEAD_OFFSET = Vector3.new(0, 2.0, 0)
  83.  
  84. local PORTRAIT_MODE_CAMERA_OFFSET = 2
  85.  
  86. -- Reset the camera look vector when the camera is enabled for the first time
  87. local SetCameraOnSpawn = true
  88.  
  89. local hasGameLoaded = false
  90.  
  91. local GestureArea = nil
  92.  
  93. --todo: remove this once TouchTapInWorld is on all platforms
  94. local touchWorkspaceEventEnabled = pcall(function() local test = UserInputService.TouchTapInWorld end)
  95.  
  96. local function layoutGestureArea(portraitMode)
  97.     if GestureArea then
  98.         if portraitMode then
  99.             GestureArea.Size = UDim2.new(1, 0, .6, 0)
  100.             GestureArea.Position = UDim2.new(0, 0, 0, 0)
  101.         else
  102.             GestureArea.Size = UDim2.new(1, 0, .5, -18)
  103.             GestureArea.Position = UDim2.new(0, 0, 0, 0)
  104.         end
  105.     end
  106. end
  107.  
  108. -- Setup gesture area that camera uses while DynamicThumbstick is enabled
  109. local function OnCharacterAdded(character)
  110.     if UserInputService.TouchEnabled then
  111.         if PlayerGui then
  112.             local ScreenGui = Instance.new("ScreenGui")
  113.             ScreenGui.Name = "GestureArea"
  114.             ScreenGui.Parent = PlayerGui
  115.            
  116.             GestureArea = Instance.new("Frame")
  117.             GestureArea.BackgroundTransparency = 1.0
  118.             GestureArea.Visible = true
  119.             GestureArea.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
  120.             layoutGestureArea(PortraitMode)
  121.             GestureArea.Parent = ScreenGui
  122.            
  123.         end
  124.         for _, child in ipairs(LocalPlayer.Character:GetChildren()) do
  125.             if child:IsA("Tool") then
  126.                 IsAToolEquipped = true
  127.             end
  128.         end
  129.         character.ChildAdded:Connect(function(child)
  130.             if child:IsA("Tool") then
  131.                 IsAToolEquipped = true
  132.             end
  133.         end)
  134.         character.ChildRemoved:Connect(function(child)
  135.             if child:IsA("Tool") then
  136.                 IsAToolEquipped = false
  137.             end
  138.         end)
  139.     end
  140. end
  141.  
  142. if LocalPlayer then
  143.     if LocalPlayer.Character ~= nil then
  144.         OnCharacterAdded(LocalPlayer.Character)
  145.     end
  146.     LocalPlayer.CharacterAdded:connect(function(character)
  147.         OnCharacterAdded(character)
  148.     end)
  149. end
  150.    
  151.    
  152. local function positionIntersectsGuiObject(position, guiObject)
  153.     if position.X < guiObject.AbsolutePosition.X + guiObject.AbsoluteSize.X
  154.         and position.X > guiObject.AbsolutePosition.X
  155.         and position.Y < guiObject.AbsolutePosition.Y + guiObject.AbsoluteSize.Y
  156.         and position.Y > guiObject.AbsolutePosition.Y then
  157.         return true
  158.     end
  159.     return false
  160. end
  161.  
  162. local function GetRenderCFrame(part)
  163.     return part:GetRenderCFrame()
  164. end
  165.  
  166. local function CreateCamera()
  167.     local this = {}
  168.     local R15HeadHeight = R15_HEAD_OFFSET
  169.     function this:GetActivateValue()
  170.         return 0.7
  171.     end
  172.    
  173.     function this:IsPortraitMode()
  174.         return PortraitMode
  175.     end
  176.    
  177.     function this:GetRotateAmountValue(vrRotationIntensity)
  178.         vrRotationIntensity = vrRotationIntensity or StarterGui:GetCore("VRRotationIntensity")
  179.         if vrRotationIntensity then
  180.             if vrRotationIntensity == "Low" then
  181.                 return VR_LOW_INTENSITY_ROTATION
  182.             elseif vrRotationIntensity == "High" then
  183.                 return VR_HIGH_INTENSITY_ROTATION
  184.             end
  185.         end
  186.         return ZERO_VECTOR2
  187.     end
  188.     function this:GetRepeatDelayValue(vrRotationIntensity)
  189.         vrRotationIntensity = vrRotationIntensity or StarterGui:GetCore("VRRotationIntensity")
  190.         if vrRotationIntensity then
  191.             if vrRotationIntensity == "Low" then
  192.                 return VR_LOW_INTENSITY_REPEAT
  193.             elseif vrRotationIntensity == "High" then
  194.                 return VR_HIGH_INTENSITY_REPEAT
  195.             end
  196.         end
  197.         return 0
  198.     end
  199.    
  200.     this.ShiftLock = false
  201.     this.Enabled = false
  202.     local isFirstPerson = false
  203.     local isRightMouseDown = false
  204.     local isMiddleMouseDown = false
  205.     this.RotateInput = ZERO_VECTOR2
  206.     this.DefaultZoom = LANDSCAPE_DEFAULT_ZOOM
  207.     this.activeGamepad = nil
  208.    
  209.     local tweens = {}
  210.  
  211.     this.lastSubject = nil
  212.     this.lastSubjectPosition = Vector3.new(0, 5, 0)
  213.  
  214.     local lastVRRotation = 0
  215.     local vrRotateKeyCooldown = {}
  216.    
  217.     local isDynamicThumbstickEnabled = false
  218.    
  219.     -- Check for changes in ViewportSize to decide if PortraitMode
  220.     local CameraChangedConn = nil
  221.     local workspaceCameraChangedConn = nil
  222.     local function onWorkspaceCameraChanged()
  223.         if UserInputService.TouchEnabled then
  224.             if CameraChangedConn then
  225.                 CameraChangedConn:Disconnect()
  226.                 CameraChangedConn = nil
  227.             end
  228.             local newCamera = workspace.CurrentCamera
  229.             if newCamera then
  230.                 local size = newCamera.ViewportSize
  231.                 PortraitMode = size.X < size.Y
  232.                 layoutGestureArea(PortraitMode)
  233.                 DefaultZoom = PortraitMode and PORTRAIT_DEFAULT_ZOOM or LANDSCAPE_DEFAULT_ZOOM
  234.                 CameraChangedConn = newCamera:GetPropertyChangedSignal("ViewportSize"):Connect(function()
  235.                     size = newCamera.ViewportSize
  236.                     PortraitMode = size.X < size.Y
  237.                     layoutGestureArea(PortraitMode)
  238.                     DefaultZoom = PortraitMode and PORTRAIT_DEFAULT_ZOOM or LANDSCAPE_DEFAULT_ZOOM
  239.                 end)
  240.             end
  241.         end
  242.     end
  243.     workspaceCameraChangedConn = workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(onWorkspaceCameraChanged)
  244.     if workspace.CurrentCamera then
  245.         onWorkspaceCameraChanged()
  246.     end
  247.        
  248.    
  249.     function this:GetShiftLock()
  250.         return ShiftLockController:IsShiftLocked()
  251.     end
  252.  
  253.     function this:GetHumanoid()
  254.         local player = PlayersService.LocalPlayer
  255.         return findPlayerHumanoid(player)
  256.     end
  257.  
  258.     function this:GetHumanoidRootPart()
  259.         local humanoid = this:GetHumanoid()
  260.         return humanoid and humanoid.Torso
  261.     end
  262.  
  263.     function this:GetRenderCFrame(part)
  264.         GetRenderCFrame(part)
  265.     end
  266.    
  267.     local STATE_DEAD = Enum.HumanoidStateType.Dead
  268.    
  269.     -- HumanoidRootPart when alive, Head part when dead
  270.     local function getHumanoidPartToFollow(humanoid, humanoidStateType)
  271.         if humanoidStateType == STATE_DEAD then
  272.             local character = humanoid.Parent
  273.             if character then
  274.                 return character:FindFirstChild("Head") or humanoid.Torso
  275.             else
  276.                 return humanoid.Torso
  277.             end
  278.         else
  279.             return humanoid.Torso
  280.         end
  281.     end
  282.  
  283.     local HUMANOID_STATE_DEAD = Enum.HumanoidStateType.Dead
  284.    
  285.     function this:GetSubjectPosition()
  286.         local result = nil
  287.         local camera = workspace.CurrentCamera
  288.         local cameraSubject = camera and camera.CameraSubject
  289.         if cameraSubject then
  290.             if cameraSubject:IsA('Humanoid') then
  291.                 local humanoidStateType = cameraSubject:GetState()
  292.                 if VRService.VREnabled and humanoidStateType == STATE_DEAD and cameraSubject == this.lastSubject then
  293.                     result = this.lastSubjectPosition
  294.                 else
  295.                     local humanoidRootPart = getHumanoidPartToFollow(cameraSubject, humanoidStateType)
  296.                     if humanoidRootPart and humanoidRootPart:IsA('BasePart') then
  297.                         local subjectCFrame = GetRenderCFrame(humanoidRootPart)
  298.                         local heightOffset = ZERO_VECTOR3
  299.                         if humanoidStateType ~= STATE_DEAD then
  300.                             heightOffset = cameraSubject.RigType == Enum.HumanoidRigType.R15 and R15HeadHeight or HEAD_OFFSET
  301.                         end
  302.  
  303.                         if PortraitMode then
  304.                             heightOffset = heightOffset + Vector3.new(0, PORTRAIT_MODE_CAMERA_OFFSET, 0)
  305.                         end
  306.  
  307.                         result = subjectCFrame.p +
  308.                             subjectCFrame:vectorToWorldSpace(heightOffset + cameraSubject.CameraOffset)
  309.                     end
  310.                 end
  311.             elseif cameraSubject:IsA('VehicleSeat') then
  312.                 local subjectCFrame = GetRenderCFrame(cameraSubject)
  313.                 local offset = SEAT_OFFSET
  314.                 if VRService.VREnabled then
  315.                     offset = VR_SEAT_OFFSET
  316.                 end
  317.                 result = subjectCFrame.p + subjectCFrame:vectorToWorldSpace(offset)
  318.             elseif cameraSubject:IsA('SkateboardPlatform') then
  319.                 local subjectCFrame = GetRenderCFrame(cameraSubject)
  320.                 result = subjectCFrame.p + SEAT_OFFSET
  321.             elseif cameraSubject:IsA('BasePart') then
  322.                 local subjectCFrame = GetRenderCFrame(cameraSubject)
  323.                 result = subjectCFrame.p
  324.             elseif cameraSubject:IsA('Model') then
  325.                 result = cameraSubject:GetModelCFrame().p
  326.             end
  327.         end
  328.         this.lastSubject = cameraSubject
  329.         this.lastSubjectPosition = result
  330.         return result
  331.     end
  332.  
  333.     function this:ResetCameraLook()
  334.     end
  335.  
  336.     function this:GetCameraLook()
  337.         return workspace.CurrentCamera and workspace.CurrentCamera.CoordinateFrame.lookVector or Vector3.new(0,0,1)
  338.     end
  339.  
  340.     function this:GetCameraZoom()
  341.         if this.currentZoom == nil then
  342.             local player = PlayersService.LocalPlayer
  343.             this.currentZoom = player and clamp(player.CameraMinZoomDistance, player.CameraMaxZoomDistance, this.DefaultZoom) or this.DefaultZoom
  344.         end
  345.         return this.currentZoom
  346.     end
  347.  
  348.     function this:GetCameraActualZoom()
  349.         local camera = workspace.CurrentCamera
  350.         if camera then
  351.             return (camera.CoordinateFrame.p - camera.Focus.p).magnitude
  352.         end
  353.     end
  354.  
  355.     function this:GetCameraHeight()
  356.         if VRService.VREnabled and not this:IsInFirstPerson() then
  357.             local zoom = this:GetCameraZoom()
  358.             return math.sin(VR_ANGLE) * zoom
  359.         end
  360.         return 0
  361.     end
  362.  
  363.     function this:ViewSizeX()
  364.         local result = 1024
  365.         local camera = workspace.CurrentCamera
  366.         if camera then
  367.             result = camera.ViewportSize.X
  368.         end
  369.         return result
  370.     end
  371.  
  372.     function this:ViewSizeY()
  373.         local result = 768
  374.         local camera = workspace.CurrentCamera
  375.         if camera then
  376.             result = camera.ViewportSize.Y
  377.         end
  378.         return result
  379.     end
  380.  
  381.    
  382.     local math_asin = math.asin
  383.     local math_atan2 = math.atan2
  384.     local math_floor = math.floor
  385.     local math_max = math.max
  386.     local math_pi = math.pi
  387.     local Vector2_new = Vector2.new
  388.     local Vector3_new = Vector3.new
  389.     local CFrame_Angles = CFrame.Angles
  390.     local CFrame_new = CFrame.new
  391.  
  392.     function this:ScreenTranslationToAngle(translationVector)
  393.         local screenX = this:ViewSizeX()
  394.         local screenY = this:ViewSizeY()
  395.         local xTheta = (translationVector.x / screenX)
  396.         local yTheta = (translationVector.y / screenY)
  397.         return Vector2_new(xTheta, yTheta)
  398.     end
  399.  
  400.     function this:MouseTranslationToAngle(translationVector)
  401.         local xTheta = (translationVector.x / 1920)
  402.         local yTheta = (translationVector.y / 1200)
  403.         return Vector2_new(xTheta, yTheta)
  404.     end
  405.  
  406.     function this:RotateVector(startVector, xyRotateVector)
  407.         local startCFrame = CFrame_new(ZERO_VECTOR3, startVector)
  408.         local resultLookVector = (CFrame_Angles(0, -xyRotateVector.x, 0) * startCFrame * CFrame_Angles(-xyRotateVector.y,0,0)).lookVector
  409.         return resultLookVector, Vector2_new(xyRotateVector.x, xyRotateVector.y)
  410.     end
  411.  
  412.     function this:RotateCamera(startLook, xyRotateVector)
  413.         if VRService.VREnabled then
  414.             local yawRotatedVector, xyRotateVector = self:RotateVector(startLook, Vector2.new(xyRotateVector.x, 0))
  415.             return Vector3_new(yawRotatedVector.x, 0, yawRotatedVector.z).unit, xyRotateVector
  416.         else
  417.             local startVertical = math_asin(startLook.y)
  418.             local yTheta = clamp(-MAX_Y + startVertical, -MIN_Y + startVertical, xyRotateVector.y)
  419.             return self:RotateVector(startLook, Vector2_new(xyRotateVector.x, yTheta))
  420.         end
  421.     end
  422.  
  423.     function this:IsInFirstPerson()
  424.         return isFirstPerson
  425.     end
  426.  
  427.     -- there are several cases to consider based on the state of input and camera rotation mode
  428.     function this:UpdateMouseBehavior()
  429.         -- first time transition to first person mode or shiftlock
  430.         if isFirstPerson or self:GetShiftLock() then
  431.             pcall(function() GameSettings.RotationType = Enum.RotationType.CameraRelative end)
  432.             if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
  433.                 UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
  434.             end
  435.         else
  436.             pcall(function() GameSettings.RotationType = Enum.RotationType.MovementRelative end)
  437.             if isRightMouseDown or isMiddleMouseDown then
  438.                 UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
  439.             else
  440.                 UserInputService.MouseBehavior = Enum.MouseBehavior.Default
  441.             end
  442.         end
  443.     end
  444.  
  445.     function this:ZoomCamera(desiredZoom)
  446.         local player = PlayersService.LocalPlayer
  447.         if player then
  448.             if player.CameraMode == Enum.CameraMode.LockFirstPerson then
  449.                 this.currentZoom = 0
  450.             else
  451.                 this.currentZoom = clamp(player.CameraMinZoomDistance, player.CameraMaxZoomDistance, desiredZoom)
  452.             end
  453.         end
  454.  
  455.         isFirstPerson = self:GetCameraZoom() < 2
  456.  
  457.         ShiftLockController:SetIsInFirstPerson(isFirstPerson)
  458.         -- set mouse behavior
  459.         self:UpdateMouseBehavior()
  460.         return self:GetCameraZoom()
  461.     end
  462.  
  463.     function this:rk4Integrator(position, velocity, t)
  464.         local direction = velocity < 0 and -1 or 1
  465.         local function acceleration(p, v)
  466.             local accel = direction * math_max(1, (p / 3.3) + 0.5)
  467.             return accel
  468.         end
  469.  
  470.         local p1 = position
  471.         local v1 = velocity
  472.         local a1 = acceleration(p1, v1)
  473.         local p2 = p1 + v1 * (t / 2)
  474.         local v2 = v1 + a1 * (t / 2)
  475.         local a2 = acceleration(p2, v2)
  476.         local p3 = p1 + v2 * (t / 2)
  477.         local v3 = v1 + a2 * (t / 2)
  478.         local a3 = acceleration(p3, v3)
  479.         local p4 = p1 + v3 * t
  480.         local v4 = v1 + a3 * t
  481.         local a4 = acceleration(p4, v4)
  482.  
  483.         local positionResult = position + (v1 + 2 * v2 + 2 * v3 + v4) * (t / 6)
  484.         local velocityResult = velocity + (a1 + 2 * a2 + 2 * a3 + a4) * (t / 6)
  485.         return positionResult, velocityResult
  486.     end
  487.  
  488.     function this:ZoomCameraBy(zoomScale)
  489.         local zoom = this:GetCameraActualZoom()
  490.        
  491.         if zoom then
  492.             -- Can break into more steps to get more accurate integration
  493.             zoom = self:rk4Integrator(zoom, zoomScale, 1)
  494.             self:ZoomCamera(zoom)
  495.         end
  496.         return self:GetCameraZoom()
  497.     end
  498.  
  499.     function this:ZoomCameraFixedBy(zoomIncrement)
  500.         return self:ZoomCamera(self:GetCameraZoom() + zoomIncrement)
  501.     end
  502.  
  503.     function this:Update()
  504.     end
  505.  
  506.     ----- VR STUFF ------
  507.  
  508.     function this:ApplyVRTransform()
  509.         if not VRService.VREnabled then
  510.             return
  511.         end
  512.         --we only want this to happen in first person VR
  513.         local player = PlayersService.LocalPlayer
  514.         if not (player and player.Character
  515.                 and player.Character:FindFirstChild("HumanoidRootPart")
  516.                 and player.Character.HumanoidRootPart:FindFirstChild("RootJoint")) then
  517.             return
  518.         end
  519.  
  520.         local camera = workspace.CurrentCamera
  521.         local cameraSubject = camera.CameraSubject
  522.         local isInVehicle = cameraSubject and cameraSubject:IsA('VehicleSeat')
  523.  
  524.         if this:IsInFirstPerson() and not isInVehicle then
  525.             local vrFrame = VRService:GetUserCFrame(Enum.UserCFrame.Head)
  526.             local vrRotation = vrFrame - vrFrame.p
  527.             local rootJoint = player.Character.HumanoidRootPart.RootJoint
  528.             rootJoint.C0 = CFrame.new(vrRotation:vectorToObjectSpace(vrFrame.p)) * CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
  529.         else
  530.             local rootJoint = player.Character.HumanoidRootPart.RootJoint
  531.             rootJoint.C0 = CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
  532.         end
  533.     end
  534.  
  535.     local vrRotationIntensityExists = true
  536.     local lastVrRotationCheck = 0
  537.     function this:ShouldUseVRRotation()
  538.         if not VRService.VREnabled then
  539.             return false
  540.         end
  541.         if not vrRotationIntensityExists and tick() - lastVrRotationCheck < 1 then return false end
  542.  
  543.         local success, vrRotationIntensity = pcall(function() return StarterGui:GetCore("VRRotationIntensity") end)
  544.         vrRotationIntensityExists = success and vrRotationIntensity ~= nil
  545.         lastVrRotationCheck = tick()
  546.  
  547.         return success and vrRotationIntensity ~= nil and vrRotationIntensity ~= "Smooth"
  548.     end
  549.  
  550.     function this:GetVRRotationInput()
  551.         local vrRotateSum = ZERO_VECTOR2
  552.  
  553.         local vrRotationIntensity = StarterGui:GetCore("VRRotationIntensity")
  554.  
  555.         local vrGamepadRotation = self.GamepadPanningCamera or ZERO_VECTOR2
  556.         local delayExpired = (tick() - lastVRRotation) >= self:GetRepeatDelayValue(vrRotationIntensity)
  557.  
  558.         if math.abs(vrGamepadRotation.x) >= self:GetActivateValue() then
  559.             if (delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]) then
  560.                 local sign = 1
  561.                 if vrGamepadRotation.x < 0 then
  562.                     sign = -1
  563.                 end
  564.                 vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity) * sign
  565.                 vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = true
  566.             end
  567.         elseif math.abs(vrGamepadRotation.x) < self:GetActivateValue() - 0.1 then
  568.             vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = nil
  569.         end
  570.         if self.TurningLeft then
  571.             if delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Left] then
  572.                 vrRotateSum = vrRotateSum - self:GetRotateAmountValue(vrRotationIntensity)
  573.                 vrRotateKeyCooldown[Enum.KeyCode.Left] = true
  574.             end
  575.         else
  576.             vrRotateKeyCooldown[Enum.KeyCode.Left] = nil
  577.         end
  578.         if self.TurningRight then
  579.             if (delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Right]) then
  580.                 vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity)
  581.                 vrRotateKeyCooldown[Enum.KeyCode.Right] = true
  582.             end
  583.         else
  584.             vrRotateKeyCooldown[Enum.KeyCode.Right] = nil
  585.         end
  586.  
  587.         if vrRotateSum ~= ZERO_VECTOR2 then
  588.             lastVRRotation = tick()
  589.         end
  590.  
  591.         return vrRotateSum
  592.     end
  593.  
  594.     local cameraTranslationConstraints = Vector3.new(1, 1, 1)
  595.     local humanoidJumpOrigin = nil
  596.     local trackingHumanoid = nil
  597.     local cameraFrozen = false
  598.     local subjectStateChangedConn = nil
  599.     local cameraSubjectChangedConn = nil
  600.     local workspaceChangedConn = nil
  601.     local humanoidChildAddedConn = nil
  602.     local humanoidChildRemovedConn = nil
  603.  
  604.     local function cancelCameraFreeze(keepConstraints)
  605.         if not keepConstraints then
  606.             cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, 1, cameraTranslationConstraints.z)
  607.         end
  608.         if cameraFrozen then
  609.             trackingHumanoid = nil
  610.             cameraFrozen = false
  611.         end
  612.     end
  613.  
  614.     local function startCameraFreeze(subjectPosition, humanoidToTrack)
  615.         if not cameraFrozen then
  616.             humanoidJumpOrigin = subjectPosition
  617.             trackingHumanoid = humanoidToTrack
  618.             cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, 0, cameraTranslationConstraints.z)
  619.             cameraFrozen = true
  620.         end
  621.     end
  622.  
  623.     local function rescaleCameraOffset(newScaleFactor)
  624.         R15HeadHeight = R15_HEAD_OFFSET*newScaleFactor
  625.     end
  626.  
  627.     local function onHumanoidSubjectChildAdded(child)
  628.         if child.Name == "BodyHeightScale" and child:IsA("NumberValue") then
  629.             if heightScaleChangedConn then
  630.                 heightScaleChangedConn:disconnect()
  631.             end
  632.             heightScaleChangedConn = child.Changed:connect(rescaleCameraOffset)
  633.             rescaleCameraOffset(child.Value)
  634.         end
  635.     end
  636.  
  637.     local function onHumanoidSubjectChildRemoved(child)
  638.         if child.Name == "BodyHeightScale" then
  639.             rescaleCameraOffset(1)
  640.             if heightScaleChangedConn then
  641.                 heightScaleChangedConn:disconnect()
  642.                 heightScaleChangedConn = nil
  643.             end
  644.         end
  645.     end
  646.  
  647.     local function onNewCameraSubject()
  648.         if subjectStateChangedConn then
  649.             subjectStateChangedConn:disconnect()
  650.             subjectStateChangedConn = nil
  651.         end
  652.         if humanoidChildAddedConn then
  653.             humanoidChildAddedConn:disconnect()
  654.             humanoidChildAddedConn = nil
  655.         end
  656.         if humanoidChildRemovedConn then
  657.             humanoidChildRemovedConn:disconnect()
  658.             humanoidChildRemovedConn = nil
  659.         end
  660.         if heightScaleChangedConn then
  661.             heightScaleChangedConn:disconnect()
  662.             heightScaleChangedConn = nil
  663.         end
  664.  
  665.         local humanoid = workspace.CurrentCamera and workspace.CurrentCamera.CameraSubject
  666.         if trackingHumanoid ~= humanoid then
  667.             cancelCameraFreeze()
  668.         end
  669.         if humanoid and humanoid:IsA('Humanoid') then
  670.             humanoidChildAddedConn = humanoid.ChildAdded:connect(onHumanoidSubjectChildAdded)
  671.             humanoidChildRemovedConn = humanoid.ChildRemoved:connect(onHumanoidSubjectChildRemoved)
  672.             for _, child in pairs(humanoid:GetChildren()) do
  673.                 onHumanoidSubjectChildAdded(child)
  674.             end
  675.  
  676.             subjectStateChangedConn = humanoid.StateChanged:connect(function(oldState, newState)
  677.                 if VRService.VREnabled and newState == Enum.HumanoidStateType.Jumping and not this:IsInFirstPerson() then
  678.                     startCameraFreeze(this:GetSubjectPosition(), humanoid)
  679.                 elseif newState ~= Enum.HumanoidStateType.Jumping and newState ~= Enum.HumanoidStateType.Freefall then
  680.                     cancelCameraFreeze(true)
  681.                 end
  682.             end)
  683.         end
  684.     end
  685.  
  686.     local function onCurrentCameraChanged()
  687.         if cameraSubjectChangedConn then
  688.             cameraSubjectChangedConn:disconnect()
  689.             cameraSubjectChangedConn = nil
  690.         end
  691.         local camera = workspace.CurrentCamera
  692.         if camera then
  693.             cameraSubjectChangedConn = camera:GetPropertyChangedSignal("CameraSubject"):connect(onNewCameraSubject)
  694.             onNewCameraSubject()
  695.         end
  696.     end
  697.  
  698.     function this:GetVRFocus(subjectPosition, timeDelta)
  699.         local newFocus = nil
  700.  
  701.         local camera = workspace.CurrentCamera
  702.         local lastFocus = self.LastCameraFocus or subjectPosition
  703.         if not cameraFrozen then
  704.             cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, math.min(1, cameraTranslationConstraints.y + 0.42 * timeDelta), cameraTranslationConstraints.z)
  705.         end
  706.         if cameraFrozen and humanoidJumpOrigin and humanoidJumpOrigin.y > lastFocus.y then
  707.             newFocus = CFrame.new(Vector3.new(subjectPosition.x, math.min(humanoidJumpOrigin.y, lastFocus.y + 5 * timeDelta), subjectPosition.z))
  708.         else
  709.             newFocus = CFrame.new(Vector3.new(subjectPosition.x, lastFocus.y, subjectPosition.z):lerp(subjectPosition, cameraTranslationConstraints.y))
  710.         end
  711.  
  712.         if cameraFrozen then
  713.             -- No longer in 3rd person
  714.             if self:IsInFirstPerson() then -- not VRService.VREnabled
  715.                 cancelCameraFreeze()
  716.             end
  717.             -- This case you jumped off a cliff and want to keep your character in view
  718.             -- 0.5 is to fix floating point error when not jumping off cliffs
  719.             if humanoidJumpOrigin and subjectPosition.y < (humanoidJumpOrigin.y - 0.5) then
  720.                 cancelCameraFreeze()
  721.             end
  722.         end
  723.  
  724.         return newFocus
  725.     end
  726.  
  727.     ------------------------
  728.  
  729.     ---- Input Events ----
  730.     local startPos = nil
  731.     local lastPos = nil
  732.     local panBeginLook = nil
  733.     local lastTapTime = nil
  734.  
  735.     local fingerTouches = {}
  736.     local NumUnsunkTouches = 0
  737.    
  738.     local inputStartPositions = {}
  739.     local inputStartTimes = {}
  740.  
  741.     local StartingDiff = nil
  742.     local pinchBeginZoom = nil
  743.  
  744.     this.ZoomEnabled = true
  745.     this.PanEnabled = true
  746.     this.KeyPanEnabled = true
  747.  
  748.     local function OnTouchBegan(input, processed)
  749.         --If isDynamicThumbstickEnabled, then only process TouchBegan event if it starts in GestureArea
  750.         if (not touchWorkspaceEventEnabled and not isDynamicThumbstickEnabled) or positionIntersectsGuiObject(input.Position, GestureArea) then
  751.             fingerTouches[input] = processed
  752.             if not processed then
  753.                 inputStartPositions[input] = input.Position
  754.                 inputStartTimes[input] = tick()
  755.                 NumUnsunkTouches = NumUnsunkTouches + 1
  756.             end
  757.         end
  758.     end
  759.  
  760.     local function OnTouchChanged(input, processed)
  761.        
  762.         if fingerTouches[input] == nil then
  763.             if isDynamicThumbstickEnabled then
  764.                 return
  765.             end
  766.             fingerTouches[input] = processed
  767.             if not processed then
  768.                 NumUnsunkTouches = NumUnsunkTouches + 1
  769.             end
  770.         end
  771.  
  772.         if NumUnsunkTouches == 1 then
  773.             if fingerTouches[input] == false then
  774.                 panBeginLook = panBeginLook or this:GetCameraLook()
  775.                 startPos = startPos or input.Position
  776.                 lastPos = lastPos or startPos
  777.                 this.UserPanningTheCamera = true
  778.  
  779.                 local delta = input.Position - lastPos     
  780.                
  781.                 delta = Vector2.new(delta.X, delta.Y * GameSettings:GetCameraYInvertValue())
  782.                
  783.                 if this.PanEnabled then
  784.                     local desiredXYVector = this:ScreenTranslationToAngle(delta) * TOUCH_SENSITIVTY
  785.                     this.RotateInput = this.RotateInput + desiredXYVector
  786.                 end
  787.  
  788.                 lastPos = input.Position
  789.             end
  790.         else
  791.             panBeginLook = nil
  792.             startPos = nil
  793.             lastPos = nil
  794.             this.UserPanningTheCamera = false
  795.         end
  796.         if NumUnsunkTouches == 2 then
  797.             local unsunkTouches = {}
  798.             for touch, wasSunk in pairs(fingerTouches) do
  799.                 if not wasSunk then
  800.                     table.insert(unsunkTouches, touch)
  801.                 end
  802.             end
  803.             if #unsunkTouches == 2 then
  804.                 local difference = (unsunkTouches[1].Position - unsunkTouches[2].Position).magnitude
  805.                 if StartingDiff and pinchBeginZoom then
  806.                     local scale = difference / math_max(0.01, StartingDiff)
  807.                     local clampedScale = clamp(0.1, 10, scale)
  808.                     if this.ZoomEnabled then
  809.                         this:ZoomCamera(pinchBeginZoom / clampedScale)
  810.                     end
  811.                 else
  812.                     StartingDiff = difference
  813.                     pinchBeginZoom = this:GetCameraActualZoom()
  814.                 end
  815.             end
  816.         else
  817.             StartingDiff = nil
  818.             pinchBeginZoom = nil
  819.         end
  820.     end
  821.    
  822.     local function calcLookBehindRotateInput(torso)
  823.         if torso then
  824.             local newDesiredLook = (torso.CFrame.lookVector - Vector3.new(0,0.23,0)).unit
  825.             local horizontalShift = findAngleBetweenXZVectors(newDesiredLook, this:GetCameraLook())
  826.             local vertShift = math.asin(this:GetCameraLook().y) - math.asin(newDesiredLook.y)
  827.             if not IsFinite(horizontalShift) then
  828.                 horizontalShift = 0
  829.             end
  830.             if not IsFinite(vertShift) then
  831.                 vertShift = 0
  832.             end
  833.            
  834.             return Vector2.new(horizontalShift, vertShift)
  835.         end
  836.         return nil
  837.     end
  838.  
  839.     local OnTouchTap = nil
  840.     if not touchWorkspaceEventEnabled then
  841.         OnTouchTap = function(position)
  842.             if isDynamicThumbstickEnabled and not IsAToolEquipped then
  843.                 if lastTapTime and tick() - lastTapTime < MAX_TIME_FOR_DOUBLE_TAP then
  844.                     local tween = {
  845.                         from = this:GetCameraZoom(),
  846.                         to = DefaultZoom,
  847.                         start = tick(),
  848.                         duration = 0.2,
  849.                         func = function(from, to, alpha)
  850.                             this:ZoomCamera(from + (to - from)*alpha)
  851.                             return to
  852.                         end
  853.                     }
  854.                     tweens["Zoom"] = tween
  855.                 else
  856.                     local humanoid = this:GetHumanoid()
  857.                     if humanoid then
  858.                         local player = PlayersService.LocalPlayer
  859.                         if player and player.Character then
  860.                             if humanoid and humanoid.Torso then
  861.                                 local tween = {
  862.                                     from = this.RotateInput,
  863.                                     to = calcLookBehindRotateInput(humanoid.Torso),
  864.                                     start = tick(),
  865.                                     duration = 0.2,
  866.                                     func = function(from, to, alpha)
  867.                                         to = calcLookBehindRotateInput(humanoid.Torso)
  868.                                         if to then
  869.                                             this.RotateInput = from + (to - from)*alpha
  870.                                         end
  871.                                         return to
  872.                                     end
  873.                                 }
  874.                                 tweens["Rotate"] = tween
  875.                                
  876.                                 -- reset old camera info so follow cam doesn't rotate us
  877.                                 this.LastCameraTransform = nil
  878.                             end
  879.                         end
  880.                     end
  881.                 end
  882.                 lastTapTime = tick()
  883.             end
  884.         end
  885.     end
  886.    
  887.     local function IsTouchTap(input)
  888.         -- We can't make the assumption that the input exists in the inputStartPositions because we may have switched from a different camera type.
  889.         if inputStartPositions[input] then
  890.             local posDelta = (inputStartPositions[input] - input.Position).magnitude
  891.             if posDelta < MAX_TAP_POS_DELTA then
  892.                 local timeDelta = inputStartTimes[input] - tick()
  893.                 if timeDelta < MAX_TAP_TIME_DELTA then
  894.                     return true
  895.                 end
  896.             end
  897.         end
  898.         return false
  899.     end
  900.    
  901.    
  902.     local function OnTouchEnded(input, processed)
  903.         if fingerTouches[input] == false then
  904.             if NumUnsunkTouches == 1 then
  905.                 panBeginLook = nil
  906.                 startPos = nil
  907.                 lastPos = nil
  908.                 this.UserPanningTheCamera = false
  909.                 if not touchWorkspaceEventEnabled and IsTouchTap(input) then
  910.                     OnTouchTap(input.Position)
  911.                 end
  912.             elseif NumUnsunkTouches == 2 then
  913.                 StartingDiff = nil
  914.                 pinchBeginZoom = nil
  915.             end
  916.         end
  917.  
  918.         if fingerTouches[input] ~= nil and fingerTouches[input] == false then
  919.             NumUnsunkTouches = NumUnsunkTouches - 1
  920.         end
  921.         fingerTouches[input] = nil
  922.         inputStartPositions[input] = nil
  923.         inputStartTimes[input] = nil
  924.     end
  925.  
  926.     local function OnMousePanButtonPressed(input, processed)
  927.         if processed then return end
  928.         this:UpdateMouseBehavior()
  929.         panBeginLook = panBeginLook or this:GetCameraLook()
  930.         startPos = startPos or input.Position
  931.         lastPos = lastPos or startPos
  932.         this.UserPanningTheCamera = true
  933.     end
  934.  
  935.     local function OnMousePanButtonReleased(input, processed)
  936.         this:UpdateMouseBehavior()
  937.         if not (isRightMouseDown or isMiddleMouseDown) then
  938.             panBeginLook = nil
  939.             startPos = nil
  940.             lastPos = nil
  941.             this.UserPanningTheCamera = false
  942.         end
  943.     end
  944.  
  945.     local function OnMouse2Down(input, processed)
  946.         if processed then return end
  947.  
  948.         isRightMouseDown = true
  949.         OnMousePanButtonPressed(input, processed)
  950.     end
  951.  
  952.     local function OnMouse2Up(input, processed)
  953.         isRightMouseDown = false
  954.         OnMousePanButtonReleased(input, processed)
  955.     end
  956.  
  957.     local function OnMouse3Down(input, processed)
  958.         if processed then return end
  959.  
  960.         isMiddleMouseDown = true
  961.         OnMousePanButtonPressed(input, processed)
  962.     end
  963.  
  964.     local function OnMouse3Up(input, processed)
  965.         isMiddleMouseDown = false
  966.         OnMousePanButtonReleased(input, processed)
  967.     end
  968.  
  969.     local function OnMouseMoved(input, processed)
  970.         if (not hasGameLoaded and VRService.VREnabled) or script.Parent.LockCamera.Value then
  971.             return
  972.         end
  973.        
  974.         local inputDelta = input.Delta
  975.         inputDelta = Vector2.new(inputDelta.X, inputDelta.Y * GameSettings:GetCameraYInvertValue())
  976.        
  977.         if startPos and lastPos and panBeginLook then
  978.             local currPos = lastPos + input.Delta
  979.             local totalTrans = currPos - startPos
  980.             if this.PanEnabled then
  981.                 local desiredXYVector = this:MouseTranslationToAngle(inputDelta) * MOUSE_SENSITIVITY
  982.                 this.RotateInput = this.RotateInput + desiredXYVector
  983.             end
  984.             lastPos = currPos
  985.         elseif this:IsInFirstPerson() or this:GetShiftLock() then
  986.             if this.PanEnabled then
  987.                 local desiredXYVector = this:MouseTranslationToAngle(inputDelta) * MOUSE_SENSITIVITY
  988.                 this.RotateInput = this.RotateInput + desiredXYVector
  989.             end
  990.         end
  991.     end
  992.  
  993.     local function OnMouseWheel(input, processed)
  994.         if not hasGameLoaded and VRService.VREnabled then
  995.             return
  996.         end
  997.         if not processed then
  998.             if this.ZoomEnabled then
  999.                 this:ZoomCameraBy(clamp(-1, 1, -input.Position.Z) * 1.4)
  1000.             end
  1001.         end
  1002.     end
  1003.  
  1004.     local function round(num)
  1005.         return math_floor(num + 0.5)
  1006.     end
  1007.  
  1008.     local eight2Pi = math_pi / 4
  1009.  
  1010.     local function rotateVectorByAngleAndRound(camLook, rotateAngle, roundAmount)
  1011.         if camLook ~= ZERO_VECTOR3 then
  1012.             camLook = camLook.unit
  1013.             local currAngle = math_atan2(camLook.z, camLook.x)
  1014.             local newAngle = round((math_atan2(camLook.z, camLook.x) + rotateAngle) / roundAmount) * roundAmount
  1015.             return newAngle - currAngle
  1016.         end
  1017.         return 0
  1018.     end
  1019.  
  1020.     local function OnKeyDown(input, processed)
  1021.         if not hasGameLoaded and VRService.VREnabled then
  1022.             return
  1023.         end
  1024.         if processed then return end
  1025.         if this.ZoomEnabled then
  1026.             if input.KeyCode == Enum.KeyCode.I then
  1027.                 this:ZoomCameraBy(-5)
  1028.             elseif input.KeyCode == Enum.KeyCode.O then
  1029.                 this:ZoomCameraBy(5)
  1030.             end
  1031.         end
  1032.         if panBeginLook == nil and this.KeyPanEnabled then
  1033.             if input.KeyCode == Enum.KeyCode.Left then
  1034.                 this.TurningLeft = true
  1035.             elseif input.KeyCode == Enum.KeyCode.Right then
  1036.                 this.TurningRight = true
  1037.             elseif input.KeyCode == Enum.KeyCode.Comma then
  1038.                 local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1,0,1), -eight2Pi * (3/4), eight2Pi)
  1039.                 if angle ~= 0 then
  1040.                     this.RotateInput = this.RotateInput + Vector2.new(angle, 0)
  1041.                     this.LastUserPanCamera = tick()
  1042.                     this.LastCameraTransform = nil
  1043.                 end
  1044.             elseif input.KeyCode == Enum.KeyCode.Period then
  1045.                 local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1,0,1), eight2Pi * (3/4), eight2Pi)
  1046.                 if angle ~= 0 then
  1047.                     this.RotateInput = this.RotateInput + Vector2.new(angle, 0)
  1048.                     this.LastUserPanCamera = tick()
  1049.                     this.LastCameraTransform = nil
  1050.                 end
  1051.             elseif input.KeyCode == Enum.KeyCode.PageUp then
  1052.             --elseif input.KeyCode == Enum.KeyCode.Home then
  1053.                 this.RotateInput = this.RotateInput + Vector2.new(0,math.rad(15))
  1054.                 this.LastCameraTransform = nil
  1055.             elseif input.KeyCode == Enum.KeyCode.PageDown then
  1056.             --elseif input.KeyCode == Enum.KeyCode.End then
  1057.                 this.RotateInput = this.RotateInput + Vector2.new(0,math.rad(-15))
  1058.                 this.LastCameraTransform = nil
  1059.             end
  1060.         end
  1061.     end
  1062.  
  1063.     local function OnKeyUp(input, processed)
  1064.         if input.KeyCode == Enum.KeyCode.Left then
  1065.             this.TurningLeft = false
  1066.         elseif input.KeyCode == Enum.KeyCode.Right then
  1067.             this.TurningRight = false
  1068.         end
  1069.     end
  1070.  
  1071.     local lastThumbstickRotate = nil
  1072.     local numOfSeconds = 0.7
  1073.     local currentSpeed = 0
  1074.     local maxSpeed = 6
  1075.     local vrMaxSpeed = 4
  1076.     local lastThumbstickPos = Vector2.new(0,0)
  1077.     local ySensitivity = 0.65
  1078.     local lastVelocity = nil
  1079.  
  1080.     -- K is a tunable parameter that changes the shape of the S-curve
  1081.     -- the larger K is the more straight/linear the curve gets
  1082.     local k = 0.35
  1083.     local lowerK = 0.8
  1084.     local function SCurveTranform(t)
  1085.         t = clamp(-1,1,t)
  1086.         if t >= 0 then
  1087.             return (k*t) / (k - t + 1)
  1088.         end
  1089.         return -((lowerK*-t) / (lowerK + t + 1))
  1090.     end
  1091.  
  1092.     -- DEADZONE
  1093.     local DEADZONE = 0.1
  1094.     local function toSCurveSpace(t)
  1095.         return (1 + DEADZONE) * (2*math.abs(t) - 1) - DEADZONE
  1096.     end
  1097.  
  1098.     local function fromSCurveSpace(t)
  1099.         return t/2 + 0.5
  1100.     end
  1101.  
  1102.     local function gamepadLinearToCurve(thumbstickPosition)
  1103.         local function onAxis(axisValue)
  1104.             local sign = 1
  1105.             if axisValue < 0 then
  1106.                 sign = -1
  1107.             end
  1108.             local point = fromSCurveSpace(SCurveTranform(toSCurveSpace(math.abs(axisValue))))
  1109.             point = point * sign
  1110.             return clamp(-1, 1, point)
  1111.         end
  1112.         return Vector2_new(onAxis(thumbstickPosition.x), onAxis(thumbstickPosition.y))
  1113.     end
  1114.  
  1115.     function this:UpdateGamepad()
  1116.         local gamepadPan = this.GamepadPanningCamera
  1117.         if gamepadPan and (hasGameLoaded or not VRService.VREnabled) then
  1118.             gamepadPan = gamepadLinearToCurve(gamepadPan)
  1119.             local currentTime = tick()
  1120.             if gamepadPan.X ~= 0 or gamepadPan.Y ~= 0 then
  1121.                 this.userPanningTheCamera = true
  1122.             elseif gamepadPan == ZERO_VECTOR2 then
  1123.                 lastThumbstickRotate = nil
  1124.                 if lastThumbstickPos == ZERO_VECTOR2 then
  1125.                     currentSpeed = 0
  1126.                 end
  1127.             end
  1128.  
  1129.             local finalConstant = 0
  1130.  
  1131.             if lastThumbstickRotate then
  1132.                 if VRService.VREnabled then
  1133.                     currentSpeed = vrMaxSpeed
  1134.                 else
  1135.                     local elapsedTime = (currentTime - lastThumbstickRotate) * 10
  1136.                     currentSpeed = currentSpeed + (maxSpeed * ((elapsedTime*elapsedTime)/numOfSeconds))
  1137.  
  1138.                     if currentSpeed > maxSpeed then currentSpeed = maxSpeed end
  1139.  
  1140.                     if lastVelocity then
  1141.                         local velocity = (gamepadPan - lastThumbstickPos)/(currentTime - lastThumbstickRotate)
  1142.                         local velocityDeltaMag = (velocity - lastVelocity).magnitude
  1143.  
  1144.                         if velocityDeltaMag > 12 then
  1145.                             currentSpeed = currentSpeed * (20/velocityDeltaMag)
  1146.                             if currentSpeed > maxSpeed then currentSpeed = maxSpeed end
  1147.                         end
  1148.                     end
  1149.                 end
  1150.  
  1151.                 local success, gamepadCameraSensitivity = pcall(function() return GameSettings.GamepadCameraSensitivity end)
  1152.                 finalConstant = success and (gamepadCameraSensitivity * currentSpeed) or currentSpeed
  1153.                 lastVelocity = (gamepadPan - lastThumbstickPos)/(currentTime - lastThumbstickRotate)
  1154.             end
  1155.  
  1156.             lastThumbstickPos = gamepadPan
  1157.             lastThumbstickRotate = currentTime
  1158.  
  1159.             return Vector2_new( gamepadPan.X * finalConstant, gamepadPan.Y * finalConstant * ySensitivity * GameSettings:GetCameraYInvertValue())
  1160.         end
  1161.  
  1162.         return ZERO_VECTOR2
  1163.     end
  1164.  
  1165.     local InputBeganConn, InputChangedConn, InputEndedConn, MenuOpenedConn, ShiftLockToggleConn, GamepadConnectedConn, GamepadDisconnectedConn, TouchActivateConn = nil, nil, nil, nil, nil, nil, nil, nil
  1166.  
  1167.     function this:DisconnectInputEvents()
  1168.         if InputBeganConn then
  1169.             InputBeganConn:disconnect()
  1170.             InputBeganConn = nil
  1171.         end
  1172.         if InputChangedConn then
  1173.             InputChangedConn:disconnect()
  1174.             InputChangedConn = nil
  1175.         end
  1176.         if InputEndedConn then
  1177.             InputEndedConn:disconnect()
  1178.             InputEndedConn = nil
  1179.         end
  1180.         if MenuOpenedConn then
  1181.             MenuOpenedConn:disconnect()
  1182.             MenuOpenedConn = nil
  1183.         end
  1184.         if ShiftLockToggleConn then
  1185.             ShiftLockToggleConn:disconnect()
  1186.             ShiftLockToggleConn = nil
  1187.         end
  1188.         if GamepadConnectedConn then
  1189.             GamepadConnectedConn:disconnect()
  1190.             GamepadConnectedConn = nil
  1191.         end
  1192.         if GamepadDisconnectedConn then
  1193.             GamepadDisconnectedConn:disconnect()
  1194.             GamepadDisconnectedConn = nil
  1195.         end
  1196.         if subjectStateChangedConn then
  1197.             subjectStateChangedConn:disconnect()
  1198.             subjectStateChangedConn = nil
  1199.         end
  1200.         if workspaceChangedConn then
  1201.             workspaceChangedConn:disconnect()
  1202.             workspaceChangedConn = nil
  1203.         end
  1204.         if TouchActivateConn then
  1205.             TouchActivateConn:disconnect()
  1206.             TouchActivateConn = nil
  1207.         end
  1208.  
  1209.         this.TurningLeft = false
  1210.         this.TurningRight = false
  1211.         this.LastCameraTransform = nil
  1212.         self.LastSubjectCFrame = nil
  1213.         this.UserPanningTheCamera = false
  1214.         this.RotateInput = Vector2.new()
  1215.         this.GamepadPanningCamera = Vector2.new(0,0)
  1216.  
  1217.         -- Reset input states
  1218.         startPos = nil
  1219.         lastPos = nil
  1220.         panBeginLook = nil
  1221.         isRightMouseDown = false
  1222.         isMiddleMouseDown = false
  1223.  
  1224.         fingerTouches = {}
  1225.         NumUnsunkTouches = 0
  1226.  
  1227.         StartingDiff = nil
  1228.         pinchBeginZoom = nil
  1229.  
  1230.         -- Unlock mouse for example if right mouse button was being held down
  1231.         if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
  1232.             UserInputService.MouseBehavior = Enum.MouseBehavior.Default
  1233.         end
  1234.     end
  1235.  
  1236.     function this:ResetInputStates()
  1237.         isRightMouseDown = false
  1238.         isMiddleMouseDown = false
  1239.         OnMousePanButtonReleased() -- this function doesn't seem to actually need parameters
  1240.  
  1241.         if UserInputService.TouchEnabled then
  1242.             --[[menu opening was causing serious touch issues
  1243.             this should disable all active touch events if
  1244.             they're active when menu opens.]]
  1245.             for inputObject, value in pairs(fingerTouches) do
  1246.                 fingerTouches[inputObject] = nil
  1247.             end
  1248.             panBeginLook = nil
  1249.             startPos = nil
  1250.             lastPos = nil
  1251.             this.UserPanningTheCamera = false
  1252.             StartingDiff = nil
  1253.             pinchBeginZoom = nil
  1254.             NumUnsunkTouches = 0
  1255.         end
  1256.     end
  1257.  
  1258.     function this.getGamepadPan(name, state, input)
  1259.         if input.UserInputType == this.activeGamepad and input.KeyCode == Enum.KeyCode.Thumbstick2 then
  1260.            
  1261.             if state == Enum.UserInputState.Cancel then
  1262.                 this.GamepadPanningCamera = ZERO_VECTOR2
  1263.                 return
  1264.             end    
  1265.            
  1266.             local inputVector = Vector2.new(input.Position.X, -input.Position.Y)
  1267.             if inputVector.magnitude > THUMBSTICK_DEADZONE then
  1268.                 this.GamepadPanningCamera = Vector2_new(input.Position.X, -input.Position.Y)
  1269.             else
  1270.                 this.GamepadPanningCamera = ZERO_VECTOR2
  1271.             end
  1272.         end
  1273.     end
  1274.  
  1275.     function this.doGamepadZoom(name, state, input)
  1276.         if input.UserInputType == this.activeGamepad and input.KeyCode == Enum.KeyCode.ButtonR3 and state == Enum.UserInputState.Begin then
  1277.             if this.ZoomEnabled then
  1278.                 if this:GetCameraZoom() > 0.5 then
  1279.                     this:ZoomCamera(0)
  1280.                 else
  1281.                     this:ZoomCamera(10)
  1282.                 end
  1283.             end
  1284.         end
  1285.     end
  1286.    
  1287.     function this:BindGamepadInputActions()
  1288.         ContextActionService:BindAction("RootCamGamepadPan", this.getGamepadPan, false, Enum.KeyCode.Thumbstick2)
  1289.         ContextActionService:BindAction("RootCamGamepadZoom", this.doGamepadZoom, false, Enum.KeyCode.ButtonR3)
  1290.     end
  1291.  
  1292.     function this:ConnectInputEvents() 
  1293.         InputBeganConn = UserInputService.InputBegan:connect(function(input, processed)
  1294.             if input.UserInputType == Enum.UserInputType.Touch then
  1295.                 OnTouchBegan(input, processed)
  1296.             elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
  1297.                 OnMouse2Down(input, processed)
  1298.             elseif input.UserInputType == Enum.UserInputType.MouseButton3 then
  1299.                 OnMouse3Down(input, processed)
  1300.             end
  1301.             -- Keyboard
  1302.             if input.UserInputType == Enum.UserInputType.Keyboard then
  1303.                 OnKeyDown(input, processed)
  1304.             end
  1305.         end)
  1306.  
  1307.         InputChangedConn = UserInputService.InputChanged:connect(function(input, processed)
  1308.             if input.UserInputType == Enum.UserInputType.Touch then
  1309.                 OnTouchChanged(input, processed)
  1310.             elseif input.UserInputType == Enum.UserInputType.MouseMovement then
  1311.                 OnMouseMoved(input, processed)
  1312.             elseif input.UserInputType == Enum.UserInputType.MouseWheel then
  1313.                 OnMouseWheel(input, processed)
  1314.             end
  1315.         end)
  1316.  
  1317.         InputEndedConn = UserInputService.InputEnded:connect(function(input, processed)
  1318.             if input.UserInputType == Enum.UserInputType.Touch then
  1319.                 OnTouchEnded(input, processed)
  1320.             elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
  1321.                 OnMouse2Up(input, processed)
  1322.             elseif input.UserInputType == Enum.UserInputType.MouseButton3 then
  1323.                 OnMouse3Up(input, processed)
  1324.             end
  1325.             -- Keyboard
  1326.             if input.UserInputType == Enum.UserInputType.Keyboard then
  1327.                 OnKeyUp(input, processed)
  1328.             end
  1329.         end)
  1330.  
  1331.         if touchWorkspaceEventEnabled then
  1332.             TouchActivateConn = UserInputService.TouchTapInWorld:connect(function(touchPos, processed)
  1333.                 if isDynamicThumbstickEnabled and not processed and not IsAToolEquipped and positionIntersectsGuiObject(touchPos, GestureArea) then
  1334.                     if lastTapTime and tick() - lastTapTime < MAX_TIME_FOR_DOUBLE_TAP then
  1335.                         local tween = {
  1336.                             from = this:GetCameraZoom(),
  1337.                             to = DefaultZoom,
  1338.                             start = tick(),
  1339.                             duration = 0.2,
  1340.                             func = function(from, to, alpha)
  1341.                                 this:ZoomCamera(from + (to - from)*alpha)
  1342.                                 return to
  1343.                             end
  1344.                         }
  1345.                         tweens["Zoom"] = tween
  1346.                     else
  1347.                         local humanoid = this:GetHumanoid()
  1348.                         if humanoid then
  1349.                             local player = PlayersService.LocalPlayer
  1350.                             if player and player.Character then
  1351.                                 if humanoid and humanoid.Torso then
  1352.                                     local tween = {
  1353.                                         from = this.RotateInput,
  1354.                                         to = calcLookBehindRotateInput(humanoid.Torso),
  1355.                                         start = tick(),
  1356.                                         duration = 0.2,
  1357.                                         func = function(from, to, alpha)
  1358.                                             to = calcLookBehindRotateInput(humanoid.Torso)
  1359.                                             if to then
  1360.                                                 this.RotateInput = from + (to - from)*alpha
  1361.                                             end
  1362.                                             return to
  1363.                                         end
  1364.                                     }
  1365.                                     tweens["Rotate"] = tween
  1366.                                    
  1367.                                     -- reset old camera info so follow cam doesn't rotate us
  1368.                                     this.LastCameraTransform = nil
  1369.                                 end
  1370.                             end
  1371.                         end
  1372.                     end
  1373.                     lastTapTime = tick()
  1374.                 end
  1375.             end)
  1376.         end
  1377.  
  1378.         MenuOpenedConn = GuiService.MenuOpened:connect(function()
  1379.             this:ResetInputStates()
  1380.         end)
  1381.  
  1382.         workspaceChangedConn = workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(onCurrentCameraChanged)
  1383.         if workspace.CurrentCamera then
  1384.             onCurrentCameraChanged()
  1385.         end
  1386.  
  1387.         ShiftLockToggleConn = ShiftLockController.OnShiftLockToggled.Event:connect(function()
  1388.             this:UpdateMouseBehavior()
  1389.         end)
  1390.        
  1391.         ShiftLockController:Lock()
  1392.  
  1393.         this.RotateInput = Vector2.new()
  1394.  
  1395.         this.activeGamepad = nil
  1396.         local function assignActivateGamepad()
  1397.             local connectedGamepads = UserInputService:GetConnectedGamepads()
  1398.             if #connectedGamepads > 0 then
  1399.                 for i = 1, #connectedGamepads do
  1400.                     if this.activeGamepad == nil then
  1401.                         this.activeGamepad = connectedGamepads[i]
  1402.                     elseif connectedGamepads[i].Value < this.activeGamepad.Value then
  1403.                         this.activeGamepad = connectedGamepads[i]
  1404.                     end
  1405.                 end
  1406.             end
  1407.  
  1408.             if this.activeGamepad == nil then -- nothing is connected, at least set up for gamepad1
  1409.                 this.activeGamepad = Enum.UserInputType.Gamepad1
  1410.             end
  1411.         end
  1412.  
  1413.         GamepadConnectedConn = UserInputService.GamepadDisconnected:connect(function(gamepadEnum)
  1414.             if this.activeGamepad ~= gamepadEnum then return end
  1415.             this.activeGamepad = nil
  1416.             assignActivateGamepad()
  1417.         end)
  1418.  
  1419.         GamepadDisconnectedConn = UserInputService.GamepadConnected:connect(function(gamepadEnum)
  1420.             if this.activeGamepad == nil then
  1421.                 assignActivateGamepad()
  1422.             end
  1423.         end)
  1424.  
  1425.         self:BindGamepadInputActions()
  1426.        
  1427.         assignActivateGamepad()
  1428.  
  1429.         -- set mouse behavior
  1430.         self:UpdateMouseBehavior()
  1431.     end
  1432.    
  1433.     --Process tweens related to tap-to-recenter and double-tap-to-zoom
  1434.     --Needs to be called from specific cameras on each update
  1435.     function this:ProcessTweens()
  1436.         for name, tween in pairs(tweens) do
  1437.             local alpha = math.min(1.0, (tick() - tween.start)/tween.duration)
  1438.             tween.to = tween.func(tween.from, tween.to, alpha)
  1439.             if math.abs(1 - alpha) < 0.0001 then
  1440.                 tweens[name] = nil
  1441.             end
  1442.         end
  1443.     end
  1444.  
  1445.     function this:SetEnabled(newState)
  1446.         if newState ~= self.Enabled then
  1447.             self.Enabled = newState
  1448.             if self.Enabled then
  1449.                 self:ConnectInputEvents()
  1450.                 self.cframe = workspace.CurrentCamera.CFrame
  1451.             else
  1452.                 self:DisconnectInputEvents()
  1453.             end
  1454.         end
  1455.     end
  1456.  
  1457.     local function OnPlayerAdded(player)
  1458.         player.Changed:connect(function(prop)
  1459.             if this.Enabled then
  1460.                 if prop == "CameraMode" or prop == "CameraMaxZoomDistance" or prop == "CameraMinZoomDistance" then
  1461.                      this:ZoomCameraFixedBy(0)
  1462.                 end
  1463.             end
  1464.         end)
  1465.        
  1466.         local function OnCharacterAdded(newCharacter)
  1467.  
  1468.             local humanoid = findPlayerHumanoid(player)
  1469.             local start = tick()
  1470.             while tick() - start < 0.3 and (humanoid == nil or humanoid.Torso == nil) do
  1471.                 wait()
  1472.                 humanoid = findPlayerHumanoid(player)
  1473.             end
  1474.  
  1475.             if humanoid and humanoid.Torso and player.Character == newCharacter then
  1476.                 local newDesiredLook = (humanoid.Torso.CFrame.lookVector - Vector3.new(0,0.23,0)).unit
  1477.                 local horizontalShift = findAngleBetweenXZVectors(newDesiredLook, this:GetCameraLook())
  1478.                 local vertShift = math.asin(this:GetCameraLook().y) - math.asin(newDesiredLook.y)
  1479.                 if not IsFinite(horizontalShift) then
  1480.                     horizontalShift = 0
  1481.                 end
  1482.                 if not IsFinite(vertShift) then
  1483.                     vertShift = 0
  1484.                 end
  1485.                 this.RotateInput = Vector2.new(horizontalShift, vertShift)
  1486.                
  1487.                 -- reset old camera info so follow cam doesn't rotate us
  1488.                 this.LastCameraTransform = nil
  1489.             end
  1490.            
  1491.             -- Need to wait for camera cframe to update before we zoom in
  1492.             -- Not waiting will force camera to original cframe
  1493.             wait()
  1494.             this:ZoomCamera(this.DefaultZoom)
  1495.         end
  1496.  
  1497.         player.CharacterAdded:connect(function(character)
  1498.             if this.Enabled or SetCameraOnSpawn then
  1499.                 OnCharacterAdded(character)
  1500.                 SetCameraOnSpawn = false
  1501.             end
  1502.         end)
  1503.         if player.Character then
  1504.             spawn(function() OnCharacterAdded(player.Character) end)
  1505.         end
  1506.     end
  1507.     if PlayersService.LocalPlayer then
  1508.         OnPlayerAdded(PlayersService.LocalPlayer)
  1509.     end
  1510.     PlayersService.ChildAdded:connect(function(child)
  1511.         if child and PlayersService.LocalPlayer == child then
  1512.             OnPlayerAdded(PlayersService.LocalPlayer)
  1513.         end
  1514.     end)
  1515.  
  1516.     local function OnGameLoaded()
  1517.         hasGameLoaded = true
  1518.     end
  1519.  
  1520.     spawn(function()
  1521.         if game:IsLoaded() then
  1522.             OnGameLoaded()
  1523.         else
  1524.             game.Loaded:wait()
  1525.             OnGameLoaded()
  1526.         end
  1527.     end)
  1528.    
  1529.     local function OnDynamicThumbstickEnabled()
  1530.         if UserInputService.TouchEnabled then
  1531.             isDynamicThumbstickEnabled = true
  1532.         end
  1533.     end
  1534.    
  1535.     local function OnDynamicThumbstickDisabled()
  1536.         isDynamicThumbstickEnabled = false
  1537.     end
  1538.    
  1539.     local function OnGameSettingsTouchMovementModeChanged()
  1540.         if LocalPlayer.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice then
  1541.             if GameSettings.TouchMovementMode.Name == "DynamicThumbstick" then
  1542.                 OnDynamicThumbstickEnabled()
  1543.             else
  1544.                 OnDynamicThumbstickDisabled()
  1545.             end
  1546.         end
  1547.     end
  1548.    
  1549.     local function OnDevTouchMovementModeChanged()
  1550.         if LocalPlayer.DevTouchMovementMode.Name == "DynamicThumbstick" then
  1551.             OnDynamicThumbstickEnabled()
  1552.         else
  1553.             OnGameSettingsTouchMovementModeChanged()
  1554.         end
  1555.     end
  1556.    
  1557.     if PlayersService.LocalPlayer then
  1558.         PlayersService.LocalPlayer.Changed:Connect(function(prop)
  1559.             if prop == "DevTouchMovementMode" then
  1560.                 OnDevTouchMovementModeChanged()
  1561.             end
  1562.         end)
  1563.         OnDevTouchMovementModeChanged()
  1564.     end
  1565.    
  1566.     GameSettings.Changed:Connect(function(prop)
  1567.         if prop == "TouchMovementMode" then
  1568.             OnGameSettingsTouchMovementModeChanged()
  1569.         end
  1570.     end)
  1571.     OnGameSettingsTouchMovementModeChanged()
  1572.     GameSettings:SetCameraYInvertVisible()
  1573.     pcall(function() GameSettings:SetGamepadCameraSensitivityVisible() end)
  1574.    
  1575.     return this
  1576. end
  1577.  
  1578. return CreateCamera
Add Comment
Please, Sign In to add comment