Bullet Wall Penetration problem

Hello Everyone, so I already had this problem with the bullet wall penetration. But now I have a problem. So, I have two rays that do bullet penetration, but penetration only works with parts of a small width, approximately only works with such a width as in the first image. But, for other parts with other bigger widths, it’s not working. I left the script with these rays and this system.

First Image:

Main Script: (I didn’t leave all script, just that have rays and etc.)

		local ray = Ray.new(origin, (lookPos - origin).Unit * 100)
		local part, pos = workspace:FindPartOnRay(ray, player.Character, false, true)
		rs.Remotes.Events.Shoot:FireClient(player)
		if part then
			local humanoid = part.Parent:FindFirstChild("Humanoid") or part.Parent.Parent:FindFirstChild("Humanoid")
			if humanoid then
				if part.Name == "Head" then
					humanoid:TakeDamage(headshot)
				elseif part.Name == "Torso" then
					humanoid:TakeDamage(damage)
				else
					humanoid:TakeDamage(damageSmall)
				end
			end
			if part.Material == Enum.Material.SmoothPlastic then
				if part.Name == "Glass" then
					local BreakingPoint = part:FindFirstChild("BreakingPoint")
					if BreakingPoint and BreakingPoint:IsA("Attachment") then
						BreakingPoint.WorldPosition = part.Position
						BreakingPoint.Position = Vector3.new(0, BreakingPoint.Position.Y, BreakingPoint.Position.Z) 
						partFracture.FracturePart(part)
					end
				end
			end
		end
		local newRay = Ray.new(pos, (ray.Direction - hit2).Unit * 300)
		local newPart, newPos = workspace:FindPartOnRay(newRay, player.Character, false, true)
		local dis = math.round(distance); print(dis)
		if newPart then
			if dis == 1 or dis == 0 and part.Material == Enum.Material.Wood then
				local humanoid = newPart.Parent:FindFirstChild("Humanoid") or newPart.Parent.Parent:FindFirstChild("Humanoid")
				if humanoid then
					if newPart.Name == "Head" then
						humanoid:TakeDamage(headshot)
					elseif newPart.Name == "Torso" then
						humanoid:TakeDamage(damage)
					else
						humanoid:TakeDamage(damageSmall)
					end
				end
			else
				return
			end
		end

If someone can help, it would be really appreciated! Thanks.

:FindPartOnRay is sadly deprecated, I would recommend using workspace:Raycast and raycastParams instead.
Could you explain what the “dis” is?
Alternatively, you could put a ray in a repeat until it has either hit a player or if it just hits a part with wood material, you could add that part to a temporary ignore ignore table (in the loop) and then it’ll shoot another ray again. And you could also add a count so that the ray only shoots 2 rays at max.

I’m bad at Raycasts, can you explain what workspace:Raycast is?

It’s distance, I’m just calculating wall width to make Bullet Wall Penetration, so if the wall material is wood and the width is equals for example 1-3, then It’s giving damage to the character. But, if 5 and etc., or wall material equals Diamond Plate, then nothing.

I already was trying to do this, but It’s not working for me either.
I just have a problem I can kill people only when the width of the wall is equal to 0, Distance Calculator when you shoot checks what’s the width of the wall using the first hit and the second hit. And then I used math.round to have just one number.

EDIT: I forgot to say that, I already tried using workspace:Raycast, but It didn’t work for me.

EDIT 2: Here is script that checks part/wall width

