Ricocheting while occupied by magnets

local ProjectileHandler = {}

local function ReturnDecimal(range)
	return Random.new():NextNumber(-range, range)
end

local function Lerp(a, b, t)
	return a + (b - a) * t
end

local DamageEnemy = game.ReplicatedStorage.RemoteEvents.DamageEnemy

function ProjectileHandler.Shoot(Properties, Viewmodel)
	if Properties.Type == "Projectile" then
		local Angle = 0
		local AngleDirectionToTravel = 1
		
		local RaycastParameters = RaycastParams.new()
		RaycastParameters.FilterType = Enum.RaycastFilterType.Exclude
		RaycastParameters.RespectCanCollide = true
		if Properties.IsPlayerShooting then
			RaycastParameters.FilterDescendantsInstances = {game.Players.LocalPlayer.Character, Viewmodel}
		end
		
		local Bullet = Instance.new("Part")
		Bullet:SetAttribute("TimesRicocheted", 0)
		Bullet:SetAttribute("EnemiesHit", 0)
		Bullet:SetAttribute("FollowsGravity", Properties.FollowsGravity)
		Bullet:SetAttribute("BulletVelocity", Vector3.new(Properties.Direction.X + ReturnDecimal(Properties.MaxInaccuracy), Properties.Direction.Y + ReturnDecimal(Properties.MaxInaccuracy), Properties.Direction.Z + ReturnDecimal(Properties.MaxInaccuracy)) * Properties.Speed)
		Bullet.Name = Properties.Name or "Bullet"
		Bullet.Size = Properties.Size or Vector3.new(1, 1, 1)
		Bullet.Color = Properties.Color or Color3.new(0, 0, 0)
		Bullet.Material = Properties.Material or Enum.Material.SmoothPlastic
		Bullet.CFrame = Properties.Origin
		Bullet.Parent = workspace
		Bullet.CollisionGroup = "Extra"
		game.CollectionService:AddTag(Properties.ExtraType)
		Bullet.CastShadow = false
		Bullet.AssemblyLinearVelocity = Bullet:GetAttribute("BulletVelocity")
		
		game.Debris:AddItem(Bullet, Properties.LifeTime)
		
		local Stepped = game:GetService("RunService").PreRender:Connect(function()
			local BulletVelocity = Bullet:GetAttribute("BulletVelocity")
			local CharacterCollisionRay = workspace:Blockcast(Bullet.CFrame, Bullet.Size, Bullet.AssemblyLinearVelocity.Unit * math.clamp(Properties.Speed / 25, 7, math.huge), RaycastParameters)
			
			if Bullet:GetAttribute("FollowsGravity") == false then
				Bullet.AssemblyLinearVelocity = BulletVelocity
			end
			Bullet.CFrame = CFrame.lookAt(Bullet.Position, Bullet.Position + Bullet.AssemblyLinearVelocity)

			for i, v in pairs(game.CollectionService:GetTagged("Magnet")) do
				if v:IsA("Part") and (v.Position - Bullet.Position).Magnitude < 10 then
					local SawCollisionRaycast = workspace:Raycast(Bullet.Position, Bullet.AssemblyLinearVelocity.Unit * 2, RaycastParameters)
					if Properties.MagneticType == "Swarm" then
						Bullet:SetAttribute("BulletVelocity", Lerp(BulletVelocity, (v.Position - Bullet.Position).Unit * Properties.Speed, 0.5))
					elseif Properties.MagneticType == "Circular" then
						Angle += (math.clamp(Properties.Speed / 900, 0, math.huge) * AngleDirectionToTravel)
						Angle = Angle % 360
						print(Angle)
						local NewX = v.Position.X + 8 * math.cos(Angle)
						local NewZ = v.Position.Z + 8 * math.sin(Angle)
						Bullet:SetAttribute("BulletVelocity", (Vector3.new(NewX, v.Position.Y, NewZ) - Bullet.Position).Unit * Properties.Speed / 2)
						--this is where the issue is
						if SawCollisionRaycast and SawCollisionRaycast.Instance then
							AngleDirectionToTravel *= -1
							print(SawCollisionRaycast.Instance.Name)
							wait()
						end
					end
				end
			end
			if CharacterCollisionRay and CharacterCollisionRay.Instance then
				if not CharacterCollisionRay.Instance.Parent:FindFirstChildOfClass("Humanoid") and Bullet:GetAttribute("TimesRicocheted") < Properties.MaxRicochets then
					Bullet:SetAttribute("TimesRicocheted", Bullet:GetAttribute("TimesRicocheted") + 1)
					Bullet.AssemblyLinearVelocity = Bullet.AssemblyLinearVelocity - (2 * Bullet.AssemblyLinearVelocity:Dot(CharacterCollisionRay.Normal) * CharacterCollisionRay.Normal)
					Bullet:SetAttribute("BulletVelocity", BulletVelocity - (2 * BulletVelocity:Dot(CharacterCollisionRay.Normal) * CharacterCollisionRay.Normal))
				else
					if Properties.IsPlayerShooting and CharacterCollisionRay.Instance.Parent == (game.Players.LocalPlayer.Character or Viewmodel) then return end
					
					if CharacterCollisionRay.Instance.Parent:FindFirstChild("Humanoid") and CharacterCollisionRay.Instance.Parent:FindFirstChild("Humanoid").Health > 0 then
						local HitHumanoid = CharacterCollisionRay.Instance.Parent:FindFirstChild("Humanoid")
						
						if Bullet:GetAttribute("EnemiesHit") and Bullet:GetAttribute("EnemiesHit") < Properties.MaxEnemiesToHit and not HitHumanoid:HasTag("BeenHit") then
							Bullet:SetAttribute("EnemiesHit", Bullet:GetAttribute("EnemiesHit") + 1)
							HitHumanoid:AddTag("BeenHit") 
							DamageEnemy:FireServer(HitHumanoid, Properties.Damage * ((Properties.LocationalDamage == true and CharacterCollisionRay.Instance:GetAttribute("WeakpointMultiplier") ~= nil) and CharacterCollisionRay.Instance:GetAttribute("WeakpointMultiplier") or 1))
							
							task.delay(0.75, function() HitHumanoid:RemoveTag("BeenHit") end)
							
							--Hit effects like explosions.

							for i = 1, Properties.ContinuousDamage.AmountOfLoops or 1 do
								Bullet.Anchored = true
								DamageEnemy:FireServer(HitHumanoid, Properties.ContinuousDamage.Damage * ((Properties.LocationalDamage == true and CharacterCollisionRay.Instance:GetAttribute("WeakpointMultiplier") ~= nil) and CharacterCollisionRay.Instance:GetAttribute("WeakpointMultiplier") or 1))
								task.wait(Properties.ContinuousDamage.WaitPerLoop)
							end
							Bullet.Anchored = false
							
							if Bullet:GetAttribute("FollowsGravity") == true and Properties.MaxEnemiesToHit > 1 and HitHumanoid.Health > 0 and Properties.ContinuousDamage.AmountOfLoops > 0 then
								Bullet.AssemblyLinearVelocity = Vector3.yAxis * Properties.Speed / 2
								Bullet:SetAttribute("TimesRicocheted", Properties.MaxRicochets)
							else Bullet:Destroy() end
							if Bullet:GetAttribute("EnemiesHit") >= Properties.MaxEnemiesToHit then Bullet:Destroy() end
						end
					elseif not (game.CollectionService:HasTag(CharacterCollisionRay.Instance, "Bullet") or CharacterCollisionRay.Instance.Name == "Bullet") then
						Bullet:Destroy()
					end
				end
			end
		end)
		
		Bullet.Destroying:Connect(function()
			Stepped:Disconnect()
		end)
		
		return Bullet
	end
end

return ProjectileHandler

i am making a system where you can make bullets by choosing a bunch of properties in a list. Bullets can have one of 3 magnetic types, swarm: the bullets all swarm around the magnet like bees to a hive, circular: the bullets spin in circles around the magnet, and none: not attracted to a magnet. when the magnet is close to a wall, the bullets should bounce off of the wall and begin moving in the opposite direction. The problem is that i haven't been able to find a way to properly detect this, using raycasts and blockcasts dont seem to work and there isn't anything else i can think of. is there any possible way to do this?

(also please tell me if my code is structured badly)