I’m currently making a small destruction script which i will use in a future game and in order to prevent some glitch(Breaking while moving across a flat surface) in need to get the touched surface normal of the touched part.
In the code, i use raycast to get the surface normal of the touched part(The final version will use vertice data). The problem comes from Roblox physic being wobbly which make the part(In this case the character limbs) go trough the touched part for some micro second. Then while the part is inside, the game raycast in the center of the hited part but it fails because the raycast origin is inside of hitted part and then when it reach the center it considers not hitting any surface so it errors.
The first version of the script used math to detect which side was the part position from the center Ex : If you are on top it will return 0,1,0 as normal and that for every side. But again, there was a problem which made it not function properly and return 75% of the time 0,0,1 or 1,0,0 as a normal when you where on top of something(0,1,0)
Here is the simplified version of the code. Just put it inside and r15 character(What im testing it on) and watch the script show the error when he fall or get hitted hard.
local Childrens = script.Parent:GetChildren()
local MinForce = 25
for i, v in pairs(Childrens) do
if v:IsA("PVInstance") and not v:IsA("Model") and v.Name ~= "HumanoidRootPart" then
v.Touched:Connect(function(Hit)
if Hit.Parent ~= v.Parent then
local AppliedForce = Vector3.new(math.abs(Hit.AssemblyLinearVelocity.X - v.AssemblyLinearVelocity.X), math.abs(Hit.AssemblyLinearVelocity.Y - v.AssemblyLinearVelocity.Y), math.abs(Hit.AssemblyLinearVelocity.Z - v.AssemblyLinearVelocity.Z))
if AppliedForce.X >= MinForce or AppliedForce.Y >= MinForce or AppliedForce.Z >= MinForce then
local RayDirection = (Hit.Position - v.Position)
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {Hit}
raycastParams.FilterType = Enum.RaycastFilterType.Whitelist
local raycastResult = workspace:Raycast(v.Position, RayDirection, raycastParams)
VisualiseRaycast(v.Position, RayDirection, raycastResult, v)
if raycastResult then
print(raycastResult.Normal)
end
end
end
end)
end
end
function VisualiseRaycast(Origine, Direction, Result, Caster)
local Visualiser = Instance.new("Part", workspace)
local FinalPos = Origine + Direction
local Distance = (Origine - FinalPos).Magnitude
Visualiser.Anchored = true
Visualiser.CanCollide = false
Visualiser.CanTouch = false
Visualiser.Size = Vector3.new(0.1, 0.1, Distance)
Visualiser.CFrame = CFrame.lookAt(Origine, FinalPos) * CFrame.new(0, 0, -Distance / 2)
if Result then
Visualiser.Color = Color3.fromRGB(0, 255, 127)
Visualiser.Name = "Succes"
else
local FailIndicator = Instance.new("Part", workspace)
FailIndicator.Anchored = true
FailIndicator.CanCollide = false
FailIndicator.CanTouch = false
FailIndicator.Name = Caster.Name
FailIndicator.Position = Caster.Position
FailIndicator.Size = Caster.Size
Visualiser.Color = Color3.fromRGB(170, 0, 0)
Visualiser.Name = "Failed"
warn("Raycast Failed")
end
end