local hit2; local distance; local newP2
		local function createParams(List, Type)
			local params = RaycastParams.new()
			params.FilterDescendantsInstances = List
			params.FilterType = Type
			return params end
		local function calculate(p1, p2)
			local dist = (p1 - p2).Magnitude return dist end
		local function cast(hitPos, orign, direction, obj)
			local cd; local hit1 = hitPos;
			if direction == nil then
				cd = CFrame.new(orign, hitPos).LookVector else direction = cd end
			local p = createParams({obj}, Enum.RaycastFilterType.Whitelist)
			local long = CFrame.new(orign, hitPos) * CFrame.new(0, 0, -300)
			local result = workspace:Raycast(long.Position, (long * CFrame.new(0, 0, 10000)).Position, p)

			if result ~= nil then hit2 = result.Position end
			if result.Instance.Material ~= Enum.Material.SmoothPlastic 
			or result.Instance.Material ~= Enum.Material.Plastic then
				distance = calculate(hit1, hit2)
			else
				return
			end
		end
		cast(lookPos, origin, nil, target)

So I’ve made a quick (rough) script of what I explained. Explanation is in the code. Regarding workspace:Raycast. I am bad at explaining code, but it’s totally the same as ray.new, with the advantage that it takes all options/properties of a raycast and scales it down into 1 parameter called RaycastParams. It falls under the Data Type section in the engine API, just like TweenInfo.

You can see how it is all set up in the script.

local RayPart = script.Parent


local IgnoreTable = {}                            -- Our "ignore list"


local Params = RaycastParams.new()                -- Params and properties
Params.FilterDescendantsInstances = IgnoreTable
Params.FilterType = Enum.RaycastFilterType.Blacklist


while task.wait(4) do
	
	
	repeat
		local count = 0 count += 1                 -- Keeps track of how many times the ray has been shot


		local RayResult = workspace:Raycast(RayPart.Position, Vector3.new(100,0,0), Params) -- Remember to add "Params" as the 3rd parameter!!
		
		
		local HitHumanoid = RayResult.Instance.Parent:FindFirstChild("Humanoid")
		
		
		
		if HitHumanoid then                          -- If Ray finds Humanoid then it take damage
			HitHumanoid:TakeDamage(10)

		else                                         -- Else it adds it to the temporary IgnoreList
			table.insert(IgnoreTable, RayResult.Instance)
			Params.FilterDescendantsInstances = IgnoreTable
		end
		
		
		            -- If the material is anything but wood, or if any of the XYZ sizes is greater than 3 then it just breaks out the loop.
		local HitPartSize = RayResult.Instance.Size
		
		if HitPartSize.X >= 3 and HitPartSize.Y >= 3 and HitPartSize.Z >= 3 
			or RayResult.Instance.Material ~= Enum.Material.Wood then break end 
		
		
	until HitHumanoid or count == 2                  -- Loops until hit humanoid or the ray has fired 2 times
	
	
	table.clear(IgnoreTable)                         -- These 2 lines basically just reset the whole thing
	Params.FilterDescendantsInstances = IgnoreTable
end

Showcase:

1 Like

I don’t know why, but It’s giving me this error in the output.
image

Here is the script:

local ignoreTable = {}
local params = RaycastParams.new()
params.FilterDescendantsInstances = ignoreTable
params.FilterType = Enum.RaycastFilterType.Blacklist
		
rs.Remotes.Events.Shoot:FireClient(player)
repeat
	local count = 0 count += 1
	local rayResult = workspace:Raycast(muzzlePos, Vector3.new(100,0,0), params)
	local hit = rayResult.Instance.Parent:FindFirstChild("Humanoid")
	if hit then
		if hit.Parent.Name == "Head" then
			hit:TakeDamage(headshot)
		elseif hit.Parent.Name == "Torso" then
			hit:TakeDamage(damage)
		else
			hit:TakeDamage(damageSmall)
		end
	else
		table.insert(ignoreTable, rayResult.Instance)
		params.FilterDescendantsInstances = ignoreTable
	end
	if rayResult.Instance.Material == Enum.Material.SmoothPlastic then
		if rayResult.Instance.Name == "Glass" then
			local BreakingPoint = rayResult.Instance:FindFirstChild("BreakingPoint")
			if BreakingPoint and BreakingPoint:IsA("Attachment") then
				BreakingPoint.WorldPosition = rayResult.Instance.Position
				BreakingPoint.Position = Vector3.new(0, BreakingPoint.Position.Y, BreakingPoint.Position.Z) 
				partFracture.FracturePart(rayResult.Instance)
			end
		end
	end
	local hitPartSize = rayResult.Instance.Size
	if hitPartSize.X >= 3 and hitPartSize.Y >= 3 and hitPartSize.Z >= 3 
		or rayResult.Instance.Material ~= Enum.Material.Wood then break end 
	until hit
	table.clear(ignoreTable)
	params.FilterDescendantsInstances = ignoreTable

