So I’ve made a viewmodel recently, works fine and dandy!
Problem is, I just can’t figure out a way to actually make the real arms follow the viewmodel arms.
I want to do this because I want the gun to actually follow the viewmodel.
I have tried to do this by copying the internal Motor6D CFrame (.Transform) of the viewmodel arms to the real arms.
connections[2] = RNS.RenderStepped:Connect(function()
if viewmodel then
torso["Right Shoulder"].Transform = modelTorso["Right Shoulder"].Transform
torso["Left Shoulder"].Transform = modelTorso["Left Shoulder"].Transform
viewmodel:SetPrimaryPartCFrame(camera.CFrame)
end
end)
I tried it and it didn’t work. I believe it’s because the arms technically aren’t actually moving up and down, but it looks like it because I am rotating the entire model to follow the camera.
How can I fix this? Any help would be appreciated.
Here’s my entire script:
local RNS = game:GetService("RunService")
local RS = game:GetService("ReplicatedStorage")
local PS = game:GetService("Players")
local PYS = game:GetService("PhysicsService")
local camera = workspace.CurrentCamera
local char: Model = script:FindFirstAncestorWhichIsA("Model") do
char.Archivable = true
end
local viewmodelCollision: string = "ViewmodelCollision"
local player: Player = PS:GetPlayerFromCharacter(char)
local hum: Humanoid = char:WaitForChild("Humanoid")
local torso = char:WaitForChild("Torso")
local animator: Animator = hum:WaitForChild("Animator")
local modelHum: Humanoid = nil
local modelAnimator: Animator = nil
local modelTorso: BasePart = nil
local connections = {}
local viewmodel = nil
local loaded = {}
local function SetCollsionGroup(base: any, group: string)
for _,v: BasePart in ipairs(base:GetDescendants()) do
if v:IsA("BasePart") then
PYS:SetPartCollisionGroup(v, group)
end
end
end
connections[1] = player.CharacterAppearanceLoaded:Connect(function()
viewmodel = RS.Viewmodel:Clone() do
viewmodel.Parent = camera
viewmodel.Name = "Viewmodel"
viewmodel.PrimaryPart = viewmodel:WaitForChild("Head")
modelTorso = viewmodel:WaitForChild("Torso")
modelHum = viewmodel:WaitForChild("Humanoid")
modelAnimator = modelHum:WaitForChild("Animator")
local blacklist = {"left leg", "right leg"}
for _,v in ipairs(char:GetDescendants()) do
if v:IsA("Shirt") or v:IsA("Pants") or v:IsA("BodyColors") then
local clone = v:Clone() do
clone.Parent = viewmodel
end
end
end
SetCollsionGroup(viewmodel, viewmodelCollision)
char.Archivable = false
connections[1]:Disconnect()
end
end)
connections[2] = RNS.RenderStepped:Connect(function()
if viewmodel then
torso["Right Shoulder"].Transform = modelTorso["Right Shoulder"].Transform
torso["Left Shoulder"].Transform = modelTorso["Left Shoulder"].Transform
viewmodel:SetPrimaryPartCFrame(camera.CFrame)
end
end)
connections[3] = animator.AnimationPlayed:Connect(function(track)
if loaded[track] or not modelHum or not modelAnimator then
return
end
loaded[track] = modelAnimator:LoadAnimation(track.Animation)
loaded[track]:Play()
track.Stopped:Connect(function()
loaded[track]:Stop()
loaded[track] = nil
end)
end)
Try applying the viewmodel’s X rotation to the C0 of the shoulder joints in addition to copying the Transforms. This should work since you will be modifying the joints’ base rotation.
-- Store the original C0
local rightShoulderC0 = torso["Right Shoulder"].C0
local leftShoulderC0 = torso["Left Shoulder"].C0
-- Run this every frame in RenderStepped
local x, y, z = viewmodel.PrimaryPart.CFrame:ToOrientation()
torso["Right Shoulder"].C0 = rightShoulderC0 * CFrame.fromOrientation(x, 0, 0)
torso["Left Shoulder"].C0 = leftShoulderC0 * CFrame.fromOrientation(x, 0, 0)
-- Apply viewmodel arms transforms
local RNS = game:GetService("RunService")
local RS = game:GetService("ReplicatedStorage")
local PS = game:GetService("Players")
local PYS = game:GetService("PhysicsService")
local camera = workspace.CurrentCamera
local char: Model = script:FindFirstAncestorWhichIsA("Model") do
char.Archivable = true
end
local viewmodelCollision: string = "ViewmodelCollision"
local player: Player = PS:GetPlayerFromCharacter(char)
local hum: Humanoid = char:WaitForChild("Humanoid")
local torso = char:WaitForChild("Torso")
local animator: Animator = hum:WaitForChild("Animator")
local modelHum: Humanoid = nil
local modelAnimator: Animator = nil
local modelTorso: BasePart = nil
local rightShoulderC0 = torso["Right Shoulder"].C0
local leftShoulderC0 = torso["Left Shoulder"].C0
local connections = {}
local viewmodel = nil
local loaded = {}
local function SetCollsionGroup(base: any, group: string)
for _,v: BasePart in ipairs(base:GetDescendants()) do
if v:IsA("BasePart") then
PYS:SetPartCollisionGroup(v, group)
end
end
end
connections[1] = player.CharacterAppearanceLoaded:Connect(function()
viewmodel = RS.Viewmodel:Clone() do
viewmodel.Parent = camera
viewmodel.Name = "Viewmodel"
viewmodel.PrimaryPart = viewmodel:WaitForChild("Head")
modelTorso = viewmodel:WaitForChild("Torso")
modelHum = viewmodel:WaitForChild("Humanoid")
modelAnimator = modelHum:WaitForChild("Animator")
local blacklist = {"left leg", "right leg"}
for _,v in ipairs(char:GetDescendants()) do
if v:IsA("Shirt") or v:IsA("Pants") or v:IsA("BodyColors") then
local clone = v:Clone() do
clone.Parent = viewmodel
end
end
end
SetCollsionGroup(viewmodel, viewmodelCollision)
char.Archivable = false
connections[1]:Disconnect()
end
end)
connections[2] = RNS.RenderStepped:Connect(function()
if viewmodel then
local x, y, z = viewmodel.PrimaryPart.CFrame:ToOrientation()
torso["Right Shoulder"].C0 = rightShoulderC0 * CFrame.fromOrientation(x, 0, 0)
torso["Left Shoulder"].C0 = leftShoulderC0 * CFrame.fromOrientation(x, 0, 0)
torso["Right Shoulder"].Transform = modelTorso["Right Shoulder"].Transform
torso["Left Shoulder"].Transform = modelTorso["Left Shoulder"].Transform
viewmodel:SetPrimaryPartCFrame(camera.CFrame)
end
end)
connections[3] = animator.AnimationPlayed:Connect(function(track)
if loaded[track] or not modelHum or not modelAnimator then
return
end
loaded[track] = modelAnimator:LoadAnimation(track.Animation)
loaded[track]:Play()
track.Stopped:Connect(function()
loaded[track]:Stop()
loaded[track] = nil
end)
end)
--connections[4] = char.DescendantAdded:Connect(function(obj)
-- if obj:IsA("Weld") and obj.Name == "RightGrip" and viewmodel then
-- task.wait()
-- for _,v in ipairs(viewmodel:GetChildren()) do
-- if v:IsA("Tool") or v:IsA("Weld") and v.Name == "RightGrip" then
-- v:Destroy()
-- end
-- end
-- local weld = obj:Clone() do
-- weld.Parent = viewmodel
-- end
-- local tool = obj.Part1.Parent:Clone() do
-- tool.Parent = viewmodel
-- weld.Part0 = viewmodel[obj.Part0.Name]
-- weld.Part1 = tool.Handle
-- end
-- for _,v in ipairs(obj.Part1.Parent:GetChildren()) do
-- if v:IsA("BasePart") then
-- v.LocalTransparencyModifier = 1
-- end
-- end
-- end
--end)
the only simple though time taking solution you can apply is to make an axe for the viewmodel as well, using C0s require unnecessary and massive mathematical efforts if you are simply going for that route
so if you want this problem to be fixed then you might need to redo the entire script because the way how im gonna explain will require a viewmodel and just the tool i suppose
and thats it
you can do anything else with the viewmodel like animate
and the cat model you can just add the tool and add it to the arms or something dunno how you want it
same with sway or animation you can script it anyway how you want it
if you dont have a handle for the tool or this doesnt work then just turn off RequiresHandle for the tool
I managed to find a solution by following a different method from a youtube video. It works well!
local RNS = game:GetService("RunService")
local RS = game:GetService("ReplicatedStorage")
local PS = game:GetService("Players")
local PYS = game:GetService("PhysicsService")
local camera = workspace.CurrentCamera
local viewmodelCollision: string = "ViewmodelCollision"
local char = script.Parent
local player = PS:GetPlayerFromCharacter(char)
local torso = char:WaitForChild("Torso")
local head = char:WaitForChild("Head")
local hum = char:WaitForChild("Humanoid")
local rShoulder, lShoulder = torso:WaitForChild("Left Shoulder"), torso:WaitForChild("Right Shoulder")
local viewmodelChar = RS.Viewmodel:Clone() do
viewmodelChar.Parent = camera
viewmodelChar.Name = "Viewmodel"
end
local viewmodelTorso = viewmodelChar:WaitForChild("Torso")
local con = {}
local function IsPlayerFirstPerson(): boolean
local distance: number = (camera.CFrame.Position - head.Position).Magnitude
return distance < 1
end
local function ReplicateAnimationToViewmodel()
for _,v: Motor6D in ipairs(viewmodelChar:GetDescendants()) do
if v:IsA("Motor6D") then
v.Transform = char:FindFirstChild(v.Name, true).Transform
end
end
end
local function SetTransparency(base: any, num: number)
local blacklist = {"Torso", "HumanoidRootPart"}
for _,v: BasePart in ipairs(base:GetDescendants()) do
if v:IsA("BasePart") and not table.find(blacklist, v.Name) then
v.LocalTransparencyModifier = num
end
end
end
local function SetCollsionGroup(base: any, group: string)
for _,v: BasePart in ipairs(base:GetDescendants()) do
if v:IsA("BasePart") then
PYS:SetPartCollisionGroup(v, group)
end
end
end
con[1] = player.CharacterAppearanceLoaded:Connect(function()
if viewmodelChar then
local blacklist = {"left leg", "right leg"}
for _,v in ipairs(char:GetDescendants()) do
if v:IsA("Shirt") or v:IsA("Pants") or v:IsA("BodyColors") then
local clone = v:Clone() do
clone.Parent = viewmodelChar
end
end
end
SetCollsionGroup(viewmodelChar, viewmodelCollision)
con[1]:Disconnect()
end
end)
con[2] = RNS.RenderStepped:Connect(function()
viewmodelChar:SetPrimaryPartCFrame(camera.CFrame)
if IsPlayerFirstPerson() then
SetTransparency(viewmodelChar, 0)
rShoulder.Part0 = viewmodelTorso
lShoulder.Part0 = viewmodelTorso
else
SetTransparency(viewmodelChar, 1)
rShoulder.Part0 = torso
lShoulder.Part0 = torso
end
ReplicateAnimationToViewmodel()
end)
con[3] = hum.Died:Connect(function()
for _,v: RBXScriptConnection in ipairs(con) do
v:Disconnect()
end
end)