How to change Tool's CFrame to view model's arm?

Hello Developers :wave:

Context

I am creating a first person view model with 2 hands for a horror game I am working on.

Issue

Whenever the player holds a tool, the tool is displayed on the player’s actual arm, not the view model.

What I’ve tried

I tried to change the CFrame of the Handle of the tool and using weld constraints, just to find out that it doesn’t work.

Code

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local HRP = (Character:FindFirstChild("Head") :: BasePart)
local Camera = workspace.Camera
local RunService = game:GetService("RunService")

local ViewModel: Model = game.ReplicatedStorage.ViewModel:Clone()
ViewModel.Parent = Camera

Player.Character:WaitForChild("Body Colors"):Clone().Parent = ViewModel;
Player.Character:WaitForChild("Shirt"):Clone().Parent = ViewModel;
Player.Character:WaitForChild("Pants"):Clone().Parent = ViewModel;

local VMHumanoid = ViewModel:FindFirstChildWhichIsA("Humanoid");
local VMAnimator = VMHumanoid:FindFirstChild("Animator") :: Animator;
local VMAnimSaves = ViewModel:FindFirstChild("Animations") :: Model;

local VMBobble = VMAnimator:LoadAnimation(VMAnimSaves:WaitForChild("Bobble"));
local VMHold = VMAnimator:LoadAnimation(VMAnimSaves:WaitForChild("BobbleHoldItem"));
VMHold.Priority = Enum.AnimationPriority.Action4;

local VMRightArm = ViewModel:WaitForChild("Right Arm") :: BasePart;
local VMToolHandle = VMRightArm:WaitForChild("ToolHandle") :: BasePart;

local toolCheck = function(tool: Tool): ()
	local equipped: boolean = false;
	
	local weld: WeldConstraint = Instance.new("WeldConstraint");
	
	local handle = tool:WaitForChild("Handle") :: BasePart;
	
	tool.Equipped:Connect(function(): ()
		if not (VMHold.IsPlaying) then
			VMHold:Play();
			equipped = true;
		end;
	end);
	tool.Unequipped:Connect(function(): ()
		if (VMHold.IsPlaying) then
			VMHold:Stop();
			equipped = false;
		end;
	end);
end;

RunService.RenderStepped:Connect(function()
	if Player.Character.Humanoid.Health == 0 then
		if Camera:FindFirstChild("ViewModel") ~= nil then
			ViewModel:Destroy()
		end
	end
	
	if Camera:FindFirstChild("ViewModel") ~= nil then
		ViewModel:PivotTo(Camera.CFrame * CFrame.new(.025, -2, -.3) * CFrame.Angles(0.3, 0, 0))
	end
	
	if (Character:FindFirstChildWhichIsA("Humanoid").MoveDirection.Magnitude > 0) then
		if not (VMBobble.IsPlaying) then
			VMBobble:Play();
		end;
	else
		if (VMBobble.IsPlaying) then
			VMBobble:Stop();
		end;
	end;
	
	for i: number, v: Tool in ipairs(Player.Backpack:GetChildren()) do
		if v:IsA("Tool") then
			toolCheck(v);
		end;
	end;
end)

Thank you :smiley:

3 Likes

First of all, OMG I absolutely love how you formatted the topic, it’s simple, concise, clear and straight to the point, Roblox should make this the format of each topic imo

So, since you are using animation best thing to do here is use a Motor6D over a WeldConstraint (im not much experienced with WeldConstraints :frowning:)

local motor6D = Instance.new("Motor6D")
motor6D.Part0 = VMRightArm
motor6D.Part1 = tool.Handle
motor6D.Parent = VMRightArm

Also you are running the toolCheck func every frame which is unideal. Instead running it once in the outer scope and then every time a child is added to backpack using the Backpack.ChildAdded event

2 Likes

Hello there!
Firstly, thank you for responding :smiling_face:
Second of all, I forgot that I was in a renderStepped function, that’s why I didn’t realize I was running the loop in it :sob:
Thirdly, This is the right arm.
image

This happens when I equip the tool: (please ignore the bg sounds :sob:)

Updated toolCheck function:

1 Like

Am I doing anything wrong here??
I feel like something is off…

1 Like

SOLUTION

I figured it OUT!
So basically what I did was make clones of the tool’s handle and weld them to the Right Hand of the view model.
I wasn’t really sure why i couldn’t think of this solution, maybe I was a little too burnt out.

Works like a charm!

It’s looks normal through the server!

CODE (ignore all prefixes and suffixes)

