while true do
wait(1)
if (RootPart.Position - Area.Position).Magnitude < 10 then
Var = true
DoStuff(true)
Var = false
wait(1)
if Var == false then
DoStuff(false)
end
end
end
It had the purpose to show a GUI when a player was inside a radius of a part, and it did the job correctly.
Recently, I found out that it doesn’t work anymore, and I wanna ask why, and how can I make it work again ?
At the moment, every second, the function fires as true, then fires as false, then as true, continuously.
The expected behaviour was for the function to fire as false when the player was not in the radius anymore, and for it to fire as true every second the player was in radius.
It looks like you are setting the variable first to true and then doing something and then back to false and then checking if it is false, which of course it would be cause you just set it to false. You need an else statement in the first if block…
if (RootPart.Position - Area.Position).Magnitude < 10 then
DoStuff(true)
else
DoStuff(false)
end
That solves the problem, but the function would constantly fire as false, I have multiple of these functions in my script, and it would cause some performance drawbacks.
Might need more info on what exactly your trying to accomplish.
if (RootPart.Position - Area.Position).Magnitude < 10 then
--Player is within range of area now
DoStuff(true)
else
--Player is not within range of area
DoStuff(false)
end
Maybe a better way might be to create a “bubble” the size of the radius around the part. Weld the bubble part to the part in question and use the bubble as a detection object. When the player touches the bubble turn on the GUI using a touch event. That would eliminate the need to constantly poll whether the player was in range.
Example Implementation:
local somePart = game.Workspace.SomePart --part in question
local radius = 10 --range radius
local guiOn = false --flag to say if the GUI is on or not
--Create the Range Bubble to activate touch events
local bubble = Instance.new("Part", somePart)
bubble.Name = "RangeBubble"
bubble.Shape = "Ball"
bubble.Size = Vector3.new(radius, radius, radius)
bubble.CanCollide = false
bubble.Transparency = 0.5
bubble.Massless = true
bubble.Position = somePart.Position
--Weld the range bubble to the part in question
local weld = Instance.new("WeldConstraint", bubble)
weld.Part0 = somePart
weld.Part1 = bubble
--Function for handling the touch event of the range bubble
local function turnOnGui(touchPart)
if(guiOn == true)then return end --Stop this from running over and over while player is touching bubble
local character = touchPart.Parent --Assume this is the plyaer character
local humanoid = character:FindFirstChildWhichIsA("Humanoid") --Check for a humanoid object
if(humanoid)then
--A player's character has touched the bubble, they are now in range
local player = game:GetService("Players"):GetPlayerFromCharacter(character) --Get the player
player.PlayerGui.MyGUI.Enabled = true --turn on the GUI object
guiOn = true --mark that the gui is on now
--[[
Turning OFF the GUI now is another story.
You need a way of determining when you will turn it off.
This could be after so much time or when the player interacts with something else.
or you could create a loop to poll when the player leaves the bubble using a distance.
TouchEnded event is not going to be reliable for this.
--]]
wait(10) --wait 10 seconds
guiOn = false --let the event run again on next touch
player.PlayerGui.MyGUI.Enabled = false --Turn off the GUI
--OR
--[[
while guiOn do
game:GetService("RunService").Stepped:wait()
local distance = (character.HumanoidRootPart.Position - somePart.Position).Magnitude
if(distance > 10)then
guiOn = false
player.PlayerGui.MyGUI.Enabled = false
end
end
--]]
end
end
bubble.Touched:Connect(turnOnGui) --set the listener for touch events
--Or create another bubble or wall somewhere else and when that is touched it can shut off the gui.
For one, I’d recommend syncing with physics as well as maybe speeding up the loop:
while true do
wait(0.5) -- You may even remove this entirely. The performance cost is much much less if you use faster distance checks such as FuzzyEq.
RunService.Stepped:Wait()
-- Extra stuff
end
Secondly, if you want it to fire once you can use a standard debounce.
local prevValue = false
while true do
wait(0.5) -- Wait 1/2 of a second
RunService.Stepped:Wait() -- Synced with physics
local currentlyClose = RootPart.Position:FuzzyEq(Area.Position, 10) -- Currently within 10 studs (this is much much faster than Magnitude because it does not use square roots which are one of the slowest, if not the slowest operations on pretty much all current CPUs)
if currentlyClose ~= prevValue then -- If the value changed
doStuff(currentlyClose) -- Do stuff!
end
end
Edit: To clarify some things
Syncing with physics will improve reliability in laggy conditions. It doesn’t do much other than ensure that the player will receive the update in sync with the network as well as make sure physics is 100% up to date. (As soon as the player’s position is updated server side so is the check)
Your script immediately turns it back off after turning on (as another user mentioned above).
while true do
wait(1)
if (RootPart.Position - Area.Position).Magnitude < 10 then
Var = true
DoStuff(true)
Var = false
else
DoStuff(false)
end
end
Edit: I’m not sure what you are using var for, but it seems useless in this example currently. If you aren’t using it for something else, it can be removed.
If you intended var to be a debounce so that the true function is only sent when it’s currently “closed”, then you could adjust the code like so:
(You can also simply use var instead of passing true or false, now that var will be set to whatever Boolean value the function is also passing. You also can further simplify the loop by placing wait(1) in the place of true in while true do. Wait(1) is a “truthy” value so that will not only allow the loop to continue, but also wait 1 second without the need for another line).
local var = false
while wait(1) do
if (RootPart.Position - Area.Position).Magnitude < 10 then
if not var then
Var = true
DoStuff(var)
end
elseif var then
var = false
DoStuff(var)
end
end