I recently tried creating the effect of the Viewmodel arms moving back to avoid clipping into the wall. It almost works fine but the arms sort of flicker when close to a wall. I know this is because the code uses the arm and gun muzzle’s position to calculate the arm length and distance from a wall and then modifies the arm’s position, which in turn changes the distance, causing a loop. Is there a way of doing this without causing the loop?
Code:
game:GetService("RunService"):BindToRenderStep("MoveArms", Enum.RenderPriority.Character.Value, function()
--Creates Cframe which the Position of the VM arm's Position looking in the same direction as the muzzle
local armPos = CFrame.lookAlong(vm.RightUpperArm.RightShoulderAttachment.WorldCFrame.Position, script.Parent.Handle.MuzzleExit.WorldCFrame.LookVector)
--Creates Cframe which the local offset between the arm and muzzle
local offset = armPos:ToObjectSpace(script.Parent.Handle.MuzzleExit.WorldCFrame)
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {vm, script.Parent.Parent}
--casts a ray from the arm to get the distance from a wall
local ray2 = workspace:Raycast((armPos * CFrame.new(offset.X, 0, 0)).Position, script.Parent.Handle.MuzzleExit.WorldCFrame.LookVector.Unit * 10, params)
if ray2 then
--Distance between the wall and gun muzzle
local diff = ray2.Distance + offset.Z
--if the difference is negative it means the muzzle is inside the wall
---moves arms back the same distance to move arms out of wall
if diff < 0 then
print(diff)
local rightCO = vm.RightUpperArm.RightShoulder
local leftCO = vm.LeftUpperArm.LeftShoulder
leftCO.C0 = CFrame.new(leftCO.C0.X, leftCO.C0.Y, 0.0019 - diff) * leftCO.C0.Rotation
rightCO.C0 = CFrame.new(rightCO.C0.X, rightCO.C0.Y, 0.0019 - diff) * rightCO.C0.Rotation
end
end
end)
To solve this issue in the script, you would either have to add the old difference to the Raycast or subtract the old difference when calculating the new difference. I also noticed that the arms wouldn’t change position if there was no ray intersection, so I added a little check at the end to fix this issue. I hope I wasn’t too late with the solution.
local diff = 0
local rightCO = vm.RightUpperArm.RightShoulder
local leftCO = vm.LeftUpperArm.LeftShoulder
local function ChangeArmsC0(Difference)
leftCO.C0 = CFrame.new(leftCO.C0.X, leftCO.C0.Y, 0.0019 - Difference) * leftCO.C0.Rotation
rightCO.C0 = CFrame.new(rightCO.C0.X, rightCO.C0.Y, 0.0019 - Difference) * rightCO.C0.Rotation
end
game:GetService("RunService"):BindToRenderStep("MoveArms", Enum.RenderPriority.Character.Value, function()
--Creates Cframe which the Position of the VM arm's Position looking in the same direction as the muzzle
local armPos = CFrame.lookAlong(vm.RightUpperArm.RightShoulderAttachment.WorldCFrame.Position, script.Parent.Handle.MuzzleExit.WorldCFrame.LookVector)
--Creates Cframe which the local offset between the arm and muzzle
local offset = armPos:ToObjectSpace(script.Parent.Handle.MuzzleExit.WorldCFrame)
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {vm, script.Parent.Parent}
--casts a ray from the arm to get the distance from a wall
local ray2 = workspace:Raycast((armPos * CFrame.new(offset.X, 0, 0)).Position, script.Parent.Handle.MuzzleExit.WorldCFrame.LookVector.Unit * 10, params)
if ray2 then
-- We add this offset to avoid the looping that occurs
local ArmZOffset = if diff < 0 then diff else 0
--Distance between the wall and gun muzzle
diff = ray2.Distance + ArmZOffset + offset.Z
--if the difference is negative it means the muzzle is inside the wall
---moves arms back the same distance to move arms out of wall
if diff < 0 then
print(diff)
ChangeArmsC0(diff)
end
elseif diff ~= 0 then
diff = 0
ChangeArmsC0(0)
end
end)
i dont even work on the project no more, and also i did end up figuring it out using what you said. I used the rig attachments for the right shoulder and the gun muzzle to get the normal arm length, then shot a cast from that same shoulder position and subtracting it from the normal to get the difference and working from there. Thanks for the help tho ill mark it as a solution since it does fix it.
So real, i have so many very specific posts for actual hard problems that have no replies at all. luckily for most of them i do end up figuring it out myself after a couple of days to a couple of weeks down the line and marking them as a solution incase some poor soul also runs into it.