Prevent decal from clipping off part?

Hey guys! I have an issue with my gunshot wound system currently where wounds are clipping off of parts. I currently have the following code to align the wound with the limb it hit:

function CreateGunshotWound(Result)
	
	local Wound = game.ReplicatedStorage.Objects.GunshotWound:Clone()
	
	Wound.Parent = Result.Instance

	local hitPosition = Result.Position
	local hitNormal = Result.Normal

	Wound:PivotTo(CFrame.new(hitPosition, hitPosition + hitNormal) * CFrame.fromEulerAnglesXYZ(0,0,math.rad(math.random(-180,180))))

	local Weld = Instance.new("WeldConstraint")
	
	Weld.Part0 = Wound.EntryWound
	Weld.Part1 = Result.Instance
	Weld.Parent = Wound.EntryWound
	
	Wound.EntryWound.Attachment.Blood:Emit(100)
	Wound.Limb.Value = Result.Instance
	Wound.Bleed.Enabled = true
end

image

However, as you can see, the gunshot wounds can clip off the part, which I do not want. I’ve already tried running this through with ChatGPT and it gave me nothing but hallucinations. I know what I need to do with the code but I don’t quite know how to do the math. Does anyone know how I could achieve this?

I have added an offset variable which is calculated based on the part size and the hitnormal.

function CreateGunshotWound(Result)
	local Wound = game.ReplicatedStorage.Objects.GunshotWound:Clone()
	Wound.Parent = Result.Instance

	local hitPosition = Result.Position
	local hitNormal = Result.Normal

	local offset = hitNormal * (Result.Instance.Size / 2 - Vector3.new(0.1, 0.1, 0.1)) -- The offset
	local WoundPos = hitPosition + offset

	Wound:PivotTo(CFrame.new(WoundPos, WoundPos + hitNormal) * CFrame.fromEulerAnglesXYZ(0, 0, math.rad(math.random(-180, 180))))

	local Weld = Instance.new("WeldConstraint")
	Weld.Part0 = Wound.EntryWound
	Weld.Part1 = Result.Instance
	Weld.Parent = Wound.EntryWound

	Wound.EntryWound.Attachment.Blood:Emit(100)
	Wound.Limb.Value = Result.Instance
	Wound.Bleed.Enabled = true
end

Uhhh not quite. That just got this:

image

Hey, I’m french so I’m having a hard time expressing myself and the solution I had but here
check if the wound decal’s size exceeds the surface boundaries of the part it hit

	local woundSize = Wound.EntryWound.Size
	
	-- Calculate wound bounds on the surface of the part
	local woundRadius = woundSize.X / 2 -- Assuming X and Y are the same for simplicity

	local partSurfaceSize = Vector3.new(partSize.X, partSize.Y, 0)
	
	local projectedHitPosition = hitPosition + hitNormal * woundRadius
	
	if math.abs(projectedHitPosition.X) + woundRadius > partSurfaceSize.X / 2 or 
	   math.abs(projectedHitPosition.Y) + woundRadius > partSurfaceSize.Y / 2 then
		-- Reposition wound slightly inward to prevent clipping
		local inwardOffset = Vector3.new(math.sign(projectedHitPosition.X) * woundRadius / 2, math.sign(projectedHitPosition.Y) * woundRadius / 2, 0)
		hitPosition = hitPosition - inwardOffset
	end

(I gave ChatGPT my solution and it did the code for me)

Guys I appreciate it but ChatGPT is kind of slow so if anyone knows how to do this WITHOUT ChatGPT it would be appreciated. Also thank you for this code but it does not work.