CUBE BURSTSTUDIOS
spinning-coins.zip
Details

Spinning Coins & Collectibles

Tag a part or model 'Coin' and it bobs, spins, pays out and respawns. One efficient loop animates them all.

Category
Code
File
spinning-coins.zip
Size
2.1 KB
Downloads
0
Added
16 Oct 2026
Licence
Free to use, no credit needed (CC0)

#coins#collectibles#pickup#simulator#luau#roblox#script

⚑ Report this

Tag a part or model 'Coin' and it bobs, spins, pays out and respawns. One efficient loop animates them all.

Tag any part or model "Coin": it bobs and spins, gives coins when touched, then respawns after a delay.

SETUP
1. Put this Script in ServerScriptService.
2. Tag your coin parts or models "Coin" (Properties > Tags). Optional number attributes:
"Value" (coins given, default 1) and "Respawn" (seconds, default 10).
3. Optional: put a Sound inside the coin; it plays when collected.
Coins go to leaderstats.Coins if it exists (works with the Leaderstats + Saving script),
otherwise to a "Coins" attribute on the player.

The main script is shown below with a Copy button, or grab the download with every file and a README.

Collectibles.server.lua
--[[
	Spinning Coins & Collectibles  ·  by Cube Burst Studios  ·  CC0
	Tag any part or model "Coin": it bobs and spins, gives coins when touched, then respawns after a delay.

	SETUP
	1. Put this Script in ServerScriptService.
	2. Tag your coin parts or models "Coin" (Properties > Tags). Optional number attributes:
	   "Value" (coins given, default 1) and "Respawn" (seconds, default 10).
	3. Optional: put a Sound inside the coin; it plays when collected.
	Coins go to leaderstats.Coins if it exists (works with the Leaderstats + Saving script),
	otherwise to a "Coins" attribute on the player.
]]

local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")
local RunService = game:GetService("RunService")

local SPIN_SPEED = 2 -- radians per second (about one turn every 3 seconds)
local BOB_HEIGHT = 0.5

local coins = {} -- [part or model] = { home = CFrame, parts = { [BasePart] = transparency }, active = bool, phase = number }

local function give(player, amount)
	local stats = player:FindFirstChild("leaderstats")
	local value = stats and stats:FindFirstChild("Coins")
	if value then
		value.Value += amount
	else
		player:SetAttribute("Coins", (player:GetAttribute("Coins") or 0) + amount)
	end
end

local function setup(coin)
	if coins[coin] or not (coin:IsA("BasePart") or coin:IsA("Model")) then
		return
	end
	if coin:IsA("Model") and not coin.PrimaryPart then
		coin.PrimaryPart = coin:FindFirstChildWhichIsA("BasePart", true) -- PivotTo needs a pivot to spin around
	end
	local parts = {}
	for _, p in ipairs(coin:IsA("Model") and coin:GetDescendants() or { coin }) do
		if p:IsA("BasePart") then
			p.Anchored = true
			p.CanCollide = false
			parts[p] = p.Transparency
		end
	end
	local info = { home = coin:GetPivot(), parts = parts, active = true, phase = math.random() * math.pi * 2 }
	coins[coin] = info
	local function setVisible(visible)
		for p, transparency in pairs(parts) do
			p.Transparency = visible and transparency or 1
		end
	end
	local function touched(hit)
		local player = Players:GetPlayerFromCharacter(hit.Parent)
		if coins[coin] ~= info or not info.active or not player then
			return
		end
		info.active = false -- one collect per spawn, even if many body parts touch at once
		give(player, coin:GetAttribute("Value") or 1)
		local sound = coin:FindFirstChildWhichIsA("Sound", true)
		if sound then
			sound:Play()
		end
		setVisible(false)
		task.delay(coin:GetAttribute("Respawn") or 10, function()
			if coins[coin] == info then
				setVisible(true)
				info.active = true
			end
		end)
	end
	for p in pairs(parts) do
		p.Touched:Connect(touched)
	end
	coin.Destroying:Connect(function()
		coins[coin] = nil
	end)
end

for _, part in ipairs(CollectionService:GetTagged("Coin")) do
	setup(part)
end
CollectionService:GetInstanceAddedSignal("Coin"):Connect(setup)

-- one loop animates every coin (much cheaper than a script per coin)
RunService.Heartbeat:Connect(function()
	local t = os.clock()
	for coin, info in pairs(coins) do
		if info.active then
			local bob = math.sin(t * 2 + info.phase) * BOB_HEIGHT
			-- spin around the world's up axis, keeping any tilt the coin was placed with
			coin:PivotTo(CFrame.new(info.home.Position + Vector3.new(0, bob, 0)) * CFrame.Angles(0, t * SPIN_SPEED + info.phase, 0) * info.home.Rotation)
		end
	end
end)

MORE
CODE

View all ↗