(FastCast) Having trouble with Reflection

bullets would go through a part and start reflecting inside other parts.
I’ve been on this all day and tried looking at the fastcast API and whatnot to figure this out, I’m stuck and I’m not sure what to do

The first shot is what I expect it to do,
but most of the time it ends up doing what the second shot is doing

function CreatePart(size, transparency, color, material)
	local Part = Instance.new("Part")
	Part.Size = size
	Part.Transparency = transparency
	Part.Color = color
	Part.Material = material
	Part.Anchored = true
	Part.CanCollide = false
	Part:SetAttribute("ArmorSettings", "Air")
	Part:SetAttribute("WallBang", true)
	Part.Parent = workspace.Entities
	return Part
end
local function Reflect(surfaceNormal, bulletNormal)
	return bulletNormal - (2 * bulletNormal:Dot(surfaceNormal) * surfaceNormal)
end
local function CanRayPierce(cast, rayResult, segmentVelocity)
	local CanPierce = false
	if rayResult.Instance:GetAttribute("ArmorSettings") == "Air" then
		CanPierce = true -- Yes! We can pierce.
	else
		local hits = cast.UserData.Hits
		if (hits == nil) then
			cast.UserData.Hits = 1
		else
			cast.UserData.Hits += 1
		end
		if (cast.UserData.Hits > 3) then CanPierce = false end
		if rayResult.Instance:GetAttribute("WallBang") then
			--MakeParticleFX("BulletHole", rayResult, cast["BulletData"])
			CanPierce = true
		end
	end
	if rayResult.Instance:GetAttribute("ArmorSettings") == "Normal_Armor" 
		or rayResult.Instance:GetAttribute("ArmorSettings") == "Fixable"
		or rayResult.Instance:GetAttribute("ArmorSettings") == "Explosive" 
		or rayResult.Instance:GetAttribute("ArmorSettings") == "OneTimeThing" then
		CanPierce = true
	else
		CanPierce = false
	end
	print(CanPierce)
	if CanPierce then
		local isWallBang = rayResult.Instance:GetAttribute("WallBang")
		local armorSettings = rayResult.Instance:GetAttribute("ArmorSettings")

		if isWallBang == true or armorSettings == "Air" then
			return
		end
		
		local position = rayResult.Position
		local normal = rayResult.Normal
		local newNormal = Reflect(normal, segmentVelocity.Unit)
		local angleOfAttack = math.deg(math.acos(newNormal:Dot(normal)))
		
		print("Shell Ricocheted")
		local Part1 = CreatePart(Vector3.new(.5, .5, .5), .5, Color3.fromRGB(85, 85, 127), Enum.Material.Neon)
		Part1.CFrame = CFrame.new(rayResult.Position, rayResult.Position + rayResult.Normal)

		local Part2 = CreatePart(Vector3.new(.1, .1, 10), .5, Color3.fromRGB(255, 170, 0), Enum.Material.Neon)
		Part2.CFrame = CFrame.new(rayResult.Position, rayResult.Position + newNormal) * CFrame.new(0,0,-5)

		local Part3 = CreatePart(Vector3.new(.3, .3, .3), .5, Color3.fromRGB(0, 170, 0), Enum.Material.Neon)
		Part3.CFrame = CFrame.new(rayResult.Position, rayResult.Position + newNormal)

		cast:SetVelocity(newNormal * segmentVelocity.Magnitude)
		cast:SetPosition(position)
	end
end
3 Likes

Doing cast:SetPosition(position + newNormal * 0.001) instead of cast:SetPosition(position) might work.

3 Likes

it kinda worked out a bit managing to just do one part instead. sometimes going through parts behind it
(timezone sucks)

also, it seems like the slower the bullet is the less likely of it will go through the part and doing all of that funkiness