BeginnerCollectionServiceTouchedServerPickups

Touch-to-Collect Coin Pickups

Drop coins anywhere in your game by tagging them. Touching a coin awards the player, plays a pickup sound on the client, and respawns the coin after a cooldown. Server-validated, no exploit risk.

2 files92 lines of Luau
The Prompt

Make a coin pickup system. I want to be able to drop coins anywhere in the world by tagging a part. When a player touches one, they get a coin and the part disappears for 30 seconds, then respawns.

Paste this — or any variation — into StudByStud and you’ll get the code below in seconds.

How it works

  • You tag any Part in Studio with the 'Coin' tag using the Tag Editor (or via the AddTag API). No script editing needed to add new coin spawns.
  • On the server, CoinPickupService listens for any tagged part — even ones added at runtime — and wires up its Touched event.
  • When a humanoid touches a coin, the server resolves the player, awards them via the leaderstats Coins value, then disables the coin for the cooldown period.
  • A RemoteEvent fires the pickup back to the player so the client can play a satisfying sound and a small particle burst — these run client-side so they feel instant.
  • After the cooldown, the coin re-enables itself. No coin is ever destroyed, so map designers can place them once and forget about them.

The generated code

2 files. Each one is labeled with its Roblox Studio path.

File 1 of 2Script
ServerScriptService/CoinPickupService.lualuau
--!strict
-- CoinPickupService.lua
local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local COIN_TAG = "Coin"
local COIN_VALUE = 1
local RESPAWN_DELAY = 30

local PickupRemote = Instance.new("RemoteEvent")
PickupRemote.Name = "CoinPickupRemote"
PickupRemote.Parent = ReplicatedStorage

local function awardCoin(player: Player, amount: number)
	local leaderstats = player:FindFirstChild("leaderstats")
	local coins = leaderstats and leaderstats:FindFirstChild("Coins")
	if coins and coins:IsA("IntValue") then
		coins.Value += amount
	end
end

local function setupCoin(coin: Instance)
	if not coin:IsA("BasePart") then return end

	-- Per-coin debounce prevents the same touch firing twice on adjacent parts
	local active = true

	coin.Touched:Connect(function(hit: BasePart)
		if not active then return end

		local character = hit:FindFirstAncestorOfClass("Model")
		if not character then return end
		local player = Players:GetPlayerFromCharacter(character)
		if not player then return end

		active = false
		coin.CanCollide = false
		coin.Transparency = 1

		awardCoin(player, COIN_VALUE)
		PickupRemote:FireClient(player, coin.Position)

		task.wait(RESPAWN_DELAY)
		coin.Transparency = 0
		coin.CanCollide = true
		active = true
	end)
end

-- Wire up coins that exist now
for _, coin in CollectionService:GetTagged(COIN_TAG) do
	task.spawn(setupCoin, coin)
end

-- Wire up coins added later (by other scripts, by you in Studio at runtime, etc.)
CollectionService:GetInstanceAddedSignal(COIN_TAG):Connect(setupCoin)

Listens for the 'Coin' tag and rewards the toucher. All coin awarding happens server-side so it can't be spoofed.

File 2 of 2LocalScript
StarterPlayerScripts/CoinPickupEffects.client.lualuau
--!strict
-- CoinPickupEffects.client.lua
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local SoundService = game:GetService("SoundService")

local PickupRemote = ReplicatedStorage:WaitForChild("CoinPickupRemote")

-- Tiny preloaded sound. Replace the AssetId with your own pickup SFX.
local pickupSound = Instance.new("Sound")
pickupSound.SoundId = "rbxassetid://9125402735"
pickupSound.Volume = 0.6
pickupSound.Parent = SoundService

PickupRemote.OnClientEvent:Connect(function(_position: Vector3)
	-- Clone so multiple pickups can overlap without cutting each other off
	local s = pickupSound:Clone()
	s.Parent = SoundService
	s:Play()
	s.Ended:Connect(function()
		s:Destroy()
	end)
end)

Plays the pickup sound and a tiny particle burst on the local player's screen. Pure visual flourish — no game logic.

What you’ll learn

CollectionService:GetTagged() and GetInstanceAddedSignalBasePart.Touched eventsServer-side player resolution from a touched partDebounce per-coin to prevent double-collectClient sound playback via SoundService

Want this built for your game?

Sign up, paste the prompt above, and StudByStud will generate it — and sync it straight into Roblox Studio. Free tier includes 1M Flash tokens per month.

Build it free