I want a GUI to open up when I get inside a circle and then close when I leave it (it has a transparent cylinder inside and the script refers to it). With just .Touched and .TouchEnded the GUI was constantly flickering when I moved inside the circle so I added the distance from center condition. Now it appears with a short lag or doesn’t appear at all.
local circle = script.Parent
local function onTouch(otherPart)
local character = otherPart.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
local player = game.Players:GetPlayerFromCharacter(humanoid.Parent)
if (character.HumanoidRootPart.Position - circle.Position).magnitude <= (circle.Size.Z/2) then
player.PlayerGui.POS.Enabled = true
end
end
end
local function offTouch(otherPart)
local character = otherPart.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
local player = game.Players:GetPlayerFromCharacter(humanoid.Parent)
if (character.HumanoidRootPart.Position - circle.Position).magnitude >= (circle.Size.Z/2) then
player.PlayerGui.POS.Enabled = false
end
end
end
circle.Touched:Connect(onTouch)
circle.TouchEnded:Connect(offTouch)
local active = false
local circle = script.Parent
local function onTouch(otherPart)
local character = otherPart.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
if not active then
active = true
local player = game.Players:GetPlayerFromCharacter(humanoid.Parent)
if (character.HumanoidRootPart.Position - circle.Position).magnitude <= (circle.Size.Z/2) then
player.PlayerGui.POS.Enabled = true
end
end
end
local function offTouch(otherPart)
local character = otherPart.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
if active then
active = false
local player = game.Players:GetPlayerFromCharacter(humanoid.Parent)
if (character.HumanoidRootPart.Position - circle.Position).magnitude >= (circle.Size.Z/2) then
player.PlayerGui.POS.Enabled = false
end
end
end
circle.Touched:Connect(onTouch)
circle.TouchEnded:Connect(offTouch)
TouchEnded never worked, you need to use Magnitude or reigen3 or something else. OR just use Touched to enable and then a close button to disable it. That’s how you fix it.
local circle = script.Parent
local toucheddb = false
local touchendeddb = false
local function onTouch(otherPart)
if toucheddb then
return
end
local character = otherPart.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
toucheddb = true
local player = game.Players:GetPlayerFromCharacter(humanoid.Parent)
player.PlayerGui.POS.Enabled = true
task.wait(5)
toucheddb = false
end
end
local function offTouch(otherPart)
if touchendeddb then
return
end
local character = otherPart.Parent
local humanoid = character:FindFirstChildWhichIsA("Humanoid")
if humanoid then
touchendeddb = true
local player = game.Players:GetPlayerFromCharacter(humanoid.Parent)
player.PlayerGui.POS.Enabled = false
task.wait(5)
touchendeddb = false
end
end
circle.Touched:Connect(onTouch)
circle.TouchEnded:Connect(offTouch)
What the previous post suggested but create a debounce for each function.
This works fine, but do you think that while loop will affect the performance much?
local circle = script.Parent
local players = game:GetService("Players")
players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local playerGUI = player:WaitForChild("PlayerGui")
local pos = playerGUI:WaitForChild("POS")
if pos then
while wait(0.1) do
if (character.HumanoidRootPart.Position - circle.Position).magnitude <= (circle.Size.Z/2) then
pos.Enabled = true
else
pos.Enabled = false
end
end
end
end)
end)
Use Run Service, I will code it for you so you can just copy and paste the code.
local circle = script.Parent
local players = game:GetService("Players")
players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local playerGUI = player:WaitForChild("PlayerGui")
local pos = playerGUI:WaitForChild("POS")
if pos then
game:GetService("RunService").Heartbeat:Connect(function()
if (character.HumanoidRootPart.Position - circle.Position).magnitude <= (circle.Size.Z/2) then
pos.Enabled = true
else
pos.Enabled = false
end
end)
end
end)
end)
Just for future reference, you should be using a while loop for this situation. Heartbeat is for cases when you need it to update quickly and if you’re not connecting and disconnecting the function it has no use being here
While loops make game lag and it makes anything below that stop working but if you use runservice it will run depending on how good your platform is and it will continue with anything below it. That’s what I got told.
I use a heartbeat 99% of the time over while loops, but for other reasons not related to performance. while loops and heartbeat’s have pretty much identical performance impacts, and in this specific case a while loop would be better.
Two examples below:
local UPDATE_FREQUENCY = 1/10
task.spawn(function()
while true do
task.wait(UPDATE_FREQUENCY)
end
end)
vs
local UPDATE_FREQUENCY = 1/10
local lastUpdate = os.clock()
RunService.Heartbeat:Connect(function()
if (os.clock() - lastUpdate >= UPDATE_FREQUENCY) then
lastUpdate = os.clock()
end
end)
These two examples accomplish the same goal, but the above does it in a much simpler way. And it’s pretty clear which one is more performant if you’re trying to run an infinite loop with no break out conditions. I only use heartbeat when I need it to disconnect at some point and not run forever. Also to solve the problem that anything below it won’t continue running, wrap it in a task.spawn()
I created my own trigger module due to touched events not working properly. It basically uses wait() when :TouchEnded() is triggered to see if a :Touched() event is rapidly fired before running the actual disconnect code.
local Trigger = {}
local Part = {} -- Part to be used in the trigger system
local TouchCount = {} -- Touch count for individual parts
local Touches = {} -- Filtered list of touching parts
local Touched = {} -- BindableEvent for Touched
local TouchEnded = {} -- BindableEvent for TouchEnded
local TouchedEvent = {} -- Exposed reference to Touched.Event
local TouchEndedEvent = {} -- Exposed reference to TouchEnded.Event
local TouchedConnection = {} -- Reference to Part.Touched:Connect()
local TouchEndedConnection = {} -- Reference to Part.TouchEnded:Connect()
local ReadOnly = {
Part = Part,
Touched = TouchedEvent,
TouchEnded = TouchEndedEvent
}
function Trigger.__index(self, name)
return ReadOnly[name] and self[ReadOnly[name]] or nil
end
function Trigger.new(part, pred)
local touches = {} -- Filtered parts touching
local touchCount = {} -- Number of times a part is touching
local touched = Instance.new("BindableEvent")
local touchEnded = Instance.new("BindableEvent")
if not pred then pred = function (hit) return hit end end
local self = {
[Part] = part,
[TouchCount] = touchCount,
[Touches] = touches,
[Touched] = touched,
[TouchEnded] = touchEnded,
[TouchedEvent] = touched.Event,
[TouchEndedEvent] = touchEnded.Event
}
self[TouchedConnection] = part.Touched:Connect(function (hit)
hit = pred(hit)
if not hit then return end
if not touchCount[hit] then
touchCount[hit] = 1
else
touchCount[hit] += 1
return
end
-- Add to parts touching
touches[#touches+1] = hit
-- Begin touch
touched:Fire(hit)
end)
self[TouchEndedConnection] = part.TouchEnded:Connect(function (hit)
hit = pred(hit)
if not hit then return end
-- Give time to twitch
wait()
-- Adjust touch count
touchCount[hit] -= 1
-- Sink all but last event
if 0 < touchCount[hit] then return end
-- Remove from touches
local j for i = #touches, 1, -1 do
touches[i], j = j, touches[i]
if j == hit then break end
end
-- Remove touch counter
touchCount[hit] = nil
-- End touch
touchEnded:Fire(hit)
end)
return setmetatable(self, Trigger)
end
function Trigger:Destroy()
--print("Destroying Trigger")
local touches = self[Touches]
local touchCount = self[TouchCount]
for n = #touches, 1, -1 do
self[TouchEnded]:Fire(touches[n])
touches[n], touchCount[touches[n]] = nil
end
self[TouchedConnection]:Disconnect()
self[TouchEndedConnection]:Disconnect()
self[Part], self[Touched], self[TouchEnded], self[TouchedEvent], self[TouchEndedEvent], self[TouchedConnection], self[TouchEndedConnection] = nil
end
return Trigger
And here’s an quick example:
local Trigger = require(PATH_TO_MODULE)
-- Optional: This particular function returns a player instance
-- when touching it's HumanoidRootPart
local function partFilter(hit)
return hit == hit.Parent.PrimaryPart and game.Players:GetPlayerFromCharacter(hit.Parent)
end
local trigger = Trigger.new(part, partFilter)
trigger.Touched:Connect(function (plr) print("Hello", plr.Name) end)
trigger.TouchEnded:Connect(function (plr) print("Goodbye", plr.Name) end)