Alternative to TouchEvent (Raycast)?

Hello! Basically, I have a script that’s inside the character when they join, however, it uses a TouchEvent, basically detecting if one of the body parts is hit, it does a function.

My Question

  1. Is there a better way to basically check if a player’s body part is hit than the code below?
  2. I’m using a RayCast module for my weapons, how would I apply it to the code below in terms of constantly checking if a body part gets hit? (I’m using RaycastHitboxV3)
for i, x in pairs(character:GetChildren()) do
	if x:IsA("BasePart") or x:IsA("MeshPart") then
		x.Touched:Connect(function(hit)

			if hit:FindFirstChild("IsASword") and hit:FindFirstChild("IsSwinging").Value == true and cooldown == false then
				cooldown = true

				--//Now we check if are hitting the player's back
				if character:FindFirstChild("Block") and character:FindFirstChild("Block"):IsA("Animation") then
					local maxHitAngle = 45
					local isFacingBack = false
					local humnCF= character.HumanoidRootPart.CFrame
					local left = (humnCF*CFrame.Angles(0, math.rad(maxHitAngle ), 0)) * CFrame.new(0, 0, -0.1)
					local right = (humnCF*CFrame.Angles(0, math.rad(-maxHitAngle ), 0)) * CFrame.new(0, 0, -0.1)
					local fartherLeft = (humnCF*CFrame.Angles(0, math.rad(maxHitAngle + 0.1), 0)) * CFrame.new(0, 0, -0.1)
					local fartherRight = (humnCF*CFrame.Angles(0, math.rad(-maxHitAngle - 0.1), 0)) * CFrame.new(0, 0, -0.1)

					local headPos = hit.Parent.Head.Position
					local isInsideAngle = (headPos - left.p).Magnitude < (headPos - fartherLeft.p).Magnitude and (headPos - right.p).Magnitude < (headPos - fartherRight.p).Magnitude 

					if isInsideAngle then -- the angle might be negative instead of positive depending on what you want, so just put "not isInsideAngle" if you need it reversed
						isFacingBack = false
					else
						isFacingBack = true
					end




					local isBlocking = false

					for i, sword in pairs(character:GetChildren()) do
						if sword:FindFirstChild("IsASword") then
							if sword:FindFirstChild("IsBlocking").Value == true then
								isBlocking = true
							end
						end
					end

					if isBlocking == true and isFacingBack == false then
						Blocked(character)
					else
						cooldown = false
					end

				else -- Not in guarding state

					DamagedEnemyHit(character)
				end
			else
				-- No attacking happening
			end
		end)
	end
end

Perhaps with spatial queries?

You could use :GetPartsInPart (more accurate but more expensive) or :GetPartBoundsInBox (for simple brick-like hitboxes)

:GetPartsInPart

local lp = game:GetService('Players').LocalPlayer
local char = workspace:WaitForChild(lp.Name)

local param = OverlapParams.new()
param.FilterDescendantsInstances = {char}
param.FilterType = Enum.RaycastFilterType.Blacklist
param.MaxParts = 1

local parts = {}
for _, v in ipairs(char:GetChildren()) do
	if v:IsA('MeshPart') then
		table.insert(parts, v)
		print(v)
	end
end

while char do
	for _, v in ipairs(parts) do
		char:SetAttribute(v.Name, #workspace:GetPartsInPart(v, param) > 0)
	end
	task.wait()
end
:GetPartBoundsInBox (extended hitbox)

local lp = game:GetService('Players').LocalPlayer
local char = workspace:WaitForChild(lp.Name)

local param = OverlapParams.new()
param.FilterDescendantsInstances = {char}
param.FilterType = Enum.RaycastFilterType.Blacklist
param.MaxParts = 1

local parts = {}
for _, v in ipairs(char:GetChildren()) do
	if v:IsA('MeshPart') then
		table.insert(parts, v)
		print(v)
	end
end

local extension = Vector3.new(.1, .1, .1)

while char do
	for _, v in ipairs(parts) do
		char:SetAttribute(v.Name, #workspace:GetPartBoundsInBox(v.CFrame, v.Size + extension, param) > 0)
	end
	task.wait()
end

Here’s a demo of the :GetPartBoundsInBox method that you can try yourself:
touchedAlternative.rbxl (34.8 KB)

2 Likes
	local Part = workspace.Part
	
	RunService.Heartbeat:Connect(function()
		local PartRegionMin = Vector3.new(Part.Position.X-Part.Size.X/2, Part.Position.Y-Part.Size.Y/2, Part.Position.Z-Part.Size.Z/2)
		local PartRegionMax = Vector3.new(Part.Position.X+Part.Size.X/2, Part.Position.Y+Part.Size.Y/2, Part.Position.Z+Part.Size.Z/2)
		local CreatedRegion = Region3.new(PartRegionMin, PartRegionMax)
		local PartsInRegion = workspace:FindPartsInRegion3WithWhiteList(CreatedRegion, {Put ignore list}, 25)

		for IndexPart, PartInRegion in pairs(PartsInRegion) do
			...
		end
	end)

I very often use regions instead of touch

Other way around, GetPartsInPart is the more accurate, more expensive one :slight_smile:

1 Like

Edit: forgot that character limbs aren’t perfect 6-faced bricks