BodyPosition ReachedTarget event not very good, any asynchronous alternatives?

Hello, I am trying to make a vacuum on the ceiling of a room that sucks up items to be deleted. I am using bodypositions to do this, and the way I am doing this is by looping through every unwanted item, making a body position for each item, setting up a reachedtarget connection for each item, and then moving the items one last time before deleting them. reachedtarget only fires when the body position’s part is super close to it’s goal, which rarely actually happens. How could I make an alternative that keeps my code asynchronous while increasing the minimum distance to activate the event?

here is my code:

local function disposeThings()
	if isDisposing == true then return end
	isDisposing = true
	for i,v in pairs(spawnedThings:GetChildren()) do
		if v:IsA("BasePart") then
			--local goalpos = {}
			--goalpos.Position = Vector3.new(0, 11.75, -15.5)
			
			local bp = Instance.new("BodyPosition")
			bp.Position = Vector3.new(0, 11.75, -15.5)
			bp.Parent = v
			v.CanCollide = false
			local tempconnect
			tempconnect = bp.ReachedTarget:Connect(function()
				bp.Position = Vector3.new(0, 16.75, -15.5)
				DBS:AddItem(v,2)
				tempconnect:Disconnect()
			end)
		elseif v:IsA("Model") then
			for a,b in pairs(v:GetDescendants()) do
				if b:IsA("BasePart") then
					b.CanCollide = false
				end
			end
			if v.PrimaryPart then
				local bp = Instance.new("BodyPosition")
				bp.Position = Vector3.new(0, 11.75, -15.5)
				bp.Parent = v.PrimaryPart
				local tempconnect
				tempconnect = bp.ReachedTarget:Connect(function()
					bp.Position = Vector3.new(0, 16.75, -15.5)
					DBS:AddItem(v,2)
					tempconnect:Disconnect()
				end)
			end
		end
	end
	--[[wait(2)
	for i,v in pairs(spawnedThings:GetChildren()) do
		if v:IsA("BasePart") then
			--local goalpos = {}
			--goalpos.Position = Vector3.new(0, 11.75, -15.5)

			local bp = v:FindFirstChild("BodyPosition")
			bp.Position = Vector3.new(0, 16.75, -15.5)
		elseif v:IsA("Model") then
			if v.PrimaryPart then
				local bp = v.PrimaryPart:FindFirstChild("BodyPosition")
				bp.Position = Vector3.new(0, 16.75, -15.5)
			end
		end
	end
	wait(1)
	for i,v in pairs(spawnedThings:GetChildren()) do
		v:Destroy()
	end]]--
	thingCount = 0
	thingCountText.Text = tostring(thingCount).."/"..tostring(maxThingCount)
	isDisposing = false
end

Why not just delete using if Part.Position.Y >= 11.75 then Part:Destroy? That would indicate they’ve been raised up the correct level.
If they are off the X and Z by a stud or so will it matter?

Because then I would have to use wait(), and that would stop the loop and cause every part to go up the vacuum 1 by one, which would look ugly and increase waiting time exponentially.

Just put a small script in each part:

if script.Parent.Position.Y >= 11.75 then
     -make it go away-
     wait(.1)
end

If you wanted to you could put it in a function that fires only when the Position property of the Part or Model changes.

I just up with a different idea: I can use getpropertychangedsignal() and then check the position when ever it is changed. That way, I don’t need to have multiple scripts and I don’t need to use loop. Thank you though for helping. I’ll mark this as the solution if it ends up working efficiently

Although you have your own solution already, you totally can do this without having the objects go up one by one.

First, you add the bodyposition as usual.
You do not wait for it to go up. Instead, you simply add the part to a list of objects to check, or reuse the original list (the table returned by spawnedThings:GetChildren()).

After you have added the bodypositions, start looping over all the parts and checking their positions, removing any destroyed parts from the world and the list, and stopping the loop when all parts are gone.

There’s also a way to do this that doesn’t involve checking positions.
Simply add an invisible part to where the BodyPosition is moving to, then make sure that this part destroys the vacuumed objects.
Making it simply delete all touched objects works, but not for the models… for those, you have to make the model check for collisions with the destroyer (or make the destroyer find the Model it touched).