-- //Services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local VRService = game:GetService("VRService")
local UserInputService = game:GetService("UserInputService")
-- //Tables
local module = {}
module.__index = module
module.objects = {}
local configuration = {
smoothness = 0.05,
cameraOffset = 1.5,
handRotation = CFrame.Angles(math.rad(90), 0, 0),
rotationKeyCode = Enum.KeyCode.Thumbstick2,
}
local ints = {
1,
0,
-1
}
function module.new(player: Player)
local self = setmetatable({}, module)
self.player = player
self.character = player.Character or player.CharacterAdded:Wait()
self.humanoid = self.character:WaitForChild("Humanoid")
self.rootPart = self.character:WaitForChild("HumanoidRootPart")
self.camera = workspace.CurrentCamera
self.trackHead = self.character:WaitForChild("TrackHead")
self.trackRight = self.character:WaitForChild("TrackRight")
self.trackLeft = self.character:WaitForChild("TrackLeft")
local vInterface = script:FindFirstChild("vInterface")
self.rotating = vInterface.rotation.Value
self.rotationIndex = {
smooth = vInterface.rotation.smooth.Value,
snap = vInterface.rotation.snap.Value,
}
self.snapAmount = vInterface.rotation.snap.amount.Value
self.input = Vector3.zero
self.yaw = 0
self.headCFrame = CFrame.identity
self.rightHandCFrame = CFrame.identity
self.leftHandCFrame = CFrame.identity
self._connections = {} :: { RBXScriptConnection }
self._alignmentTemplates = {
Instance.new("AlignPosition"),
Instance.new("AlignOrientation"),
}
return self
end
function module:Init()
self.player.CameraMode = Enum.CameraMode.LockFirstPerson
self.camera.CameraType = Enum.CameraType.Scriptable
self.humanoid.AutoRotate = false
self:_setupAlignments()
VRService:RecenterUserHeadCFrame()
self:_connectEvents()
end
function module:Destroy()
for _, connection in self._connections do
connection:Disconnect()
end
table.clear(self._connections)
end
function module:_setupAlignments()
for _, part in ipairs(self.character:GetChildren()) do
if (part:IsA("BasePart") and part.Name ~= "Head") then
part:GetPropertyChangedSignal("LocalTransparencyModifier"):Connect(function()
part.LocalTransparencyModifier = 0
end)
part.LocalTransparencyModifier = 0
if string.match(part.Name, "Track") then
for _, template in ipairs(self._alignmentTemplates) do
local clone = template:Clone()
local attachment = part:FindFirstChild(part.Name .. "Attachment")
if not part:FindFirstChild(clone.Name) then
clone.Parent = part
end
if attachment then
clone.Attachment0 = attachment
end
clone.RigidityEnabled = true
if clone:IsA("AlignPosition") then
clone.Mode = Enum.PositionAlignmentMode.OneAttachment
elseif clone:IsA("AlignOrientation") then
clone.Mode = Enum.OrientationAlignmentMode.OneAttachment
end
if not table.find(module.objects, clone) then
table.insert(module.objects, clone)
end
end
end
end
end
end
function module:_connectEvents()
table.insert(
self._connections,
RunService.RenderStepped:Connect(function(deltaTime: number)
self:_step(deltaTime)
end)
)
table.insert(
self._connections,
UserInputService.InputChanged:Connect(function(input: InputObject, gameProcessed: boolean)
self:_onInputChanged(input, gameProcessed)
end)
)
end
function module:_step(deltaTime: number)
self.headCFrame = VRService:GetUserCFrame(Enum.UserCFrame.Head)
self.rightHandCFrame = VRService:GetUserCFrame(Enum.UserCFrame.RightHand)
self.leftHandCFrame = VRService:GetUserCFrame(Enum.UserCFrame.LeftHand)
self:_updateCharacterFacing()
self:_updateCamera()
self:_updateTrackParts()
end
function module:_updateYaw(input: InputObject, deltaTime: number)
if self.rotating then
if self.rotationIndex.smooth then
--self.yaw += self.input.X * configuration.smoothness
elseif self.rotationIndex.snap then
self.yaw += self.input.X * self.snapAmount --* deltaTime
self.camera.CFrame = CFrame.Angles(0, math.rad(self.yaw), 0):Inverse()
end
else
return
end
end
function module:_updateCharacterFacing()
if self.rootPart then
local lookDirection = self.headCFrame.LookVector
local flatLook = Vector3.new(lookDirection.X, 0, lookDirection.Z)
if flatLook.Magnitude < 1e-4 then
return
end
self.rootPart.CFrame = CFrame.lookAt(self.rootPart.Position, self.rootPart.Position + flatLook.Unit) * CFrame.Angles(0, math.rad(self.yaw), 0):Inverse()
else
return
end
end
function module:_updateCamera()
if self.rootPart then
local neckWorld = self.camera.CFrame * self.headCFrame
local subjectPosition = self.rootPart.Position
local goalPosition = subjectPosition - neckWorld.Position + self.camera.CFrame.Position
goalPosition = Vector3.new(goalPosition.X, subjectPosition.Y + configuration.cameraOffset, goalPosition.Z)
local currentRotation = self.camera.CFrame - self.camera.CFrame.Position
self.camera.CFrame = (CFrame.new(goalPosition) * currentRotation)
else
return
end
end
function module:_updateTrackParts()
if not (self.trackHead and self.trackRight and self.trackLeft) then
return
end
if (self.trackHead and self.trackRight and self.trackLeft) then
self.trackHead.CFrame = self.camera.CFrame * self.headCFrame
self.trackRight.CFrame = self.camera.CFrame * self.rightHandCFrame * configuration.handRotation
self.trackLeft.CFrame = self.camera.CFrame * self.leftHandCFrame * configuration.handRotation
end
-- //for loop
for i, obj in ipairs(module.objects) do
if obj then
if obj:IsA("AlignPosition") then
obj.Position = obj.Parent.Position
elseif obj:IsA("AlignOrientation") then
obj.CFrame = obj.Parent.CFrame
end
end
if not obj then
return
end
end
end
function module:_onInputChanged(input: InputObject, gameProcessed: boolean)
if gameProcessed then
return
end
if input.KeyCode == configuration.rotationKeyCode then
self.input = input.Position
-- //for loop
for i, vl in ints do
if self.input.X == vl then
self:_updateYaw()
end
end
end
end
return module
1 Like
edit: needed a debounce, thanks and goodnight
1 Like
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.