How to make GUI appear and disappear when touching and not touching part

I am trying to make it so that when the you enter the area with a non-collision part, a shop GUI tweens in, and when you leave the area the shop GUI tweens out.

local replicatedstorage = game:GetService('ReplicatedStorage') 

script.Parent.Touched:Connect(function(hit)
	print("test1")
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player and not game.StarterGui.ShopGui.Frame.Visible then
		print("test2")
		replicatedstorage:WaitForChild('TouchingShop'):FireClient(player)
	end
end)

script.Parent.TouchEnded:Connect(function(hit)
	print("test3")
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player and game.StarterGui.ShopGui.Frame.Visible then
		print("test4")
		replicatedstorage:WaitForChild('NotTouchingShop'):FireClient(player)
	end
end)

The problem is that all the print statements start firing randomly, and the TouchEnded should only be firing when you leave the part, but it does it rapidly while you are inside it.

Annotation 2020-04-10 150959
Here are my GUI tween scripts:

Popup Script:

script.Parent.Frame.Visible = false
script.Parent.Frame.Position = UDim2.new(0.182, 0,-1.163, 0)
local frame = script.Parent.Frame
local replicatedstorage = game:GetService('ReplicatedStorage')

replicatedstorage:WaitForChild('TouchingShop').OnClientEvent:Connect(function()
	print("Shop opened") 
	frame.Visible = true
	frame:TweenPosition(UDim2.new(0.182, 0,0.163, 0))
end)

My shop GUI doesn’t open either, and the code isn’t working since it’s not printing “Shop opened”

Close script:

local replicatedstorage = game:GetService('ReplicatedStorage')
local frame = script.Parent.Frame

replicatedstorage:WaitForChild('NotTouchingShop').OnClientEvent:Connect(function()
	frame:TweenPosition(UDim2.new(0.182, 0,-1.163, 0), "In", "Quint", 1)
	wait(2)
	frame.Visible = false
end)

I’ve attempted to use answers from these posts but they didn’t work, the TouchEnded still fires when you’re inside the part.

How can I fix my scripts so that it works?

EDIT: I’ve removed the Visibility part from the script but the problem persists

EDIT 2: I’ve made it all client sided
It still has issues though, as it keeps randomly disappearing
robloxapp-20200410-1646453.wmv

EDIT 3: I used magnitude instead of touched, the GUI works now

6 Likes

Firstly, I want to point out that Touched events can run on the client so you can just use a local script to listen if the player is touching the part or not. which would remove the latency from communicating with the client from the server.

Secondly, I don’t think if you change something in a GUI from the client the server can see it. so the line where you check if the GUI is visible wont work.

2 Likes

I removed the “and game.StarterGui.ShopGui.Frame.Visible” and now the script opens but it keeps appearing and disappearing

I changed it to a LocalScript inside the part but it wouldn’t do anything

.Touched works in server scripts

1 Like

player.PlayerGui.ShopGui.Frame.Visible will access the PlayerGui

StarterGui would be a container for what every player starts with, it can then be accessed from the PlayerGui

No?

Have you even tried to do this in studio or is this an assumption? As far as I know, most events work in client since it’s the primary focus of the game. So, the best solution has already been provided by @LuaDeveloped
already. Make a touched event for the client and bring up a GUI nice and easy.
Also, don’t forget debounce.

Try to put the localscript in the client side folders (startergui or the like) and try again. Make sure to adjust the variable references accordingly tho’.

A couple things after looking at this code.
First off, doing if player and game.StarterGui.ShopGui.Frame.Visible then will not give results you want. StarterGui is a server sided thing that clones UI to clients.

PlayerGui would be better (obtained with player.PlayerGui)

Secondly, it’s best probably figure out a method to check the frame visibility on the client, like so:

replicatedstorage:WaitForChild('TouchingShop').OnClientEvent:Connect(function()
if not game.Players.LocalPlayer.PlayerGui.ShopGui.Frame.Visible then
	print("Shop opened") 
	frame.Visible = true
	frame:TweenPosition(UDim2.new(0.182, 0,0.163, 0))
end
end)

