How to get nearest part from a selection of parts, and prevent the loop from continuing until said part is no longer near player

I’m trying to get a constant loop of all the doors in my game, and basically stop the loop when a door is found, and the player is near said door, but still be able to track wheether the player gets closer to a different door, or has moved away from the current door

local function RenderStepped()
	local Character = Player.Character
	if Character then
		local HumanoidRootPart = Character:FindFirstChild('HumanoidRootPart')
		if not HumanoidRootPart then return end

		for _, v in pairs(AllDoors) do
			Distance = (v.CFrame.Position - HumanoidRootPart.CFrame.Position).magnitude
			if not Door or Distance <= 8 then
				Door = v
			end
		end
     end
     if Door then
         print('Nearest door', Door) -- SHOULD ONLY PRINT ONCE!, not constantly
    end
end
1 Like

Is there any particular reason you want to lock up the GPU for this task? You named the function RenderStepped which implies you intend on running it on the render cycle.

If you just want to find the nearest door then record the minimum distance so far and iterate over the set of doors. If the initial minimum distance is replaced with 8 then it will not find any door if none are closer than 8 away.

local function GetNearestDoor()
	local Character = Player.Character
	if not Character then return end
	local HumanoidRootPart = Character:FindFirstChild('HumanoidRootPart')
	if not HumanoidRootPart then return end
	local minDistance, door = math.huge, nil
	for _, v in pairs(AllDoors) do
		local distance = (v.Position - HumanoidRootPart.Position).Magnitude
		if distance < minDistance then
			minDistance, door = distance, v
		end
	end
	return door
end

It is being run by RenderStepped, so ye. Reason I don’t want it constantly looping is because I want to try tweening the door, and if its constantly looping, the door just keep tweening, and I’m unsure how to go about fixing that problem :confused:

Kinda made another post here on the whole door tweening problem

It still prints constantly tho :confused:

local function GetNearestDoor()
	local Character = Player.Character
	if not Character then return end
	local HumanoidRootPart = Character:FindFirstChild('HumanoidRootPart')
	if not HumanoidRootPart then return end
	local minDistance, door = 8, nil
	for _, v in pairs(AllDoors) do
		local distance = (v.Position - HumanoidRootPart.Position).Magnitude
		if distance < minDistance then
			minDistance, door = distance, v
		end
	end
	return door
end

local function RenderStepped()
	local Door = GetNearestDoor()
	if Door then
		print(Door)
	end
end 

There isn’t really any easy way to improve finding the nearest door better than a constant loop. Synchronizing it with the screen’s framerate is completely unnecessary.

The problem you want to solve is to have an event-driven type system where you only do something when the status of whether or not a particular door is in range changes. This can be done using a loop in its own thread and a BindableEvent.

local NearestDoorChanged = Instance.new("BindableEvent")
coroutine.wrap(function()
	local nearestDoor = nil
	while true do
		local door = GetNearestDoor()
		if nearestDoor ~= door then
			nearestDoor = door
			NearestDoorChanged:Fire(door)
		end
		wait(.1)
	end
end)()

NearestDoorChanged.Event:Connect(function(door)
	print("door: "..tostring(door))
end)
1 Like

I’ve never really used coroutines before, but guessing it just allows the loop to continue running while allowing the code after to run as well. Could I use a spawn() function instead??

spawn is fine here, it has the same effect, it just acts like there’s a wait() at the top but that doesn’t matter here.

1 Like