Tool viewmodel doesn't collide with enemies and resources

I am currently building a survival game with tools to break resources and to fight enemies. I wanted the game to be in first person so I have viewmodel system in place to make it look better. However, when I use the viewmodel, the tools seem to not be able to break resources but still work fine. I want tools to be able to detect collision with resources and be able to break them. I have a feeling that the collision doesn’t work because the viewmodel is affecting character’s actual arms and is only client side. Does anyone know why my current system isn’t working and any possible solutions?

Currently my tools (axe, pickaxe, sword) use the .touched function to detect touching.
Resources use the humanoid object to keep track of health.
My viewmodel is only client based and still uses the character arms. It comes from this video:
View Model Part 2 (there is also a part 1 which explains how it works)

-video showing why it doesn’t work-

-Tool code-

-- local tool = script.Parent
local handle = tool.Handle
local hitbox = tool.HitBox
local ProxPrompt = hitbox.ToolPickup
local settingsfolder = tool.Settings

local damageVal = settingsfolder.Damage
local cooldownVal = settingsfolder.Cooldown

local db = false
local canhit = false

local function swingFunc()
	
	if not db then

		db = true
		canhit = true

		local Anim = Instance.new("StringValue")
		Anim.Name = "toolanim"
		Anim.Value = "Slash"
		Anim.Parent = tool

		task.wait(0.5)

		canhit = false

		task.wait(cooldownVal.Value)

		Anim:Destroy()

		db = false
		canhit = false
	end
	
end

local function EnemyHitFunc(hitpart)

	if canhit and hitpart.parent ~= tool.Parent then

		if hitpart.parent ~= tool.Parent and hitpart.parent:FindFirstChild("Humanoid") and hitpart.parent:FindFirstChild("EnemyTag") then
			local humanoid = hitpart.parent:FindFirstChild("Humanoid")
			humanoid.Health -= damageVal.Value
			canhit = false
		end

	end

end

local function TreeHitFunc(hitpart)

	if canhit and hitpart.parent ~= tool.Parent then

		if hitpart.parent ~= tool.Parent and hitpart.parent:FindFirstChild("Humanoid") and hitpart.parent:FindFirstChild("TreeTag") then
			local humanoid = hitpart.parent:FindFirstChild("Humanoid")
			humanoid.Health -= damageVal.Value
			canhit = false
		end

	end

end

local function RockHitFunc(hitpart)

	if canhit and hitpart.parent ~= tool.Parent then

		if hitpart.parent ~= tool.Parent and hitpart.parent:FindFirstChild("Humanoid") and hitpart.parent:FindFirstChild("RockTag") then
			canhit = false
			local humanoid = hitpart.parent:FindFirstChild("Humanoid")
			humanoid.Health -= damageVal.Value
		end

	end

end

tool.Activated:Connect(swingFunc)
hitbox.Touched:Connect(EnemyHitFunc)
hitbox.Touched:Connect(TreeHitFunc)
--hitbox.Touched:Connect(RockHitFunc)

while task.wait() do
	if tool.Parent:FindFirstChild("Humanoid") then
		hitbox.CanCollide = false
		ProxPrompt.Enabled = false
	else
		hitbox.CanCollide = true
		ProxPrompt.Enabled = true
	end
end

-Viewmodel code-

-- local runMult = 10
local walkMult = 4
local swaySpeed = .1 -- 0 is fast 1 is slow
local returnSpeed = .1-- 0 is fast 1 is slow
local smoothingMult = 1-- 0 is fast 1 is slow
-----------------
local OFFSET = 0 -- the forward offset
local X = 0 -- the forward offset
local Y = 0 -- the forward offset

local runService = game:GetService("RunService")
local character = script.Parent
local VM = game.ReplicatedStorage.Viewmodel:Clone()
VM.Parent = workspace.CurrentCamera
local leftShoulder = character.Torso["Left Shoulder"]
local rightShoulder = character.Torso["Right Shoulder"]
local sine = 0
function getCFrame(cframe)
	local sx, sy, sz, m00, m01, m02, m10, m11, m12, m20, m21, m22 = cframe:GetComponents()

	local X = math.atan2(-m12, m22)

	local Y = math.asin(m02)

	local Z = math.atan2(-m01, m00)
	return X,Y,Z
