SyntaxGameServer/RCCService2018/content/scripts/PlayerScripts/StarterPlayerScripts/CameraScript/RootCamera/VRCamera.lua

261 lines
7.7 KiB
Lua

local PlayersService = game:GetService('Players')
local UserInputService = game:GetService('UserInputService')
local VRService = game:GetService("VRService")
local ContextActionService = game:GetService("ContextActionService")
local LocalPlayer = PlayersService.LocalPlayer
local RootCameraCreator = require(script.Parent)
local XZ_VECTOR = Vector3.new(1, 0, 1)
local ZERO_VECTOR2 = Vector2.new(0, 0)
local PRESNAP_TIME_OFFSET = 0.5 --seconds
local PRESNAP_TIME_LATCH = PRESNAP_TIME_OFFSET * 10
local HEIGHT_OFFSET = 3
local HORZ_OFFSET = 4
local function CreateVRCamera()
local module = RootCameraCreator()
module.AllowOcclusion = false
local lastUpdate = tick()
local forceSnap = true
local forceSnapPoint = nil
local lastLook = Vector3.new(0, 0, -1)
local movementUpdateEventConn = nil
local lastSnapTimeEstimate = math.huge
local snapId = 0
local waitingForSnap = false
local snappedHeadOffset = VRService:GetUserCFrame(Enum.UserCFrame.Head).p
local snapPendingWhileJumping = false
local isJumping = false
local autoSnapsPaused = false
local currentDestination = nil
local function forceSnapTo(snapPoint)
forceSnap = true
forceSnapPoint = snapPoint
snapId = snapId + 1
waitingForSnap = false
end
local function onMovementUpdateEvent(updateType, arg1, arg2)
if updateType == "targetPoint" then
currentDestination = arg1
end
if updateType == "timing" then
local estimatedTimeRemaining = arg1
local snapPoint = arg2
if waitingForSnap and estimatedTimeRemaining > lastSnapTimeEstimate then
--our estimate grew, so cancel this snap and potentially re-evaluate it
waitingForSnap = false
snapId = snapId + 1
end
if estimatedTimeRemaining < PRESNAP_TIME_LATCH and estimatedTimeRemaining > PRESNAP_TIME_OFFSET then
waitingForSnap = true
snapId = snapId + 1
local thisSnapId = snapId
local timeToWait = estimatedTimeRemaining - PRESNAP_TIME_OFFSET
coroutine.wrap(function()
wait(timeToWait)
if waitingForSnap and snapId == thisSnapId then
waitingForSnap = false
forceSnap = true
forceSnapPoint = snapPoint
end
end)()
end
elseif updateType == "shortPath" or updateType == "pathFailure" or updateType == "offtrack" and not autoSnapsPaused then
if isJumping then
snapPendingWhileJumping = true
return
end
local snapPoint = arg1
forceSnapTo(snapPoint)
elseif updateType == "force" then
snapPendingWhileJumping = false
isJumping = false
forceSnapTo(nil)
end
end
local function onResetCameraAction(actionName, inputState, inputObj)
if inputState == Enum.UserInputState.Begin then
autoSnapsPaused = true
onMovementUpdateEvent("force", nil, nil)
else
autoSnapsPaused = false
end
end
local function bindActions(bind)
if bind then
ContextActionService:BindActionAtPriority("ResetCameraVR", onResetCameraAction, false, Enum.ContextActionPriority.Low.Value, Enum.KeyCode.ButtonL2)
else
autoSnapsPaused = false
ContextActionService:UnbindAction("ResetCameraVR")
end
end
local lastKnownTorsoPosition = Vector3.new()
local function onCharacterAdded(character)
local humanoid = character:WaitForChild("Humanoid")
humanoid.StateChanged:connect(function(oldState, newState)
local camera = workspace.CurrentCamera
if not camera or camera.CameraSubject ~= humanoid or not VRService.VREnabled then
return
end
if newState == Enum.HumanoidStateType.Jumping then
isJumping = true
elseif newState == Enum.HumanoidStateType.Landed then
if snapPendingWhileJumping then
forceSnapTo(nil)
snapPendingWhileJumping = false
end
isJumping = false
elseif newState == Enum.HumanoidStateType.Dead then
forceSnapTo(nil)
elseif newState == Enum.HumanoidStateType.Swimming then
if isJumping and snapPendingWhileJumping then
--Jumped into water and let go of controls during flight, treat as a normal landing
forceSnapTo(nil)
snapPendingWhileJumping = false
end
isJumping = false
end
end)
local humanoidRootPart = humanoid.Torso
humanoidRootPart.Changed:connect(function(property)
local camera = workspace.CurrentCamera
local cameraSubject = camera.CameraSubject
if camera and cameraSubject == humanoid and property == "CFrame" or property == "Position" then
if (humanoidRootPart.Position - lastKnownTorsoPosition).magnitude > 5 then
forceSnapTo(nil)
end
end
end)
end
if LocalPlayer.Character then
onCharacterAdded(LocalPlayer.Character)
end
LocalPlayer.CharacterAdded:connect(onCharacterAdded)
spawn(function()
local rootCamera = script.Parent
if not rootCamera then return end
local cameraScript = rootCamera.Parent
if not cameraScript then return end
local playerScripts = cameraScript.Parent
if not playerScripts then return end
local controlScript = playerScripts:WaitForChild("ControlScript")
local masterControlModule = controlScript:WaitForChild("MasterControl")
local vrNavigationModule = masterControlModule:WaitForChild("VRNavigation")
local movementUpdateEvent = vrNavigationModule:WaitForChild("MovementUpdate")
movementUpdateEventConn = movementUpdateEvent.Event:connect(onMovementUpdateEvent)
end)
local onCameraSubjectChangedConn = nil
local function onCameraSubjectChanged()
local camera = workspace.CurrentCamera
if camera and camera.CameraSubject then
delay(1, function () forceSnap = true end)
end
end
local function onCurrentCameraChanged()
if onCameraSubjectChangedConn then
onCameraSubjectChangedConn:disconnect()
onCameraSubjectChangedConn = nil
end
if workspace.CurrentCamera then
onCameraSubjectChangedConn = workspace.CurrentCamera:GetPropertyChangedSignal("CameraSubject"):connect(onCameraSubjectChanged)
onCameraSubjectChanged()
end
end
workspace:GetPropertyChangedSignal("CurrentCamera"):connect(onCurrentCameraChanged)
onCurrentCameraChanged()
local function onVREnabled()
bindActions(VRService.VREnabled)
end
VRService:GetPropertyChangedSignal("VREnabled"):connect(onVREnabled)
function module:Update()
local now = tick()
local timeDelta = now - lastUpdate
local camera = workspace.CurrentCamera
local cameraSubject = camera and camera.CameraSubject
local player = PlayersService.LocalPlayer
local subjectPosition = self:GetSubjectPosition()
local zoom = self:GetCameraZoom()
local subjectPosition = self:GetSubjectPosition()
local gamepadRotation = self:UpdateGamepad()
if subjectPosition and currentDestination then
local dist = (currentDestination - subjectPosition).magnitude
if dist < 10 then
forceSnap = true
forceSnapPoint = currentDestination
currentDestination = nil
end
end
if cameraSubject and cameraSubject:IsA("Humanoid") then
local rootPart = cameraSubject.RootPart
if rootPart then
lastKnownTorsoPosition = rootPart.Position
end
end
local look = lastLook
if subjectPosition and forceSnap then
forceSnap = false
local newFocusPoint = subjectPosition
if forceSnapPoint then
newFocusPoint = Vector3.new(forceSnapPoint.X, subjectPosition.Y, forceSnapPoint.Z)
end
camera.Focus = CFrame.new(newFocusPoint)
forceSnapPoint = nil
look = camera:GetRenderCFrame().lookVector
snappedHeadOffset = VRService:GetUserCFrame(Enum.UserCFrame.Head).p
end
if subjectPosition and player and camera then
local cameraFocusP = camera.Focus.p
self.RotateInput = ZERO_VECTOR2
look = (look * XZ_VECTOR).unit
camera.CFrame = CFrame.new(cameraFocusP - (HORZ_OFFSET * look)) + Vector3.new(0, HEIGHT_OFFSET, 0) - snappedHeadOffset
self.LastCameraTransform = camera.CFrame
self.LastCameraFocus = camera.Focus
end
lastLook = look
lastUpdate = now
end
return module
end
return CreateVRCamera