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.
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
https://i.gyazo.com/390c55b5678bdac6c925c6ca4c667497.gif
this is just what @RVVZ but I made their idea into an example
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
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.
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
Thanks for following my idea I think the way you did it is great!