Most efficient way to constantly check if player's magnitude meets a requirement?

only started scripting about a week ago, not sure how i should go about doing this. the for loop makes sense to check the magnitude across all interactable items compared to the player, but i don’t know how i should actively check the players magnitude across all 24/7 instead of just once. here’s what i have so far and i think it broke my game lol

while true do
	for i,v in pairs(interactions:GetChildren()) do
		local magnitude = (humanoid.Position - v.Position).Magnitude
		if magnitude <= 8 then
			script.Parent.Text = v.Prompt
			tweenin:Play()
		else
			tweenout:Play()
		end
	end
end
1 Like

while loops will loop forever, but it probably timed out because there is no wait or pause in your code. you can just add a wait() or change while true do to while wait() do, so the code doesn’t time out and stress itself.

Here is a reasonable writeup for quadtrees which are the efficient solution for this problem in 2D. Couldn’t easily find one for octrees (3D), but conceptually this is the best starting place:

As mentioned above you need a wait or it will timeout.

while true do
	for i,v in pairs(interactions:GetChildren()) do
		local magnitude = (humanoid.Position - v.Position).Magnitude
		if magnitude <= 8 then
			script.Parent.Text = v.Prompt
			tweenin:Play()
		else
			tweenout:Play()
		end
	end
wait()
end

Others here are right, while-loop requires some waiting, otherwise it exhausts all allowed execution time. However, don’t use wait(). It’s not OK to use it anymore, and here is the reason why (avoid delay() and spawn() in your work as well).

I just got tons of information about wait() function from @evaera’s article on eryn io. Visit her article to get tons of information instantly!

Jokes aside, I don’t know what you are checking magnitude for, but perhaps there is an alternative to constant magnitude calculations.

  1. while-loop
local RunService = game:GetService("RunService")

while true do
	for i, v in pairs(interactions:GetChildren()) do
		local magnitude = (humanoid.Position - v.Position).Magnitude
		if magnitude <= 8 then
			script.Parent.Text = v.Prompt
			tweenin:Play()
		else
			tweenout:Play()
		end
	end
	-- wait(1) ==> Not demanding, slower response.
	
	--[[
		RunService is much more consistent and reliable than wait(), while
		having same run frequency (1/30). In the near future, you should
		replace Heartbeat with its successor .PostSimulation:Wait().
	]]
	RunService.Heartbeat:Wait() -- Very rapid.
end

How else could you check player’s presence?

  1. .Touched event

The following is pretty performance friendly. It help you detect colliding. Once the collision stops, .TouchEnded is activated. There are different ways to detect object touches. For example, you can check the name

if (hit.Name = "HumanoidRootPart) then end

Check for parent’s name:

-- *Suppose that Players service is already defined.*
if (Players:GetPlayerFromCharacter(hit.Parent) == "player's name here") then end

Of you can check for object’s class:

instance:IsA() --> check if instance is class or subclass of given class.

instance.ClassName --> read-only property, ignores inheritance

There are even more of various checks you can do. For instance, you can use :FindFirstChild(“name here”), :FindFirstChildWhichIsA(“”), or :FindFirstChildOfClass(“”). Former is similar, but ignores inheritance, so it’s more strict.

The following example has a little weakness. However, the fact that complete touching of all part’s surfaces is required can be a minor drawback, but expanding part’s size pretty much solves the problem for good. It’s worth to mention that .Touched event is not as reliable at high speeds (hundreeds of studs per second).

--[[
	Detector should be anchored and have collisions disabled.
	Other properties are up to your choice.
]]
local box = workspace.Box -- your part
local is_inside = false

box.Touched:Connect(function(hit)
	if (hit.Name == "HumanoidRootPart" and not is_inside) then
		is_inside = true; print("INSIDE")
		-- execute code here
	end
end)

box.TouchEnded:Connect(function(hit)
	if (hit.Parent:FindFirstChild("HumanoidRootPart") and is_inside) then
		is_inside = false; print("OUTSIDE")
		-- execute code here
	end
end)
  1. Regions

Regions are excelent, but you should think carefully when using them. Overuse leads to performance drops (of course, we are talking about large regions). I don’t, however, think you need to use them in this case. Read more about region3 here.

1 Like