Help With for loops and magnitude script

Well first of all, this is my first post, I am new to this, what happens is that I am trying to make a store with magnitude, what I want to do is that if a player enters the magnitude radius, the gui appears, It works correctly, but it does not work with all the Parts, only with one, Can someone tell me why this happens? Thanks
Answer my questions please:

  1. Why is this happening?

  2. What can I do to fix it?

Here is a small fragment of the script where the error is

RunService.RenderStepped:Connect(function()
	for _,Part in pairs(Parts:GetChildren())do
		local Magnitude = (HumanoidRootPart.Position-Part.Position).Magnitude
		if Debounces == true then
			if Magnitude <= 10 then
				Frame.Visible = true
				ItemData = Part.Name
			else
				Frame.Visible = false
				ItemData = Data
			end
		end
	end
end)

Thanks for your attention, I hope to solve this soon!

Any errors? Also maybe could you add a print that prints out the magnitude to help us see what went wrong.

It really works fine, but it doesn’t work with all parts, to specify, I move a little closer to one part and it works but if I move closer to the other part it stops working

Does that mean the output didn’t have any errors?

No, it does not mark errors in fact, it just works only with one part, but with the other part that is in the folder as well, no

Perhaps have an invisible block which encloses the store, then use that as the start of the magnitude.

Do you know what the output tab is? When you say errors do you mean errors in the output tab or the red lines that appear under code in a script?

Hello everyone!

Even though this is a relatively old topic, and the original poster has probably had found an alternative solution, I decided to answer it now. Why is that? Because I saw at least two separate topics mentioning this loop problem, both of them unsolved, and I answered one similar questions today as well.

It’s time to break down the process.

What is actually happening inside the loop?

Original code

RunService.RenderStepped:Connect(function()
	for _,Part in pairs(Parts:GetChildren())do
		local magnitude = (HumanoidRootPart.Position - Part.Position).Magnitude
		if (magnitude <= 10) then
			frame.Visible = true
		else
			frame.Visible = false
		end
	end
end)

Looks fine, right? Yes it does, but doesn’t do what we expect it to do. What is happening here? RunService.RenderStepped runs on every rendered frame. Right after that, our for-loop starts. It loops through all parts, measures the magnitude between two vectors, namely position of HumanoidRootPart and one of the parts inside a folder, and through each pass magnitude is compared with number 10. Frame is set visible again as long as the condition is met. However! The GUI frame only shows if player is standing near one particular part. The loop runs very fast and passes through the whole table, continuously changing magnitude value according to the current part, and continuously comparing. Player cannot see any difference. It isn’t visible until the last element in given table is reached. Because it is last in order, loop doesn’t repeat, but the GUI is rather set visible and code execution pauses until next frame is rendered, which calls the whole process to run again.

How to fix this behaviour?

Instead of using RunService, I chose a while-loop. Repeat rate of RunService is way to high in for this case.

In short, we will loop through the table again, but this time search for the lowest magnitude value. First we will define “default”, starting one, later compare it with new ones, and if necessary, replace old value with lower number.

while (true) do
	--[[
		Reset magnitude value each time, so nearest
		part is not permanently determined. Otherwise,
		magnitude would be once set to the lowest value,
		and left unchanged.
	]]
	magnitude = 100
	for _, part in pairs(Parts) do
		local partDist = (hrp.Position - part.Position).Magnitude
		-- Compare magnitudes and find the nearest part.
		if (not magnitude or partDist < magnitude) then
			magnitude = partDist
			nearest = part
		end
	end
	
	if (magnitude <= 10) then
		frame.Visible = true
	else
		frame.Visible = false
	end
	wait(.1)
end

We have two options now. Either to use the above example, or to save three lines of code and use built-in method DistanceFromCharacter().

local partDist = Players.LocalPlayer:DistanceFromCharacter(part position)

Same calculations, both ways base on magnitude, most likely both between HumanoidRootPart’s position and given part’s position.

Finally, here is the whole code:

local Players = game:GetService("Players")

local frame = Players.LocalPlayer.PlayerGui.ShopGui.Frame; frame.Visible = false
local StoreBranches = workspace.StoreBranches:GetChildren()

local magnitude, nearest

while (true) do
	--[[
		Reset magnitude value each time, so nearest
		part is not permanently determined.
	]]
	magnitude = 100
	for _, store in pairs(StoreBranches) do
		local dist = Players.LocalPlayer:DistanceFromCharacter(store.Position)
		-- Compare magnitudes and find the nearest part.
		if (not magnitude or dist < magnitude) then
			magnitude = dist
			nearest = store
		end
	end
	
	if (magnitude <= 10) then
		frame.Visible = true
	else
		frame.Visible = false
	end
	wait(.1)
end

Alternatively, Region3 could be used (because it is excelent, accurate, yet performance demanding if used thoughtlessly). Another good alternative would be detection done via .Touched connection. The former is probably better, because it’s simple and doesn’t run routinely (.Touched only listens for changes).

Cheers!

1 Like