我的视角模型本地脚本在移动躯干时会让手臂抖动
当我以高速移动躯干时,手臂会抖动,理想的状态应该是手臂能立即旋转。据我所知,这只会在Z 轴和X 轴方向发生。
展示问题的媒体:


https://files.catbox.moe/402frc.mp4
现在我在视图模型中使用真实的手臂作为参考,我猜这是因为左右肩膀跟着它,但它应该正常跟随视图模型,完全没有抖动。
视图模型模块:
------------------------------------Settings\/
local invertedSway = false -- true means sway will smooth behind and false means it will predict
local thirdpersonArms = true -- should arms follow camera angle in thrid person
local swaySensitivity = 1 -- higher number = more sway
local UseOffset = true -- if true then it will use the torso orientation for viewbobbing instead of the preset positions
local offsetDiv = 2 -- how much the offset is divided by if useoffset is true
-- walk bob if useoffset is false
local period = 2
local omega = 5
local amplitude = .2 -- studs
------------------------------------Settings/\
--------------------------------------- Code\/
local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local ToolFramework = ReplicatedStorage:FindFirstChild("ToolFramework")
local Modules = ReplicatedStorage:WaitForChild("Modules")
local Misc = ReplicatedStorage.Miscs
local ViewmodelRigs = Misc.ViewmodelRigs
local viewmodelr6 = ViewmodelRigs.ViewModel
local ToolDataServer = require(ToolFramework:FindFirstChild("Registry"))
local ToolSettingsDefault = ToolDataServer.Ranged["ToolSettings"]
local Players = game:GetService("Players")
local uis = game:GetService("UserInputService")
local spring = require(script.spring)
local ViewModel = {}
ViewModel.__index = ViewModel
-- Constructor
function ViewModel.new(boundKey,offsetobject : Vector3Value, rotationobject : Vector3Value)
local self = setmetatable({}, ViewModel)
self.Seam = require(Modules.Seam)
self.Scope = self.Seam.Scope(self.Seam)
self.HoldingAim = self.Scope:Value(false)
self.player = Players.LocalPlayer
self.camera = workspace.CurrentCamera
self.boundKey = boundKey or "LeftControl"
self.renderConn = nil
self.charConn = nil
self.dieConn = nil
self.sway = spring.create()
self.offset = Instance.new("Vector3Value",self.camera)
self.offset.Name = "Offset"
self.rot_offset = Instance.new("Vector3Value",self.camera)
self.rot_offset.Name = "Rot_Offset"
-- build the invisible head+torso model
--self.model = Instance.new("Model")
--self.model.Name = "ViewModel"
--self.model.Parent = self.camera
self.humanoid = nil
self.characterRemoved = nil
self.model = viewmodelr6:Clone()
self.model.Name = "ViewModel"
self.model.Parent = self.camera
self.ViewmodelAimingVectorDefault = Vector3.zero
self.ViewmodelNoAimingVectorDefault = Vector3.zero
self.TargetAimingVector = nil
self.TargetAimingVector = self.Scope:Computed(function(Use) -- The speed based on whether we are sprinting
if Use(self.HoldingAim) then
return self.ViewmodelAimingVectorDefault
else
return self.ViewmodelNoAimingVectorDefault
end
end)
self.Scope:New(self.offset, {
Value = self.Scope:Spring(self.TargetAimingVector, 24, 0.9) -- We use a spring so that it's not a sudden change
})
self:_createParts()
return self
end
-- create head, torso, and weld
function ViewModel:_createParts()
local head = self.model.Head
local torso = self.model.Torso
local weld = Instance.new("Weld")
--local head = Instance.new("Part")
--local torso = Instance.new("Part")
--local weld = Instance.new("Weld")
--[[
head.Name = "Head"
head.Size = Vector3.new(2, 1, 1)
head.Anchored = true
head.Transparency = 1
head.CanCollide = false
head.CanQuery = false
head.Parent = self.model
head.CollisionGroup = "CannotCollide"
torso.Name = "Torso"
torso.Size = Vector3.new(2, 2, 1)
torso.Transparency = 1
torso.CanCollide = false
torso.CanQuery = false
torso.Parent = self.model
torso.CollisionGroup = "CannotCollide"
--]]
weld.Part0 = head
weld.Part1 = torso
weld.C0 = CFrame.new(0, -1.5, 0)
weld.Parent = head
self.headPart = head
self.torsoPart = torso
self.model.PrimaryPart = head
end
-- start listening for character and render steps
function ViewModel:Init()
-- set the bound key for MouseLockController
self.player.PlayerScripts:WaitForChild("PlayerModule")
:WaitForChild("CameraModule")
:WaitForChild("MouseLockController")
:WaitForChild("BoundKeys").Value = self.boundKey
-- connect CharacterAdded
if self.player.Character:FindFirstChildWhichIsA("Humanoid") then
self.humanoid = self.player.Character:FindFirstChildWhichIsA("Humanoid")
end
self.charConn = self.player.CharacterAdded:Connect(function(char)
self:_onCharacter(char)
end)
self.dieConn = self.humanoid.Died:Connect(function()
self:Destroy()
end)
self.characterRemoved = self.player.CharacterRemoving:Connect(function()
self:Destroy()
end)
-- if character already loaded
if self.player.Character then
self:_onCharacter(self.player.Character)
end
end
-- Handles character spawn and viewmodel updates
function ViewModel:_onCharacter(char)
-- Disconnect previous RenderStepped connection
if self.renderConn then
self.renderConn:Disconnect()
end
-- References
local animator: Animator = char:FindFirstChildWhichIsA("Animator")
or char:FindFirstChild("Humanoid") and char.Humanoid:FindFirstChildWhichIsA("Animator")
local torso = char:WaitForChild("Torso")
local leftShoulder = torso:WaitForChild("Left Shoulder")
local rightShoulder = torso:WaitForChild("Right Shoulder")
local leftArm = char:WaitForChild("Left Arm")
local rightArm = char:WaitForChild("Right Arm")
leftShoulder.Part0 = self.torsoPart
rightShoulder.Part0 = self.torsoPart
-- Bobbing and sway variables
local bobbingVector = Vector3.new()
local velocity = 0
local mega = omega * math.pi / period
-- Connect to RenderStepped
RunService:BindToRenderStep("viewmodel", Enum.RenderPriority.Camera + 1, function(dt)
local cam = self.camera
local firstPerson = (cam.CFrame.Position - cam.Focus.Position).Magnitude < 0.75
local t = tick()
-- Smooth velocity tracking
velocity = math.lerp(velocity, torso.Velocity.Magnitude, 0.1)
-- Bobbing calculation
local speedmod = velocity / 16 > 1.5 and 2 or 1
local Bobx = -math.cos(t * mega * speedmod)
local Boby = 1 - (Bobx * Bobx)
Bobx = -Bobx * amplitude * (velocity / 16)
Boby = -Boby * amplitude * (velocity / 16)
-- Optional rotation offset based on torso vs root orientation
local ROTOFFSET = CFrame.Angles(0, 0, 0)
if UseOffset then
local relative = torso.CFrame:ToObjectSpace(char.HumanoidRootPart.CFrame)
local rotX, rotY, rotZ = relative:ToOrientation()
ROTOFFSET = CFrame.Angles(
-rotX / offsetDiv,
-rotY / offsetDiv, 0)
else
bobbingVector = bobbingVector:Lerp(Vector3.new(Bobx, Boby, 0), 0.2)
end
-- Reparent shoulders to viewmodel torso
--leftShoulder.Part0 = self.torsoPart
--rightShoulder.Part0 = self.torsoPart
-- Ensure arms are visible
leftArm.LocalTransparencyModifier = 0
rightArm.LocalTransparencyModifier = 0
-- Mouse sway
local md = uis:GetMouseDelta()
self.sway:shove(Vector3.new(md.Y, md.X))
local sway = self.sway:update(dt)
if not invertedSway then
sway = -sway
end
-- First-person viewmodel positioning
if firstPerson then
self.model.PrimaryPart = self.headPart
local camcf = cam.CFrame
camcf += camcf.RightVector * self.offset.Value.X
camcf += camcf.UpVector * self.offset.Value.Y
camcf += camcf.LookVector * self.offset.Value.Z
camcf *= CFrame.Angles(
math.rad(bobbingVector.Y * 15),
math.rad(bobbingVector.X * 15),
0
) * ROTOFFSET * CFrame.Angles(
math.rad(self.rot_offset.Value.X),
math.rad(self.rot_offset.Value.Y),
math.rad(self.rot_offset.Value.Z))
camcf += camcf.LookVector * 4
camcf *= CFrame.Angles(
math.rad(sway.X / (25 / swaySensitivity)),
math.rad(sway.Y / (25 / swaySensitivity)),
0
)
self.model:PivotTo(camcf - camcf.LookVector * 4)
-- Third-person fallback
else
self.model.PrimaryPart = self.torsoPart
local cf = torso.CFrame + Vector3.new(0, 0.5, 0)
if char:FindFirstChildOfClass("Tool") and thirdpersonArms then
local x = select(1, cam.CFrame:ToOrientation())
cf *= CFrame.fromOrientation(x, 0, 0)
end
cf -= cf.UpVector * 0.5
self.model:PivotTo(cf)
end
end)
self.renderConn = RunService.RenderStepped:Connect(function(dt)
end)
end
-- disconnect and clean up
function ViewModel:Destroy()
if self.charConn then
self.charConn:Disconnect()
self.charConn = nil
end
if self.renderConn then
self.renderConn:Disconnect()
self.renderConn = nil
end
if self.model then
self.model:Destroy()
self.model = nil
end
if self.offset then
self.offset:Destroy()
self.offset = nil
end
if self.rot_offset then
self.rot_offset:Destroy()
self.rot_offset = nil
end
RunService:UnbindFromRenderStep("viewmodel")
self.TargetAimingVector = nil
end
return ViewModel
解决方案
我也不知道自己在做什么,但这可能能解决你的问题。基本上把整个 _onCharacter 函数替换为这个
function ViewModel:_onCharacter(char)
if self.renderConn then self.renderConn:Disconnect() end
local torso = char:WaitForChild("Torso")
local root = char:WaitForChild("HumanoidRootPart")
local leftShoulder = torso:WaitForChild("Left Shoulder")
local rightShoulder = torso:WaitForChild("Right Shoulder")
local leftArm = char:WaitForChild("Left Arm")
local rightArm = char:WaitForChild("Right Arm")
leftShoulder.Part0 = self.torsoPart
rightShoulder.Part0 = self.torsoPart
local bobbingVector = Vector3.zero
local mega = omega * math.pi / period
RunService:BindToRenderStep("viewmodel", Enum.RenderPriority.Camera.Value + 1, function(dt)
local cam = self.camera
local firstPerson = (cam.CFrame.Position - cam.Focus.Position).Magnitude < 0.75
local t = tick()
local currentVelocity = torso.AssemblyLinearVelocity.Magnitude
local speedmod = currentVelocity / 16 > 1.5 and 2 or 1
local Bobx = -math.cos(t * mega * speedmod)
local Boby = 1 - (Bobx * Bobx)
Bobx = -Bobx * amplitude * (currentVelocity / 16)
Boby = -Boby * amplitude * (currentVelocity / 16)
local ROTOFFSET = CFrame.identity
if UseOffset then
local relative = torso.CFrame:ToObjectSpace(root.CFrame)
local rotX, rotY, rotZ = relative:ToOrientation()
ROTOFFSET = CFrame.Angles(-rotX / offsetDiv, -rotY / offsetDiv, 0)
else
bobbingVector = bobbingVector:Lerp(Vector3.new(Bobx, Boby, 0), 0.2)
end
leftArm.LocalTransparencyModifier = 0
rightArm.LocalTransparencyModifier = 0
local md = uis:GetMouseDelta()
self.sway:shove(Vector3.new(md.Y, md.X))
local sway = self.sway:update(dt)
if not invertedSway then sway = -sway end
if firstPerson then
self.model.PrimaryPart = self.headPart
local camcf = cam.CFrame
camcf *= CFrame.new(self.offset.Value)
camcf *= CFrame.Angles(
math.rad(bobbingVector.Y * 15),
math.rad(bobbingVector.X * 15),
0
) * ROTOFFSET * CFrame.Angles(
math.rad(self.rot_offset.Value.X),
math.rad(self.rot_offset.Value.Y),
math.rad(self.rot_offset.Value.Z)
)
local finalSway = CFrame.Angles(
math.rad(sway.X / (25 / swaySensitivity)),
math.rad(sway.Y / (25 / swaySensitivity)),
0
)
self.model:PivotTo(camcf * finalSway)
else
self.model.PrimaryPart = self.torsoPart
local cf = torso.CFrame
if char:FindFirstChildOfClass("Tool") and thirdpersonArms then
local x = select(1, cam.CFrame:ToOrientation())
cf *= CFrame.fromOrientation(x, 0, 0)
end
self.model:PivotTo(cf)
end
end)
end
所以先从现在开始,我们改用 AssemblyLinearVelocity。主要是因为 Velocity 已被弃用。我还通过执行 CFrame.new(offset.Value) 来简化了CFrame的计算,代替 RightVector * Offset。另外,velocity 的lerp可能在快速转向或加速时导致你的手臂在躯干后方“漂移”,所以我把它去除了。这里还有一些其他的小改动,但不过是让你的代码多加了一点脑力的小改动。
希望这个系统对你的游戏要稳定得多 :]
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。