local Player = game.Players.LocalPlayer
local Character = Player.Character or Player.CharacterAdded:Wait()
local HRP = (Character:FindFirstChild("Head") :: BasePart)
local Camera = workspace.Camera

local RunService = game:GetService("RunService")
local ReplicatedStorage = game:GetService("ReplicatedStorage");
local Tools = ReplicatedStorage:WaitForChild("Tools");

local ViewModel: Model = ReplicatedStorage:WaitForChild("ViewModel"):Clone();
ViewModel.Parent = Camera;

Player.Character:WaitForChild("Body Colors"):Clone().Parent = ViewModel;
Player.Character:WaitForChild("Shirt"):Clone().Parent = ViewModel;
Player.Character:WaitForChild("Pants"):Clone().Parent = ViewModel;

local VMHumanoid = ViewModel:FindFirstChildWhichIsA("Humanoid");
local VMAnimator = VMHumanoid:FindFirstChild("Animator") :: Animator;
local VMAnimSaves = ViewModel:FindFirstChild("Animations") :: Model;

local VMBobble = VMAnimator:LoadAnimation(VMAnimSaves:WaitForChild("Bobble"));
local VMHold = VMAnimator:LoadAnimation(VMAnimSaves:WaitForChild("BobbleHoldItem"));
VMHold.Priority = Enum.AnimationPriority.Action4;

local VMRightArm = ViewModel:WaitForChild("Right Arm") :: BasePart;
local VMToolHandle = VMRightArm:WaitForChild("ToolHandle") :: BasePart;

local SUFFIX = "_CLONE";
local PREFIX = "CHECK_DONE_";

local lArrow = "<-";
local rArrow = "->";

local toolCheck = function(tool: Tool): ()
	local equipped: boolean = false;
	
	tool.Equipped:Connect(function(): ()
		if not (VMHold.IsPlaying) then
			VMHold:Play();
			equipped = true;
			
			for i: number, v: Instance in ipairs(tool:GetDescendants()) do
				if v:IsA("BasePart") or v:IsA("MeshPart") or v:IsA("UnionOperation") then
					v.Transparency = 1;
				elseif v:IsA("PointLight") or v:IsA("SurfaceLight") then
					v.Brightness = 0;
				elseif v:IsA("ParticleEmitter") then
					v.Enabled = false;
				end;
			end;
			
			local cloneTool: BasePart = Tools:WaitForChild(tool.Name):Clone();
			cloneTool.Name = tool.Name..SUFFIX;
			cloneTool.Parent = VMToolHandle;
			local motor6d = Instance.new("Motor6D", VMToolHandle);
			motor6d.Name = lArrow..tool.Name..SUFFIX..rArrow;
			motor6d.Part0 = cloneTool;
			motor6d.Part1 = VMToolHandle;
		end;
	end);
	
	tool.Unequipped:Connect(function(): ()
		if (VMHold.IsPlaying) then
			VMHold:Stop();
			equipped = false;
			local clonedTool = VMToolHandle:WaitForChild(tool.Name..SUFFIX);
			clonedTool:Destroy();
			local motor6d = VMToolHandle:WaitForChild(lArrow..tool.Name..SUFFIX..rArrow);
			motor6d:Destroy();
		end;
	end);
	
	return PREFIX..tool.Name;
end;

RunService.RenderStepped:Connect(function()
	if (Player.Character.Humanoid.Health == 0) then
		if (Camera:FindFirstChild("ViewModel")) then
			ViewModel:Destroy()
		end
	end
	
	if Camera:FindFirstChild("ViewModel") ~= nil then
		ViewModel:PivotTo(Camera.CFrame * CFrame.new(.025, -2, -.3) * CFrame.Angles(0.3, 0, 0))
	end
	
	if (Character:FindFirstChildWhichIsA("Humanoid").MoveDirection.Magnitude > 0) then
		if not (VMBobble.IsPlaying) then
			VMBobble:Play();
		end;
	else
		if (VMBobble.IsPlaying) then
			VMBobble:Stop();
		end;
	end;
end)

Player.Backpack.ChildAdded:Connect(function(child: Instance)
	if child:IsA("Tool") then
		local test = toolCheck(child);
	end;
end);

for i: number, v: Tool in ipairs(Player.Backpack:GetChildren()) do
	if (v:IsA("Tool")) then
		local test = toolCheck(v);
	end;
end;

Obviously this code was written to satisfy the “Candle” tool (for tests).
You can modify this however you want!
Again, thank you so much for reading, and the ones who helped me!
Thank you :smiling_face:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.