I also want to address people saying to put the touched event on the client. While you can do this, I don’t recommend it as the servers position of the client is better. The less you can put on the client in my opinion, the better, as it will lessen the chances of exploitation.

1 Like

Touched can be connected to by the server. Try to do your own testing and research as well if you’re telling another to do so before responding. There is no client-only tag on the Touched event and a server script can connect to it.

While it’s not particularly appropriate for this specific use case and this can all be (and should be) controlled from the client, what you said isn’t right. It’d be more accurate to say it’s not good for this use case instead.

2 Likes

I said to put the touched event in a local script. He has it on the server the uses a remote event to tell the client.

As for the visibility. If you change the property from the client it won’t replicate. I tried it.

I never said that it isn’t.I only said that the event can be connected in the client which prevents calling remotes here and there. (latency)

Also if i mislead you, it’s probably my language. English isn’t my first or second language :sweat_smile: . I try

You don’t need to fire a remote event from the client to allow the server to detect when a part is touched. The touched event can be detected on the client and the server. (I haven’t used .Touched for a while so something might have changed since the last time i’ve used it.)

That’s exactly what I meant :sweat_smile:

My english sucks honestly

1 Like

There are a few issues with your code, some major, some minor.

For starters, there is no reason to have this run through remote events since the entirety of your code can be client-sided as I have seen a few others mention in this thread. It’s bad practice in this scenario and isn’t necessary in the slightest.

The major issue posed by your code is the relative unreliability of .Touched and .TouchedEnded (when it comes to a use case such as this), though if we set that aside, there are two other prime issues in your code:

  1. You are trying to identify .Visible from the startergui (which remains unchanged in your code as it should)
  2. You are trying to identify .Visible whilst changing it on the client (thus the value still remains unchanged).

I strongly recommend switching the entirety of your code to client-side and removing the detection of .Visible in the first place (since it doesn’t serve much purpose to begin with)

To defend @fredrick254 in this situation, he never tried to claim .Touched couldn’t be connected to by the server nor did he say it couldn’t be connected to by the client. He simply offered his advice to switch from a server-side system with RemoteEvents to making the entire script client-side without making any bold and untrue statements.

(cc: @colbert2677)

1 Like

That’s not right. This wasn’t clarified until later. The choice in wording leads to confusion when you say “no” to someone saying that Touched works on the server. Until said clarification, this was not the implication and a whole different thing was said up until a later response.

When you read it out, yes in fact this part says that Touched can’t be connected to by the server, which is untrue. It’s not the same thing as suggesting changing your system to avoid network overhead.

Please take any further discussion of this to DMs as it’s getting off-topic.

1 Like

I’ve followed your advice and made it all client sided, now it runs on a single script

script.Parent.Frame.Visible = false
script.Parent.Frame.Position = UDim2.new(0.182, 0,-1.163, 0)
local frame = script.Parent.Frame
local replicatedstorage = game:GetService('ReplicatedStorage')

game.Workspace.ShopArea.Touched:Connect(function(hit)
	if not game.Players.LocalPlayer.PlayerGui.ShopGui.Frame.Visible then
		print("Shop opened") 
		frame.Visible = true
		frame:TweenPosition(UDim2.new(0.182, 0,0.163, 0))
	end
end)

game.Workspace.ShopArea.TouchedEnded:Connect(function(hit)
	print("Shop closed")
	frame:TweenPosition(UDim2.new(0.182, 0,-1.163, 0), "In", "Quint", 1)
	wait(2)
	frame.Visible = false
end)

It still has issues though, as it keeps randomly disappearing
robloxapp-20200410-1646453.wmv

Is there a better alternative to this?

There is! Due to these events not being very reliable I like to use things like :GetTouchingParts() (which has its own issues you should look into), or my person favorite, magnitudes.

Magnitudes essentially check the distance a player is from a part, and if they’re within range it does stuff (or you can inverse it and stuff happens when they’re out of range).

3 Likes

Thank you! After using magnitude and changing the part to a cylinder I was able to make it work properly.

5 Likes