One option is to just detect the touched event locally and change the text property of the gui but that would be horribly insecure and exploitable, so let's not go down that route.
A safer way would be to set up a listener function to the touched event from the server and tell the client when this event fires. Because there is communication between server and client, you will need to use remote events. Another thing you must do to prevent exploits is to store how many coins each player has internally somewhere on the server. If you don't and purely base the amount of coins a player has based on a value stored locally, an exploit could easily change that value to something different. Here, I'm giving some very rough code on what this would look like:
Server script:
local coin = workspace.Coin
local remoteEvent = workspace.CoinObtained
local CoinsOwned = {}
game.Players.PlayerAdded:Connect(function(p)
CoinsOwned[p.Name] = 0
end)
game.Players.PlayerLeaving:Connect(function(p)
CoinsOwned[p.Name] = nil
end)
coin.Touched:Connect(function(hit)
local Player = game.Players.GetPlayerFromCharacter(hit.Parent)
if Player then
CoinsOwned[Player.Name] = CoinsOwned[Player.Name + 1
remoteEvent:FireClient(Player)
end
end)
Local script:
local remoteEvent = workspace.CoinObtained
local PlayerGui = game.Players.LocalPlayer.PlayerGui
local textBox = PlayerGui.ScreenGui.text
local coins = 0
remoteEvent.OnServerEvent:Connect(function()
coins = coins + 1
textBox.text = "Coins: "..coins
end)