end
runService.RenderStepped:Connect(function(deltatime)
	--character:FindFirstChild("Right Arm").LocalTransparencyModifier = 0
	OFFSET = script.OFFSET.Value
	X = script.X.Value
	Y = script.Y.Value
	--character:FindFirstChild("Left Arm").LocalTransparencyModifier = 0
	
	
	local pcframe = workspace.CurrentCamera.CFrame + workspace.CurrentCamera.CFrame.LookVector * OFFSET + workspace.CurrentCamera.CFrame.RightVector * X + workspace.CurrentCamera.CFrame.UpVector * Y
	
	local lerpedRot = VM.PrimaryPart.CFrame:lerp(pcframe,smoothingMult)
	local _,_,_,m11,m12,m13,m21,m22,m23,m31,m32,m33 = lerpedRot:components();
	local ogPos = pcframe.p;
	local newCf = CFrame.new(ogPos.x,ogPos.y,ogPos.z,m11,m12,m13,m21,m22,m23,m31,m32,m33)

	VM.PrimaryPart.CFrame = newCf;
	
	
	
	local dist = (workspace.CurrentCamera.CFrame.Position - character.Head.Position).Magnitude
	if dist < 1 then
		rightShoulder.Part0 = VM.Torso
		leftShoulder.Part0 = VM.Torso
	else
		rightShoulder.Part0 = character.Torso
		leftShoulder.Part0 = character.Torso
	end
end)
local val = 0
local moving = false
while task.wait() do
	sine = math.sin(val)
	if character.Humanoid.MoveDirection ~= Vector3.new(0,0,0) then
		
		val  += .08
		game.TweenService:Create(script.X, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = sine/runMult}):Play()
		if sine < 0 then
			game.TweenService:Create(script.Y, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = -sine/runMult}):Play()
		else
			game.TweenService:Create(script.Y, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = sine/runMult}):Play()
		end
		
		--[[
		if character.Sprint.Sprinting.Value == false then
			val  += .1
			game.TweenService:Create(script.X, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = sine/runMult}):Play()
			if sine < 0 then
				game.TweenService:Create(script.Y, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = -sine/runMult}):Play()
			else
				game.TweenService:Create(script.Y, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = sine/runMult}):Play()
			end
		else
			val  += .2
			game.TweenService:Create(script.X, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = sine/walkMult}):Play()
			if sine < 0 then
				game.TweenService:Create(script.Y, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = -sine/walkMult}):Play()
			else
				game.TweenService:Create(script.Y, TweenInfo.new(swaySpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = sine/walkMult}):Play()
			end
		end
		]]
	else
		game.TweenService:Create(script.Y, TweenInfo.new(returnSpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = 0}):Play()
		game.TweenService:Create(script.X, TweenInfo.new(returnSpeed,Enum.EasingStyle.Linear,Enum.EasingDirection.Out), {Value = 0}):Play()
	end

end

-tree object in game-
tree
-tool object in game-
tool

If you you need more information let me know.

Probably because you are using .Touched, assuming the viewmodel is anchored it will only detect unanchored objects like enemy players and not anchored ones like rocks.

I would suggest a different hit detection method like raycasts or spatial queries for this.

2 Likes

the viewmodel is anchored, as well as the tree. I’ll try another detection method and see if it works.

Edit:
It does work, I have implemented a detection system using :GetPartsInPart()

local function hitObject()
	
	local partinpartparams = OverlapParams.new()

	partinpartparams.FilterType = Enum.RaycastFilterType.Exclude
	partinpartparams.FilterDescendantsInstances = {tool.Parent}

	local touchinghitbox = game.Workspace:GetPartsInPart(hitbox,partinpartparams)
	--[[
	if touchinghitbox then
		print("touch!")
	end
	]]
	for Index, part in pairs(touchinghitbox) do
		if canhit and part.Parent:FindFirstChild("Humanoid")  then
			local humanoid = part.parent:FindFirstChild("Humanoid")
			humanoid.Health -= damageVal.Value
			canhit = false
		end
	end
	
end

note: I call this function in a while loop

1 Like

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