muzzlePos it’s giving from Framework local script position of muzzle:

framework.viewmodel.Muzzle.Position

EDIT: I forgot to say that I have that script in ServerScriptService.

That error is because the raycast returns nil, meaning it hit nothing. You can avoid that error by adding this line right after the workspace:Raycast line.

if not RayResult then break end

Another quick thing, the “hit” only refers to the Humanoid, so saying hit.Parent.Name will just give you the character name. Say something like:

if hit then -- Checks if Humanoid has actually been hit
			if RayResult.Instance.Name == "Head" then          -- If so then it checks which part and damage the player accordingly
				hit:TakeDamage(20)
			elseif RayResult.Instance.Name == "HumanoidRootPart" then
				hit:TakeDamage(15)
			else
				hit:TakeDamage(10)
			end
end

Oh yeah and one last thing, you probably already know, but the vector3.new(100,0,0) should be replaced with original direction which you had in the first script, so you avoid shooting a raycast in one specific direction every time.

No, It’s not fixing the problem. I don’t know why but it’s working with Glass, but not with the dummy and walls.

Hmm, it’s hard for me to point to the exact issue, I noticed you forgot to add the count == 2 in the until. And remember that if the raycast hits the “Glass”, then the loop will end because it isn’t wood material.
If you wanna whitelist SmoothPlastic aswell, you can make a material table and then if it doesn’t find the material then it breaks

-- Outside the loop
local MaterialTable = {Enum.Material.Wood, Enum.Material.SmoothPlastic}

-- Inside the repeat loop
if HitPartSize.X >= 3 and HitPartSize.Y >= 3 and HitPartSize.Z >= 3 
			or not table.find(MaterialTable, RayResult.Instance.Material) then break end

So, I’ve added count == 2, so, I don’t see now error. But penetration is not working. And when I shoot in Glass, it’s breaking ALL glass that I have. (First Image)

I have the problem I guess here:
image

Omg my bad sorry, it’s because the “local count” is inside the repeat loop. I edited the original script here, you can just edit in the parts that are missing or should be replaced with your own code.

local RayPart = script.Parent


local IgnoreTable = {}
local MaterialTable = {Enum.Material.Wood, Enum.Material.SmoothPlastic}
local count = 0

local Params = RaycastParams.new()
Params.FilterDescendantsInstances = IgnoreTable
Params.FilterType = Enum.RaycastFilterType.Blacklist


while task.wait(3) do

	repeat
		count += 1


		local RayResult = workspace:Raycast(RayPart.Position, Vector3.new(100,0,0), Params)
		if not RayResult then break end
		print("Shot")
		local HitHumanoid = RayResult.Instance.Parent:FindFirstChild("Humanoid")



		if HitHumanoid then
			if RayResult.Instance.Name == "Head" then
				HitHumanoid:TakeDamage(20)
			elseif RayResult.Instance.Name == "HumanoidRootPart" then
				HitHumanoid:TakeDamage(15)
			else
				HitHumanoid:TakeDamage(10)
			end
		else
			table.insert(IgnoreTable, RayResult.Instance)
			Params.FilterDescendantsInstances = IgnoreTable
		end
		
		if RayResult.Instance.Material == Enum.Material.SmoothPlastic and RayResult.Instance.Name == "Glass" then
			RayResult.Instance.Parent = nil
		end
		
		local HitPartSize = RayResult.Instance.Size
		
		
		if HitPartSize.X >= 3 and HitPartSize.Y >= 3 and HitPartSize.Z >= 3 
			or not table.find(MaterialTable, RayResult.Instance.Material) then break end
		
		
		
		print(count)
	until HitHumanoid or count == 2

	count = 0
	table.clear(IgnoreTable)
	Params.FilterDescendantsInstances = IgnoreTable
