Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local PlayersService = game:GetService("Players")
- local UserInputService = game:GetService("UserInputService")
- local StarterGui = game:GetService("StarterGui")
- local GuiService = game:GetService("GuiService")
- local ContextActionService = game:GetService("ContextActionService")
- local VRServiceExists, VRService = pcall(function()
- return game:GetService("VRService")
- end)
- if not VRServiceExists or not VRService then
- VRService = UserInputService
- end
- local CameraScript = script.Parent
- local ShiftLockController = require(CameraScript:WaitForChild("ShiftLockController"))
- local Settings = UserSettings()
- local GameSettings = Settings.GameSettings
- local spawnLocationFixFlagExists, spawnLocationFixFlagEnabled = pcall(function()
- return Settings:IsUserFeatureEnabled("UserSpawnLocationFixEnabled")
- end)
- local FFlagSpawnLocationFixEnabled = spawnLocationFixFlagExists and spawnLocationFixFlagEnabled
- local clamp = function(low, high, num)
- if low <= high then
- return math.min(high, math.max(low, num))
- end
- return num
- end
- local findAngleBetweenXZVectors = function(vec2, vec1)
- return math.atan2(vec1.X * vec2.Z - vec1.Z * vec2.X, vec1.X * vec2.X + vec1.Z * vec2.Z)
- end
- local IsFinite = function(num)
- return num == num and num ~= 1 / 0 and num ~= -1 / 0
- end
- local THUMBSTICK_DEADZONE = 0.2
- local humanoidCache = {}
- local function findPlayerHumanoid(player)
- local character = player and player.Character
- if character then
- local resultHumanoid = humanoidCache[player]
- if resultHumanoid and resultHumanoid.Parent == character then
- return resultHumanoid
- else
- humanoidCache[player] = nil
- for _, child in pairs(character:GetChildren()) do
- if child:IsA("Humanoid") then
- humanoidCache[player] = child
- return child
- end
- end
- end
- end
- end
- local MIN_Y = math.rad(-80)
- local MAX_Y = math.rad(80)
- local VR_ANGLE = math.rad(15)
- local VR_LOW_INTENSITY_ROTATION = Vector2.new(math.rad(15), 0)
- local VR_HIGH_INTENSITY_ROTATION = Vector2.new(math.rad(45), 0)
- local VR_LOW_INTENSITY_REPEAT = 0.1
- local VR_HIGH_INTENSITY_REPEAT = 0.4
- local ZERO_VECTOR2 = Vector2.new(0, 0)
- local TOUCH_SENSITIVTY = Vector2.new(math.pi * 2.25, math.pi * 2)
- local MOUSE_SENSITIVITY = Vector2.new(math.pi * 4, math.pi * 1.9)
- local SEAT_OFFSET = Vector3.new(0, 5, 0)
- local VR_SEAT_OFFSET = Vector3.new(0, 4, 0)
- local HEAD_OFFSET = Vector3.new(0, 1.5, 0)
- local R15_HEAD_OFFSET = Vector3.new(0, 2, 0)
- local SetCameraOnSpawn = true
- local hasGameLoaded = false
- local GetRenderCFrame = function(part)
- return part:GetRenderCFrame()
- end
- local function CreateCamera()
- local this = {}
- local R15HeadHeight = R15_HEAD_OFFSET
- function this:GetActivateValue()
- return 0.7
- end
- function this:GetRotateAmountValue(vrRotationIntensity)
- vrRotationIntensity = vrRotationIntensity or StarterGui:GetCore("VRRotationIntensity")
- if vrRotationIntensity then
- if vrRotationIntensity == "Low" then
- return VR_LOW_INTENSITY_ROTATION
- elseif vrRotationIntensity == "High" then
- return VR_HIGH_INTENSITY_ROTATION
- end
- end
- return ZERO_VECTOR2
- end
- function this:GetRepeatDelayValue(vrRotationIntensity)
- vrRotationIntensity = vrRotationIntensity or StarterGui:GetCore("VRRotationIntensity")
- if vrRotationIntensity then
- if vrRotationIntensity == "Low" then
- return VR_LOW_INTENSITY_REPEAT
- elseif vrRotationIntensity == "High" then
- return VR_HIGH_INTENSITY_REPEAT
- end
- end
- return 0
- end
- this.ShiftLock = false
- this.Enabled = false
- local isFirstPerson = false
- local isRightMouseDown = false
- local isMiddleMouseDown = false
- this.RotateInput = Vector2.new()
- this.lastSubject = nil
- this.lastSubjectPosition = Vector3.new(0, 5, 0)
- local lastVRRotation = 0
- local vrRotateKeyCooldown = {}
- function this:GetShiftLock()
- return ShiftLockController:IsShiftLocked()
- end
- function this:GetHumanoid()
- local player = PlayersService.LocalPlayer
- return findPlayerHumanoid(player)
- end
- function this:GetHumanoidRootPart()
- local humanoid = this:GetHumanoid()
- return humanoid and humanoid.Torso
- end
- function this:GetRenderCFrame(part)
- GetRenderCFrame(part)
- end
- function this:GetSubjectPosition()
- local result
- local camera = workspace.CurrentCamera
- local cameraSubject = camera and camera.CameraSubject
- if cameraSubject then
- if cameraSubject:IsA("VehicleSeat") then
- local subjectCFrame = GetRenderCFrame(cameraSubject)
- local offset = SEAT_OFFSET
- if VRService.VREnabled then
- offset = VR_SEAT_OFFSET
- end
- result = subjectCFrame.p + subjectCFrame:vectorToWorldSpace(offset)
- elseif cameraSubject:IsA("SkateboardPlatform") then
- local subjectCFrame = GetRenderCFrame(cameraSubject)
- result = subjectCFrame.p + SEAT_OFFSET
- elseif cameraSubject:IsA("BasePart") then
- local subjectCFrame = GetRenderCFrame(cameraSubject)
- result = subjectCFrame.p
- elseif cameraSubject:IsA("Model") then
- result = cameraSubject:GetModelCFrame().p
- elseif cameraSubject:IsA("Humanoid") then
- if cameraSubject:GetState() == Enum.HumanoidStateType.Dead and cameraSubject == this.lastSubject and VRService.VREnabled then
- result = this.lastSubjectPosition
- else
- local humanoidRootPart = cameraSubject.Torso
- if humanoidRootPart and humanoidRootPart:IsA("BasePart") then
- local subjectCFrame = GetRenderCFrame(humanoidRootPart)
- if cameraSubject.RigType == Enum.HumanoidRigType.R15 then
- result = subjectCFrame.p + subjectCFrame:vectorToWorldSpace(R15HeadHeight + cameraSubject.CameraOffset)
- else
- result = subjectCFrame.p + subjectCFrame:vectorToWorldSpace(HEAD_OFFSET + cameraSubject.CameraOffset)
- end
- end
- end
- end
- end
- this.lastSubject = cameraSubject
- this.lastSubjectPosition = result
- return result
- end
- function this:ResetCameraLook()
- end
- function this:GetCameraLook()
- return workspace.CurrentCamera and workspace.CurrentCamera.CoordinateFrame.lookVector or Vector3.new(0, 0, 1)
- end
- function this:GetCameraZoom()
- if this.currentZoom == nil then
- local player = PlayersService.LocalPlayer
- this.currentZoom = player and clamp(player.CameraMinZoomDistance, player.CameraMaxZoomDistance, 10) or 10
- end
- return this.currentZoom
- end
- function this:GetCameraActualZoom()
- local camera = workspace.CurrentCamera
- if camera then
- return camera.CoordinateFrame.p - camera.Focus.p.magnitude
- end
- end
- function this:GetCameraHeight()
- if not this:IsInFirstPerson() and VRService.VREnabled then
- local zoom = this:GetCameraZoom()
- return math.sin(VR_ANGLE) * zoom
- end
- return 0
- end
- function this:ViewSizeX()
- local result = 1024
- local camera = workspace.CurrentCamera
- if camera then
- result = camera.ViewportSize.X
- end
- return result
- end
- function this:ViewSizeY()
- local result = 768
- local camera = workspace.CurrentCamera
- if camera then
- result = camera.ViewportSize.Y
- end
- return result
- end
- function this:ScreenTranslationToAngle(translationVector)
- local screenX = this:ViewSizeX()
- local screenY = this:ViewSizeY()
- local xTheta = translationVector.x / screenX
- local yTheta = translationVector.y / screenY
- return Vector2.new(xTheta, yTheta)
- end
- function this:MouseTranslationToAngle(translationVector)
- local xTheta = translationVector.x / 1920
- local yTheta = translationVector.y / 1200
- return Vector2.new(xTheta, yTheta)
- end
- function this:RotateVector(startVector, xyRotateVector)
- local startCFrame = CFrame.new(Vector3.new(), startVector)
- local resultLookVector = CFrame.Angles(0, -xyRotateVector.x, 0) * startCFrame * CFrame.Angles(-xyRotateVector.y, 0, 0).lookVector
- return resultLookVector, Vector2.new(xyRotateVector.x, xyRotateVector.y)
- end
- function this:RotateCamera(startLook, xyRotateVector)
- if VRService.VREnabled then
- local yawRotatedVector, xyRotateVector = self:RotateVector(startLook, Vector2.new(xyRotateVector.x, 0))
- return Vector3.new(yawRotatedVector.x, 0, yawRotatedVector.z).unit, xyRotateVector
- else
- local startVertical = math.asin(startLook.y)
- local yTheta = clamp(-MAX_Y + startVertical, -MIN_Y + startVertical, xyRotateVector.y)
- return self:RotateVector(startLook, Vector2.new(xyRotateVector.x, yTheta))
- end
- end
- function this:IsInFirstPerson()
- return isFirstPerson
- end
- function this:UpdateMouseBehavior()
- if isFirstPerson or self:GetShiftLock() then
- pcall(function()
- GameSettings.RotationType = Enum.RotationType.CameraRelative
- end)
- if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
- UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter
- end
- else
- pcall(function()
- GameSettings.RotationType = Enum.RotationType.MovementRelative
- end)
- if isRightMouseDown or isMiddleMouseDown then
- UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
- else
- UserInputService.MouseBehavior = Enum.MouseBehavior.Default
- end
- end
- end
- function this:ZoomCamera(desiredZoom)
- local player = PlayersService.LocalPlayer
- if player then
- if player.CameraMode == Enum.CameraMode.LockFirstPerson then
- this.currentZoom = 0
- else
- this.currentZoom = clamp(player.CameraMinZoomDistance, player.CameraMaxZoomDistance, desiredZoom)
- end
- end
- isFirstPerson = self:GetCameraZoom() < 2
- ShiftLockController:SetIsInFirstPerson(isFirstPerson)
- self:UpdateMouseBehavior()
- return self:GetCameraZoom()
- end
- local rk4Integrator = function(position, velocity, t)
- local direction = velocity < 0 and -1 or 1
- local function acceleration(p, v)
- local accel = direction * math.max(1, p / 3.3 + 0.5)
- return accel
- end
- local p1 = position
- local v1 = velocity
- local a1 = acceleration(p1, v1)
- local p2 = p1 + v1 * (t / 2)
- local v2 = v1 + a1 * (t / 2)
- local a2 = acceleration(p2, v2)
- local p3 = p1 + v2 * (t / 2)
- local v3 = v1 + a2 * (t / 2)
- local a3 = acceleration(p3, v3)
- local p4 = p1 + v3 * t
- local v4 = v1 + a3 * t
- local a4 = acceleration(p4, v4)
- local positionResult = position + (v1 + 2 * v2 + 2 * v3 + v4) * (t / 6)
- local velocityResult = velocity + (a1 + 2 * a2 + 2 * a3 + a4) * (t / 6)
- return positionResult, velocityResult
- end
- function this:ZoomCameraBy(zoomScale)
- local zoom = this:GetCameraActualZoom()
- if zoom then
- if UserSettings():IsUserFeatureEnabled("UserBetterInertialScrolling") then
- zoom = rk4Integrator(zoom, zoomScale, 0.1)
- else
- zoom = rk4Integrator(zoom, zoomScale, 1)
- end
- self:ZoomCamera(zoom)
- end
- return self:GetCameraZoom()
- end
- function this:ZoomCameraFixedBy(zoomIncrement)
- return self:ZoomCamera(self:GetCameraZoom() + zoomIncrement)
- end
- function this:Update()
- end
- function this:ApplyVRTransform()
- if not VRService.VREnabled then
- return
- end
- local player = PlayersService.LocalPlayer
- if not player or not player.Character or not player.Character:FindFirstChild("HumanoidRootPart") or not player.Character.HumanoidRootPart:FindFirstChild("RootJoint") then
- return
- end
- local camera = workspace.CurrentCamera
- local cameraSubject = camera.CameraSubject
- local isInVehicle = cameraSubject and cameraSubject:IsA("VehicleSeat")
- if this:IsInFirstPerson() and not isInVehicle then
- local vrFrame = VRService:GetUserCFrame(Enum.UserCFrame.Head)
- local vrRotation = vrFrame - vrFrame.p
- local rootJoint = player.Character.HumanoidRootPart.RootJoint
- rootJoint.C0 = CFrame.new(vrRotation:vectorToObjectSpace(vrFrame.p)) * CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
- else
- local rootJoint = player.Character.HumanoidRootPart.RootJoint
- rootJoint.C0 = CFrame.new(0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 1, 0)
- end
- end
- local vrRotationIntensityExists = true
- local lastVrRotationCheck = 0
- function this:ShouldUseVRRotation()
- if not VRService.VREnabled then
- return false
- end
- if not vrRotationIntensityExists and tick() - lastVrRotationCheck < 1 then
- return false
- end
- local success, vrRotationIntensity = pcall(function()
- return StarterGui:GetCore("VRRotationIntensity")
- end)
- vrRotationIntensityExists = success and vrRotationIntensity ~= nil
- lastVrRotationCheck = tick()
- return success and vrRotationIntensity ~= nil and vrRotationIntensity ~= "Smooth"
- end
- function this:GetVRRotationInput()
- local vrRotateSum = ZERO_VECTOR2
- local vrRotationIntensity = StarterGui:GetCore("VRRotationIntensity")
- local vrGamepadRotation = self.GamepadPanningCamera or ZERO_VECTOR2
- local delayExpired = tick() - lastVRRotation >= self:GetRepeatDelayValue(vrRotationIntensity)
- if math.abs(vrGamepadRotation.x) >= self:GetActivateValue() then
- if delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] then
- local sign = 1
- if vrGamepadRotation.x < 0 then
- sign = -1
- end
- vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity) * sign
- vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = true
- end
- elseif math.abs(vrGamepadRotation.x) < self:GetActivateValue() - 0.1 then
- vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = nil
- end
- if self.TurningLeft then
- if delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Left] then
- vrRotateSum = vrRotateSum - self:GetRotateAmountValue(vrRotationIntensity)
- vrRotateKeyCooldown[Enum.KeyCode.Left] = true
- end
- else
- vrRotateKeyCooldown[Enum.KeyCode.Left] = nil
- end
- if self.TurningRight then
- if delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Right] then
- vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity)
- vrRotateKeyCooldown[Enum.KeyCode.Right] = true
- end
- else
- vrRotateKeyCooldown[Enum.KeyCode.Right] = nil
- end
- if vrRotateSum ~= ZERO_VECTOR2 then
- lastVRRotation = tick()
- end
- return vrRotateSum
- end
- local cameraTranslationConstraints = Vector3.new(1, 1, 1)
- local humanoidJumpOrigin, trackingHumanoid
- local cameraFrozen = false
- local subjectStateChangedConn, cameraChangedConn, workspaceChangedConn, humanoidChildAddedConn, humanoidChildRemovedConn
- local function cancelCameraFreeze(keepConstraints)
- if not keepConstraints then
- cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, 1, cameraTranslationConstraints.z)
- end
- if cameraFrozen then
- trackingHumanoid = nil
- cameraFrozen = false
- end
- end
- local function startCameraFreeze(subjectPosition, humanoidToTrack)
- if not cameraFrozen then
- humanoidJumpOrigin = subjectPosition
- trackingHumanoid = humanoidToTrack
- cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, 0, cameraTranslationConstraints.z)
- cameraFrozen = true
- end
- end
- local function rescaleCameraOffset(newScaleFactor)
- R15HeadHeight = R15_HEAD_OFFSET * newScaleFactor
- end
- local function onHumanoidSubjectChildAdded(child)
- if child.Name == "BodyHeightScale" and child:IsA("NumberValue") then
- if heightScaleChangedConn then
- heightScaleChangedConn:disconnect()
- end
- heightScaleChangedConn = child.Changed:connect(rescaleCameraOffset)
- rescaleCameraOffset(child.Value)
- end
- end
- local function onHumanoidSubjectChildRemoved(child)
- if child.Name == "BodyHeightScale" then
- rescaleCameraOffset(1)
- if heightScaleChangedConn then
- heightScaleChangedConn:disconnect()
- heightScaleChangedConn = nil
- end
- end
- end
- local function onNewCameraSubject()
- if subjectStateChangedConn then
- subjectStateChangedConn:disconnect()
- subjectStateChangedConn = nil
- end
- if humanoidChildAddedConn then
- humanoidChildAddedConn:disconnect()
- humanoidChildAddedConn = nil
- end
- if humanoidChildRemovedConn then
- humanoidChildRemovedConn:disconnect()
- humanoidChildRemovedConn = nil
- end
- if heightScaleChangedConn then
- heightScaleChangedConn:disconnect()
- heightScaleChangedConn = nil
- end
- local humanoid = workspace.CurrentCamera and workspace.CurrentCamera.CameraSubject
- if trackingHumanoid ~= humanoid then
- cancelCameraFreeze()
- end
- if humanoid and humanoid:IsA("Humanoid") then
- humanoidChildAddedConn = humanoid.ChildAdded:connect(onHumanoidSubjectChildAdded)
- humanoidChildRemovedConn = humanoid.ChildRemoved:connect(onHumanoidSubjectChildRemoved)
- for _, child in pairs(humanoid:GetChildren()) do
- onHumanoidSubjectChildAdded(child)
- end
- subjectStateChangedConn = humanoid.StateChanged:connect(function(oldState, newState)
- if newState == Enum.HumanoidStateType.Jumping and not this:IsInFirstPerson() and VRService.VREnabled then
- startCameraFreeze(this:GetSubjectPosition(), humanoid)
- elseif newState ~= Enum.HumanoidStateType.Jumping and newState ~= Enum.HumanoidStateType.Freefall then
- cancelCameraFreeze(true)
- end
- end)
- end
- end
- local function onCameraChanged(prop)
- if prop == "CameraSubject" then
- onNewCameraSubject()
- end
- end
- local function onCurrentCameraChanged()
- if cameraChangedConn then
- cameraChangedConn:disconnect()
- cameraChangedConn = nil
- end
- local camera = workspace.CurrentCamera
- if camera then
- camera.Changed:connect(onCameraChanged)
- onCameraChanged("CameraSubject")
- end
- end
- function this:GetVRFocus(subjectPosition, timeDelta)
- local newFocus
- local camera = workspace.CurrentCamera
- local lastFocus = self.LastCameraFocus or subjectPosition
- if not cameraFrozen then
- cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, math.min(1, cameraTranslationConstraints.y + 0.42 * timeDelta), cameraTranslationConstraints.z)
- end
- if cameraFrozen and humanoidJumpOrigin and humanoidJumpOrigin.y > lastFocus.y then
- newFocus = CFrame.new(Vector3.new(subjectPosition.x, math.min(humanoidJumpOrigin.y, lastFocus.y + 5 * timeDelta), subjectPosition.z))
- else
- newFocus = CFrame.new(Vector3.new(subjectPosition.x, lastFocus.y, subjectPosition.z):lerp(subjectPosition, cameraTranslationConstraints.y))
- end
- if cameraFrozen then
- if self:IsInFirstPerson() then
- cancelCameraFreeze()
- end
- if humanoidJumpOrigin and subjectPosition.y < humanoidJumpOrigin.y - 0.5 then
- cancelCameraFreeze()
- end
- end
- return newFocus
- end
- local startPos, lastPos, panBeginLook
- local fingerTouches = {}
- local NumUnsunkTouches = 0
- local StartingDiff, pinchBeginZoom
- this.ZoomEnabled = true
- this.PanEnabled = true
- this.KeyPanEnabled = true
- local function OnTouchBegan(input, processed)
- fingerTouches[input] = processed
- if not processed then
- NumUnsunkTouches = NumUnsunkTouches + 1
- end
- end
- local function OnTouchChanged(input, processed)
- if fingerTouches[input] == nil then
- fingerTouches[input] = processed
- if not processed then
- NumUnsunkTouches = NumUnsunkTouches + 1
- end
- end
- if NumUnsunkTouches == 1 then
- if fingerTouches[input] == false then
- panBeginLook = panBeginLook or this:GetCameraLook()
- startPos = startPos or input.Position
- lastPos = lastPos or startPos
- this.UserPanningTheCamera = true
- local delta = input.Position - lastPos
- if this.PanEnabled then
- local desiredXYVector = this:ScreenTranslationToAngle(delta) * TOUCH_SENSITIVTY
- this.RotateInput = this.RotateInput + desiredXYVector
- end
- lastPos = input.Position
- end
- else
- panBeginLook = nil
- startPos = nil
- lastPos = nil
- this.UserPanningTheCamera = false
- end
- if NumUnsunkTouches == 2 then
- local unsunkTouches = {}
- for touch, wasSunk in pairs(fingerTouches) do
- if not wasSunk then
- table.insert(unsunkTouches, touch)
- end
- end
- if #unsunkTouches == 2 then
- local difference = unsunkTouches[1].Position - unsunkTouches[2].Position.magnitude
- if StartingDiff and pinchBeginZoom then
- local scale = difference / math.max(0.01, StartingDiff)
- local clampedScale = clamp(0.1, 10, scale)
- if this.ZoomEnabled then
- this:ZoomCamera(pinchBeginZoom / clampedScale)
- end
- else
- StartingDiff = difference
- pinchBeginZoom = this:GetCameraActualZoom()
- end
- end
- else
- StartingDiff = nil
- pinchBeginZoom = nil
- end
- end
- local function OnTouchEnded(input, processed)
- if fingerTouches[input] == false then
- if NumUnsunkTouches == 1 then
- panBeginLook = nil
- startPos = nil
- lastPos = nil
- this.UserPanningTheCamera = false
- elseif NumUnsunkTouches == 2 then
- StartingDiff = nil
- pinchBeginZoom = nil
- end
- end
- if fingerTouches[input] ~= nil and fingerTouches[input] == false then
- NumUnsunkTouches = NumUnsunkTouches - 1
- end
- fingerTouches[input] = nil
- end
- local function OnMousePanButtonPressed(input, processed)
- if processed then
- return
- end
- this:UpdateMouseBehavior()
- panBeginLook = panBeginLook or this:GetCameraLook()
- startPos = startPos or input.Position
- lastPos = lastPos or startPos
- this.UserPanningTheCamera = true
- end
- local function OnMousePanButtonReleased(input, processed)
- this:UpdateMouseBehavior()
- if not isRightMouseDown and not isMiddleMouseDown then
- panBeginLook = nil
- startPos = nil
- lastPos = nil
- this.UserPanningTheCamera = false
- end
- end
- local function OnMouse2Down(input, processed)
- if processed then
- return
- end
- isRightMouseDown = true
- OnMousePanButtonPressed(input, processed)
- end
- local function OnMouse2Up(input, processed)
- isRightMouseDown = false
- OnMousePanButtonReleased(input, processed)
- end
- local function OnMouse3Down(input, processed)
- if processed then
- return
- end
- isMiddleMouseDown = true
- OnMousePanButtonPressed(input, processed)
- end
- local function OnMouse3Up(input, processed)
- isMiddleMouseDown = false
- OnMousePanButtonReleased(input, processed)
- end
- local function OnMouseMoved(input, processed)
- if not hasGameLoaded and VRService.VREnabled then
- return
- end
- if startPos and lastPos and panBeginLook then
- local currPos = lastPos + input.Delta
- local totalTrans = currPos - startPos
- if this.PanEnabled then
- local desiredXYVector = this:MouseTranslationToAngle(input.Delta) * MOUSE_SENSITIVITY
- this.RotateInput = this.RotateInput + desiredXYVector
- end
- lastPos = currPos
- elseif (this:IsInFirstPerson() or this:GetShiftLock()) and this.PanEnabled then
- local desiredXYVector = this:MouseTranslationToAngle(input.Delta) * MOUSE_SENSITIVITY
- this.RotateInput = this.RotateInput + desiredXYVector
- end
- end
- local function OnMouseWheel(input, processed)
- if not hasGameLoaded and VRService.VREnabled then
- return
- end
- if not processed and this.ZoomEnabled then
- if UserSettings():IsUserFeatureEnabled("UserBetterInertialScrolling") then
- this:ZoomCameraBy(-input.Position.Z / 15)
- else
- this:ZoomCameraBy(clamp(-1, 1, -input.Position.Z) * 1.4)
- end
- end
- end
- local round = function(num)
- return math.floor(num + 0.5)
- end
- local eight2Pi = math.pi / 4
- local function rotateVectorByAngleAndRound(camLook, rotateAngle, roundAmount)
- if camLook ~= Vector3.new(0, 0, 0) then
- camLook = camLook.unit
- local currAngle = math.atan2(camLook.z, camLook.x)
- local newAngle = round((math.atan2(camLook.z, camLook.x) + rotateAngle) / roundAmount) * roundAmount
- return newAngle - currAngle
- end
- return 0
- end
- local function OnKeyDown(input, processed)
- if not hasGameLoaded and VRService.VREnabled then
- return
- end
- if processed then
- return
- end
- if this.ZoomEnabled then
- if input.KeyCode == Enum.KeyCode.I then
- this:ZoomCameraBy(-5)
- elseif input.KeyCode == Enum.KeyCode.O then
- this:ZoomCameraBy(5)
- end
- end
- if panBeginLook == nil and this.KeyPanEnabled then
- if input.KeyCode == Enum.KeyCode.Left then
- this.TurningLeft = true
- elseif input.KeyCode == Enum.KeyCode.Right then
- this.TurningRight = true
- elseif input.KeyCode == Enum.KeyCode.Comma then
- local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1, 0, 1), -eight2Pi * 0.75, eight2Pi)
- if angle ~= 0 then
- this.RotateInput = this.RotateInput + Vector2.new(angle, 0)
- this.LastUserPanCamera = tick()
- this.LastCameraTransform = nil
- end
- elseif input.KeyCode == Enum.KeyCode.Period then
- local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1, 0, 1), eight2Pi * 0.75, eight2Pi)
- if angle ~= 0 then
- this.RotateInput = this.RotateInput + Vector2.new(angle, 0)
- this.LastUserPanCamera = tick()
- this.LastCameraTransform = nil
- end
- elseif input.KeyCode == Enum.KeyCode.PageUp then
- this.RotateInput = this.RotateInput + Vector2.new(0, math.rad(15))
- this.LastCameraTransform = nil
- elseif input.KeyCode == Enum.KeyCode.PageDown then
- this.RotateInput = this.RotateInput + Vector2.new(0, math.rad(-15))
- this.LastCameraTransform = nil
- end
- end
- end
- local function OnKeyUp(input, processed)
- if input.KeyCode == Enum.KeyCode.Left then
- this.TurningLeft = false
- elseif input.KeyCode == Enum.KeyCode.Right then
- this.TurningRight = false
- end
- end
- local lastThumbstickRotate
- local numOfSeconds = 0.7
- local currentSpeed = 0
- local maxSpeed = 6
- local vrMaxSpeed = 4
- local thumbstickSensitivity = 1
- local lastThumbstickPos = Vector2.new(0, 0)
- local ySensitivity = 0.65
- local lastVelocity
- local k = 0.35
- local lowerK = 0.8
- local function SCurveTranform(t)
- t = clamp(-1, 1, t)
- if t >= 0 then
- return k * t / (k - t + 1)
- end
- return -(lowerK * -t / (lowerK + t + 1))
- end
- local DEADZONE = 0.1
- local function toSCurveSpace(t)
- return (1 + DEADZONE) * (2 * math.abs(t) - 1) - DEADZONE
- end
- local fromSCurveSpace = function(t)
- return t / 2 + 0.5
- end
- local function gamepadLinearToCurve(thumbstickPosition)
- local function onAxis(axisValue)
- local sign = 1
- if axisValue < 0 then
- sign = -1
- end
- local point = fromSCurveSpace(SCurveTranform(toSCurveSpace(math.abs(axisValue))))
- point = point * sign
- return clamp(-1, 1, point)
- end
- return Vector2.new(onAxis(thumbstickPosition.x), onAxis(thumbstickPosition.y))
- end
- function this:UpdateGamepad()
- local gamepadPan = this.GamepadPanningCamera
- if gamepadPan and (hasGameLoaded or not VRService.VREnabled) then
- gamepadPan = gamepadLinearToCurve(gamepadPan)
- local currentTime = tick()
- if gamepadPan.X ~= 0 or gamepadPan.Y ~= 0 then
- this.userPanningTheCamera = true
- elseif gamepadPan == Vector2.new(0, 0) then
- lastThumbstickRotate = nil
- if lastThumbstickPos == Vector2.new(0, 0) then
- currentSpeed = 0
- end
- end
- local finalConstant = 0
- if lastThumbstickRotate then
- if VRService.VREnabled then
- currentSpeed = vrMaxSpeed
- else
- local elapsedTime = (currentTime - lastThumbstickRotate) * 10
- currentSpeed = currentSpeed + maxSpeed * (elapsedTime * elapsedTime / numOfSeconds)
- if currentSpeed > maxSpeed then
- currentSpeed = maxSpeed
- end
- if lastVelocity then
- local velocity = (gamepadPan - lastThumbstickPos) / (currentTime - lastThumbstickRotate)
- local velocityDeltaMag = velocity - lastVelocity.magnitude
- if velocityDeltaMag > 12 then
- currentSpeed = currentSpeed * (20 / velocityDeltaMag)
- if currentSpeed > maxSpeed then
- currentSpeed = maxSpeed
- end
- end
- end
- end
- finalConstant = thumbstickSensitivity * currentSpeed
- lastVelocity = (gamepadPan - lastThumbstickPos) / (currentTime - lastThumbstickRotate)
- end
- lastThumbstickPos = gamepadPan
- lastThumbstickRotate = currentTime
- return Vector2.new(gamepadPan.X * finalConstant, gamepadPan.Y * finalConstant * ySensitivity)
- end
- return Vector2.new(0, 0)
- end
- local InputBeganConn, InputChangedConn, InputEndedConn, MenuOpenedConn, ShiftLockToggleConn, GamepadConnectedConn, GamepadDisconnectedConn
- function this:DisconnectInputEvents()
- if InputBeganConn then
- InputBeganConn:disconnect()
- InputBeganConn = nil
- end
- if InputChangedConn then
- InputChangedConn:disconnect()
- InputChangedConn = nil
- end
- if InputEndedConn then
- InputEndedConn:disconnect()
- InputEndedConn = nil
- end
- if MenuOpenedConn then
- MenuOpenedConn:disconnect()
- MenuOpenedConn = nil
- end
- if ShiftLockToggleConn then
- ShiftLockToggleConn:disconnect()
- ShiftLockToggleConn = nil
- end
- if GamepadConnectedConn then
- GamepadConnectedConn:disconnect()
- GamepadConnectedConn = nil
- end
- if GamepadDisconnectedConn then
- GamepadDisconnectedConn:disconnect()
- GamepadDisconnectedConn = nil
- end
- if subjectStateChangedConn then
- subjectStateChangedConn:disconnect()
- subjectStateChangedConn = nil
- end
- if cameraChangedConn then
- cameraChangedConn:disconnect()
- cameraChangedConn = nil
- end
- if workspaceChangedConn then
- workspaceChangedConn:disconnect()
- workspaceChangedConn = nil
- end
- this.TurningLeft = false
- this.TurningRight = false
- this.LastCameraTransform = nil
- self.LastSubjectCFrame = nil
- this.UserPanningTheCamera = false
- this.RotateInput = Vector2.new()
- this.GamepadPanningCamera = Vector2.new(0, 0)
- startPos = nil
- lastPos = nil
- panBeginLook = nil
- isRightMouseDown = false
- isMiddleMouseDown = false
- fingerTouches = {}
- NumUnsunkTouches = 0
- StartingDiff = nil
- pinchBeginZoom = nil
- if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then
- UserInputService.MouseBehavior = Enum.MouseBehavior.Default
- end
- end
- function this:ResetInputStates()
- isRightMouseDown = false
- isMiddleMouseDown = false
- OnMousePanButtonReleased()
- if UserInputService.TouchEnabled then
- for inputObject, value in pairs(fingerTouches) do
- fingerTouches[inputObject] = nil
- end
- panBeginLook = nil
- startPos = nil
- lastPos = nil
- this.UserPanningTheCamera = false
- StartingDiff = nil
- pinchBeginZoom = nil
- NumUnsunkTouches = 0
- end
- end
- function this:ConnectInputEvents()
- InputBeganConn = UserInputService.InputBegan:connect(function(input, processed)
- if input.UserInputType == Enum.UserInputType.Touch then
- OnTouchBegan(input, processed)
- elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
- OnMouse2Down(input, processed)
- elseif input.UserInputType == Enum.UserInputType.MouseButton3 then
- OnMouse3Down(input, processed)
- end
- if input.UserInputType == Enum.UserInputType.Keyboard then
- OnKeyDown(input, processed)
- end
- end)
- InputChangedConn = UserInputService.InputChanged:connect(function(input, processed)
- if input.UserInputType == Enum.UserInputType.Touch then
- OnTouchChanged(input, processed)
- elseif input.UserInputType == Enum.UserInputType.MouseMovement then
- OnMouseMoved(input, processed)
- elseif input.UserInputType == Enum.UserInputType.MouseWheel then
- OnMouseWheel(input, processed)
- end
- end)
- InputEndedConn = UserInputService.InputEnded:connect(function(input, processed)
- if input.UserInputType == Enum.UserInputType.Touch then
- OnTouchEnded(input, processed)
- elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
- OnMouse2Up(input, processed)
- elseif input.UserInputType == Enum.UserInputType.MouseButton3 then
- OnMouse3Up(input, processed)
- end
- if input.UserInputType == Enum.UserInputType.Keyboard then
- OnKeyUp(input, processed)
- end
- end)
- MenuOpenedConn = GuiService.MenuOpened:connect(function()
- this:ResetInputStates()
- end)
- workspaceChangedConn = workspace.Changed:connect(function(prop)
- if prop == "CurrentCamera" then
- onCurrentCameraChanged()
- end
- end)
- onCurrentCameraChanged()
- ShiftLockToggleConn = ShiftLockController.OnShiftLockToggled.Event:connect(function()
- this:UpdateMouseBehavior()
- end)
- this.RotateInput = Vector2.new()
- local activateGamepad
- local function assignActivateGamepad()
- local connectedGamepads = UserInputService:GetConnectedGamepads()
- if #connectedGamepads > 0 then
- for i = 1, #connectedGamepads do
- if activateGamepad == nil then
- activateGamepad = connectedGamepads[i]
- elseif connectedGamepads[i].Value < activateGamepad.Value then
- activateGamepad = connectedGamepads[i]
- end
- end
- end
- if activateGamepad == nil then
- activateGamepad = Enum.UserInputType.Gamepad1
- end
- end
- GamepadConnectedConn = UserInputService.GamepadDisconnected:connect(function(gamepadEnum)
- if activateGamepad ~= gamepadEnum then
- return
- end
- activateGamepad = nil
- assignActivateGamepad()
- end)
- GamepadDisconnectedConn = UserInputService.GamepadConnected:connect(function(gamepadEnum)
- if activateGamepad == nil then
- assignActivateGamepad()
- end
- end)
- local function getGamepadPan(name, state, input)
- if input.UserInputType == activateGamepad and input.KeyCode == Enum.KeyCode.Thumbstick2 then
- if state == Enum.UserInputState.Cancel then
- this.GamepadPanningCamera = Vector2.new(0, 0)
- return
- end
- local inputVector = Vector2.new(input.Position.X, -input.Position.Y)
- if inputVector.magnitude > THUMBSTICK_DEADZONE then
- this.GamepadPanningCamera = Vector2.new(input.Position.X, -input.Position.Y)
- else
- this.GamepadPanningCamera = Vector2.new(0, 0)
- end
- end
- end
- local function doGamepadZoom(name, state, input)
- if input.UserInputType == activateGamepad and input.KeyCode == Enum.KeyCode.ButtonR3 and state == Enum.UserInputState.Begin and this.ZoomEnabled then
- if this.currentZoom > 0.5 then
- this:ZoomCamera(0)
- else
- this:ZoomCamera(10)
- end
- end
- end
- ContextActionService:BindAction("RootCamGamepadPan", getGamepadPan, false, Enum.KeyCode.Thumbstick2)
- ContextActionService:BindAction("RootCamGamepadZoom", doGamepadZoom, false, Enum.KeyCode.ButtonR3)
- assignActivateGamepad()
- self:UpdateMouseBehavior()
- end
- function this:SetEnabled(newState)
- if newState ~= self.Enabled then
- self.Enabled = newState
- if self.Enabled then
- self:ConnectInputEvents()
- self.cframe = workspace.CurrentCamera.CoordinateFrame
- else
- self:DisconnectInputEvents()
- end
- end
- end
- local function OnPlayerAdded(player)
- player.Changed:connect(function(prop)
- if this.Enabled and (prop == "CameraMode" or prop == "CameraMaxZoomDistance" or prop == "CameraMinZoomDistance") then
- this:ZoomCameraFixedBy(0)
- end
- end)
- local function OnCharacterAdded(newCharacter)
- if not FFlagSpawnLocationFixEnabled then
- this:ZoomCamera(12.5)
- end
- local humanoid = findPlayerHumanoid(player)
- local start = tick()
- while tick() - start < 0.3 and (humanoid == nil or humanoid.Torso == nil) do
- wait()
- humanoid = findPlayerHumanoid(player)
- end
- if not FFlagSpawnLocationFixEnabled then
- wait()
- end
- if humanoid and humanoid.Torso and player.Character == newCharacter then
- local newDesiredLook = humanoid.Torso.CFrame.lookVector - Vector3.new(0, 0.23, 0).unit
- local horizontalShift = findAngleBetweenXZVectors(newDesiredLook, this:GetCameraLook())
- local vertShift = math.asin(this:GetCameraLook().y) - math.asin(newDesiredLook.y)
- if not IsFinite(horizontalShift) then
- horizontalShift = 0
- end
- if not IsFinite(vertShift) then
- vertShift = 0
- end
- this.RotateInput = Vector2.new(horizontalShift, vertShift)
- this.LastCameraTransform = nil
- end
- if FFlagSpawnLocationFixEnabled then
- wait()
- this:ZoomCamera(12.5)
- end
- end
- player.CharacterAdded:connect(function(character)
- if this.Enabled or SetCameraOnSpawn then
- OnCharacterAdded(character)
- SetCameraOnSpawn = false
- end
- end)
- if player.Character then
- spawn(function()
- OnCharacterAdded(player.Character)
- end)
- end
- end
- if PlayersService.LocalPlayer then
- OnPlayerAdded(PlayersService.LocalPlayer)
- end
- PlayersService.ChildAdded:connect(function(child)
- if child and PlayersService.LocalPlayer == child then
- OnPlayerAdded(PlayersService.LocalPlayer)
- end
- end)
- local function OnGameLoaded()
- hasGameLoaded = true
- end
- spawn(function()
- if game:IsLoaded() then
- OnGameLoaded()
- else
- game.Loaded:wait()
- OnGameLoaded()
- end
- end)
- local function FakeZoomCamera(n)
- this:ZoomCamera(n)
- end
- script.Parent.Parent:WaitForChild("ZoomCamera").Event:connect(FakeZoomCamera)
- return this
- end
- return CreateCamera
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement