i wanna add penetration to my game
depending on the angle of the bullet your bullet may go through a wall if the penetration of the bullet is strong enough just like how penetration works in war thunder

main question: how to calculate the amount of penetration needed to go through a wall depending on the angle

The relative armor thickness (x) can be calculated as the actual armor thickness (w), divided by the sine of the angle (θ). It is important to use degrees, not radians, when doing this calculation.

(Of course, ignoring the “Use degrees, not radians” part, as Roblox uses radians)

This only works if the “armor” you are penetrating is a rectangular prism or abstracted into a 2-dimensional plane. For more complicated shapes or if you want it to work with Meshparts, you need to measure the thickness from the impact point to the exit point. Using raycasts won’t suffice because there might be gaps in the mesh, and also because of convex decomposition clipping errors.

Here’s my thickness measuring tool that uses spatial query instead in an iterative manner. It can definitely be improved; it has some precision loss that can be fixed, but works as-is. This should give you a general idea of how its done.

Code

local function raycastThickness(part: BasePart, hitAt: Vector3, dir: Vector3, maxDist: number?): number?
local rcp: RaycastParams = RaycastParams.new()
rcp.FilterDescendantsInstances = {part}
rcp.FilterType = Enum.RaycastFilterType.Include
local olp: OverlapParams = OverlapParams.new()
olp.FilterDescendantsInstances = {part}
olp.FilterType = Enum.RaycastFilterType.Include
olp.MaxParts = 1
local extents: number = part.Size.Magnitude
local extentsRCR: RaycastResult? = workspace:Raycast(hitAt+dir*(extents+1), dir*-(extents+2), rcp)
if extentsRCR then
extents = (hitAt - extentsRCR.Position).Magnitude
end
extents = math.min(extents, maxDist or math.huge)
local scanRadius: number = math.max(0.1, math.floor(extents*1 +.5)*.02)
print(`scan radius {scanRadius}`)
scannerP.Size = Vector3.one*scanRadius
local scanStep: number = scanRadius * 2
task.spawn(dot, hitAt, Color3.new(1, 0, 0))
task.spawn(dot, hitAt+dir*extents, Color3.new(1, 1, 0))
local delta: Vector3 = dir*scanStep
local scanPos: Vector3 = hitAt
local traveled: number = 0
local i: number = 0
while traveled < extents do
i += 1
scannerP.Position = scanPos
if not workspace:GetPartsInPart(scannerP, olp)[1] then
break
end
scanPos += delta
traveled += scanStep
end
task.spawn(draw, hitAt, hitAt+dir*traveled, Color3.new(0, 1, 0))
print(`iterations count {i}`)
return traveled
end