end

Video:

1 Like

I have no errors, Glass works. But I have one last problem. My Dummy did not take any damage, even just shot at him without penetration.

EDIT: I guess it’s problem with dummies, but I don’t think so.

EDIT 2: I forgot to show the script.


		local ignoreTable = {}
		local params = RaycastParams.new()
		params.FilterDescendantsInstances = ignoreTable
		params.FilterType = Enum.RaycastFilterType.Blacklist
		
		local count = 0 
		local materialTable = {Enum.Material.Wood, Enum.Material.SmoothPlastic}
		rs.Remotes.Events.Shoot:FireClient(player)
		repeat
			count += 1
			local rayResult = workspace:Raycast(muzzlePos, Vector3.new(100,0,0), params)
			if not rayResult then break end
			print("Shot")
			local hitHum = rayResult.Instance.Parent:FindFirstChild("Humanoid")

			if hitHum then
				if rayResult.Instance.Name == "Head" then
					hitHum:TakeDamage(20)
				elseif rayResult.Instance.Name == "HumanoidRootPart" then
					hitHum:TakeDamage(15)
				else
					hitHum:TakeDamage(10)
				end
			else
				table.insert(ignoreTable, rayResult.Instance)
				params.FilterDescendantsInstances = ignoreTable
			end
			if rayResult.Instance.Material == Enum.Material.SmoothPlastic then
				if rayResult.Instance.Name == "Glass" then
					local BreakingPoint = rayResult.Instance:FindFirstChild("BreakingPoint")
					if BreakingPoint and BreakingPoint:IsA("Attachment") then
						BreakingPoint.WorldPosition = rayResult.Instance.Position
						BreakingPoint.Position = Vector3.new(0, BreakingPoint.Position.Y, BreakingPoint.Position.Z) 
						partFracture.FracturePart(rayResult.Instance)
					end
				end
			end

			if rayResult.Instance.Material == Enum.Material.SmoothPlastic and rayResult.Instance.Name == "Glass" then
				rayResult.Instance.Parent = nil
			end
			local hitPartSize = rayResult.Instance.Size
			if hitPartSize.X >= 3 and hitPartSize.Y >= 3 and hitPartSize.Z >= 3 
				or not table.find(materialTable, rayResult.Instance.Material) then break end
			print(count)
		until hitHum or count == 2
		count = 0
		table.clear(ignoreTable)
		params.FilterDescendantsInstances = ignoreTable

EDIT 3: When I shoot dummies, my glass is started to broken lol

Oh, these lines shouldn’t be there. They were just my own quick “glass breaking” part.

if rayResult.Instance.Material == Enum.Material.SmoothPlastic and rayResult.Instance.Name == "Glass" then
	rayResult.Instance.Parent = nil
end

So, the glass is fixed, but the Penetration is not working. Oh and, when I’m shooting the dummy, it’s giving him damage only when I’m in front of him and very very close. Is there a better way to do this? Or can I take my old script and somehow remake it so that it works fine?

Well, as I mentioned, the vector3.new(100,0,0) should be replaced with the direction kind of like you had in your first script. Else it will just go one certain direction all the time.

In this line you had what appears to be a certain direction.

local rayResult = workspace:Raycast(origin, (lookPos - origin).Unit * 100, params)
1 Like

Never mind, It’s problem with my script and viewmodel. Because, I created a new place, and made it like in your videos. And it’s working. So basically, you helped me, but now I need to fix my script now.

OHH, I remember that you said to change it, and I forgot about it. Now everything works perfectly! Thank you so much!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.