Checking the back of a part

I want to be able to check if something hits a player in the back so I have to rely on the humanoidrootpart which in terms is just a regular part. how can I check to see if a part hits the back of the humanoidrootpart?

Have you tried creating a new part and welding it to the back of the HumanoidRootPart? Then use that newpart as the hit register.

2 Likes

I could do that, but I doubt it would be a reliable method. Yes I have thought of that, I just want to know if there’s any alternatives?

as far as I know you can’t do anything that is more reliable and simple than an easy .Touched function (that is if the part is not a projectile, if you know the part is coming you could probably make use of rays but I’d personally use .Touched anyways)

local character = script.Parent
local humanoidRootPart = character.HumanoidRootPart
local rootSize = humanoidRootPart.Size
local rootx, rooty, rootz = rootSize.x, rootSize.y, rootSize.z


function BackTouched(part) -- touched function, edit it to your needs
	if not (part.Parent == character) and not (part.Name == "Baseplate") then
		part.BrickColor = BrickColor.Random()
	end
end

function CreateBack()
	
	local back = Instance.new("Part") -- back part that we will edit and position
		back.Size = Vector3.new(rootx, rooty*1.5, rootz/2)
		back.CFrame = humanoidRootPart.CFrame * CFrame.new(0, 0, rootz/2)
		back.Massless = true
		back.CanCollide = false
		back.Parent = character

	local weld = Instance.new("WeldConstraint") -- welds back to humanoidrootpart
		weld.Part0 = back
		weld.Part1 = humanoidRootPart
		weld.Parent = back
		
	back.Touched:Connect(BackTouched) -- connects touched function
	
end

CreateBack()

this is a script inside of StarterCharacterScripts, so everytime the Player’s character is spawned it will create a new back, and everytime the character despawns it will be destroyed with the character

this is just what @RVVZ but I made their idea into an example

1 Like

Maybe what you could do instead is use ray tracings, with a ray that starts at the humanoidrootpart, and goes in the opposite direction of the humanoidrootpart.
And we will check if the .magnitude (length) of the part’s positon that was traced is like super small which would mean that it’s hitting the humanoidrotpart

I think what I would do is use a .Touched event like said before, and taking the dot product of the unit distance from the touched part and the hrp’s look vector, seeing if the angle produced is less than 0 or some limit:

local maxAngle = math.rad(110) -- in degrees

HRP.Touched:Connect(hit)
    local dot = HRP.CFrame.LookVector:Dot((hit.Position - HRP.Position).Unit)
    if math.acos(dot) > maxAngle then
        print("back was touched!")
    end
end)

The dot product between two vectors a and b is equivalent to cos(theta) * a.Magnitude * b.Magnitude. Since a and b are unit vectors in this block, we are left with cos(theta), which is what math.acos reverts.

A more tangible way of doing it is transforming the touched part’s position along the hrp’s CFrame and checking if the touched part’s Z coordinate is behind the part:

HRP.Touched:Connect(function(hit)
    local point = HRP.CFrame:Inverse() * hit.Position
    if point.Z < -0.5 --[[and math.abs(point.X) < 2]] then
        print("back was touched!")
    end
end)

CFrame:Inverse, when multiplied by another CFrame or Vector3, returns the said CFrame/Vector3 in local space relative to what you inversed. The new relative point can have its position compared as if it was a 3-dimensional “distance” per say.

A bit hard to explain honestly, please reply if you need more info on that.

In order to check if something hits the back of a player, I would use both raycasting and surface normals.
First off, create a raycast from the start position to the humanoidrootpart position. Ignore the target, and focus on both the position and the normal. Now, you need to convert it to an angle by using CFrame.new(start,goal) and by getting the angle from the CFrame. Now, convert it to the object space of the hit part’s CFrame. Now, get the components of the normal. Look at the fourth returned object. If it is equal to negative one, then you are facing it’s back.
Code:

function checkiffacingback(startpos,endpos)
local hitback = false
local hit,pos,normal = workspace:FindPartOnRay(Ray.new(startpos,endpos-startpos))
local objectnormal = (CFrame.new(pos,pos+normal)-pos):ToObjectSpace(hit.CFrame)
local x,y,z,hitback = objectnormal:components()
if hitback == -1 then
hitback = true
end
return hitback
end
2 Likes

Cleaning up @OsterDog’s code:

function CheckIfFacingBack(startPos, endPos)
    local hitBack = false
    local ray = Ray.new(startPos, endPos - startPos)
    local hit, _, normal = workspace:FindPartOnRay(ray)
    local objectNormal = CFrame.new(Vector3.new(), normal):ToObjectSpace(hit.CFrame)
    if objectNormal.RightVector.X == -1 then
        hitBack = true
    end
    return hitBack
end

Yes, objectNormal.RightVector.X is the fourth return from objectNormal:components()

And I think you would use it like this:

HRP.Touched:Connect(function(hit)
    if CheckIfFacingBack(hit.Position, HRP.Position) then
        print("back was touched!")
    end
end)

You can also double check if hit from CheckIfFacingBack is equal to HRP.

I just realized it doesn’t matter if you check the RightVector since you comparing directly to -1 and not using math.sign or something like that, very hard to achieve just from a bad CFrame.

2 Likes

The simplest solution is to weld a part onto the back of HumanoidRootPart and use .Touched

I like that idea, super nice! I’m gonna give that a try

Try creating a a new part as a child of the humanoid and ‘glue’ or weld it to the back of the humanoid. After that use a part touched script/block to detect the giving object, then affecting the parent part in however you wish.

Your script is pretty cool! I love the amount of math you utilised you deffintley deserve the solution not me

1 Like

Thanks for following my idea I think the way you did it is great!