Skip to main content

Stage 3: Plank Walkway + pickup coins

Course progressStage 3 of 10
~45 min
Before you start

Finish Stage 2. Your TycoonEconomy script scans all SpawnLocations and pays each one its StageNumber in coins.

Build

a plank walkway, the Stage 4 checkpoint, and a generic coin-pickup script driven by a CoinValue attribute

Learn

how a ProximityPrompt turns any part into an interactable, and how an attribute on the part lets one script handle many different coin values

Ship

a tycoon where coins float on the path itself — pick them up to bank extra, on top of the per-stage rewards

Teacher demo

60-second demo:

  • Play Stage 3. Notice the gold coins floating above the plank walkway.
  • Walk near one — a "Press E to collect" prompt appears. Press E. Coin disappears, counter ticks up by 1.
  • Walk near a gold coin (different recipe) — counter ticks up by 5.
  • Explain: "Same script handles both. The CoinValue attribute on the part decides how much it's worth."

The big idea

Stages 1 and 2 paid the player only when they reached a checkpoint. That's the baseline income. Today you add bonus income — pickups scattered along the path that pay you instantly when you collect them.

This is the second economy lever in any tycoon: not just "what does the journey pay?" but "what's lying around for the player to grab?" Pickup rewards encourage exploration and reward careful play — you have to read the path to spot them.

The mechanic uses a Roblox feature called ProximityPrompt. Add one to any part and Roblox shows a "press E" UI bubble when a player walks near it. When pressed, an event fires. You connect that event to a script that pays out and removes the pickup.

Today's script is generic: one handler in ServerScriptService that wires up every pickup it can find — and each pickup's payout is whatever its CoinValue attribute says. Same data-driven pattern as Stage 2, applied to a different mechanic.

New words
ProximityPrompt
a Roblox object you add to a part — shows a 'press key to interact' bubble when a player walks near it
Triggered event
fires when the player actually presses the key on the prompt; gives you the player as an argument
ActionText
the words shown on the prompt UI ('Collect', 'Buy', 'Open')
HoldDuration
how long the player must hold the key before the prompt fires — 0 means instant
Destroy
removes a part from the game permanently — perfect for one-shot pickups

Build it

Step 1 — Build the plank walkway

Three thin planks end-to-end with a wider rest stop in the middle. Same as the base obby's Stage 3.

A plank walkway with a rest stop

Build this part

Plank_1

Block
Open recipe
Size
2 × 1 × 21
Color
Reddish brown
Material
Wood
Anchored
✓ Yes
Place
Starting at the Stage 3 green pad, stretching forward
Build this part

RestStop

Block
Open recipe
Size
13 × 1 × 6
Color
Brick yellow
Material
Wood
Anchored
✓ Yes
Place
At the far end of Plank_1
Build this part

Plank_2

Block
Open recipe
Size
2 × 1 × 21
Color
Reddish brown
Material
Wood
Anchored
✓ Yes
Place
On the far side of RestStop
Build this part

Plank_3

Block
Open recipe
Size
2 × 1 × 21
Color
Reddish brown
Material
Wood
Anchored
✓ Yes
Place
End-to-end with Plank_2

Step 2 — Wire the Stage 4 checkpoint

Build this part

SpawnLocation (Stage 4 — end of plank walkway)

Block
Open recipe
Size
6 × 1 × 6
Color
Bright yellow
Material
Plastic
Anchored
✓ Yes
Place
At the end of Plank_3

Also: check AllowTeamChangeOnTouch. Uncheck Neutral. Set TeamColor to Bright yellow.

Tag this SpawnLocation with a StageNumber attribute set to 4 — same gesture as Stage 1.

In Teams, insert a new Team named Stage 4. Set its TeamColor to Bright yellow. Uncheck AutoAssignable.

Press Play. Walk the planks. The Stage 4 pad now pays 4 coins (your Stage 2 script picks it up automatically, no script edits needed). That's the payoff for last stage's refactor.

Step 3 — Build a coin pickup

Coin pickups are flat gold cylinders that float above the walkway. Players collect them by walking up and pressing E.

Build this part

CoinPickup

Cylinder
Open recipe
Size
0.4 × 2 × 2
Color
Bright yellow
Material
Neon
Anchored
✓ Yes
Place
Hovering 3 studs above Plank_1, in the middle of its length

Cylinder with X = 0.4 makes a flat disc. Anchored = true keeps it floating. The shape is your visual contract — players should recognize it as 'coin'.

3.1 Add a ProximityPrompt

A ProximityPrompt is what makes the coin interactable.

  • In Explorer, right-click CoinPickupInsert ObjectProximityPrompt.
  • Click the new ProximityPrompt and open Properties. Set:
    • ActionTextCollect
    • HoldDuration0 (instant on press)
    • MaxActivationDistance8 (player must be within 8 studs)

3.2 Add a CoinValue attribute to the pickup

This is the same attribute trick as StageNumber — the part carries its own payout in an attribute, and one generic script reads it.

  • With CoinPickup selected, in Properties → Attributes → click +.
  • Name: CoinValue. Type: number. Value: 1.

Step 4 — Write the pickup script

Open TycoonEconomy in ServerScriptService. You'll build the pickup wiring in two passes — write the function first and test it on one pickup, then convert to a loop that handles every pickup automatically.

Code flow

You are adding this to the bottom of the same TycoonEconomy script from Stages 1-2. Pass 1 ends with one temporary test line. Pass 2 deletes only that test line and replaces it with the scan loop. Do not keep both versions.

Pass 1 — Define wirePickup and test it on one pickup

Type this to the bottom of TycoonEconomy:

local function wirePickup(pickup)
local prompt = pickup:FindFirstChildWhichIsA("ProximityPrompt")
local value = pickup:GetAttribute("CoinValue")
if not prompt or not value then return end

prompt.Triggered:Connect(function(player)
if not player or not player:FindFirstChild("leaderstats") then return end
player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + value
pickup:Destroy()
end)
end

-- Test the function on the one pickup you placed by hand.
wirePickup(workspace:WaitForChild("CoinPickup"))

Press ▶ Play. Walk near the gold disc. The "Collect" prompt appears. Press E. The coin disappears, your counter goes up by 1.

If pressing E does nothing, the ProximityPrompt is missing or the CoinValue attribute is missing — re-check Step 3.1 and 3.2.

Press Stop. The function works for one pickup. Pass 2 makes it work for all of them.

Pass 2 — Replace the single call with a scan loop

The function stays. Delete only the temporary test line:

wirePickup(workspace:WaitForChild("CoinPickup"))

Replace it with a loop that finds every pickup by its CoinValue attribute and wires each one:

for _, part in ipairs(workspace:GetDescendants()) do
if part:GetAttribute("CoinValue") then
wirePickup(part)
end
end

Your pickup section should now end like this:

local function wirePickup(pickup)
local prompt = pickup:FindFirstChildWhichIsA("ProximityPrompt")
local value = pickup:GetAttribute("CoinValue")
if not prompt or not value then return end

prompt.Triggered:Connect(function(player)
if not player or not player:FindFirstChild("leaderstats") then return end
player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + value
pickup:Destroy()
end)
end

for _, part in ipairs(workspace:GetDescendants()) do
if part:GetAttribute("CoinValue") then
wirePickup(part)
end
end

Press ▶ Play. You can still collect the original pickup. The script just got more general — any pickup you add in Step 5 will be wired automatically.

Press Stop. Reset doesn't bring back collected pickups (Destroy is permanent within a session). Each fresh Play session starts with all pickups present because they're placed in Workspace, not spawned by script.

Step 5 — Add more pickups

The whole point of pickups is to scatter them across the obby. Now that the script is generic, more pickups = more coins.

  • Click CoinPickup in Explorer. Press Ctrl+D to duplicate. Drag the copy to a different spot on the walkway. Repeat 3–4 times.
  • For one of the duplicates, change its CoinValue attribute to 5. Change its BrickColor to something obviously rarer (Gold, Bright orange, or Really red). This is your "gold coin" — same script, different payout.

Press Play. Collect everything. Watch the counter. The gold coin pays 5; the regular ones pay 1.

Understand it

The Triggered event is the analog of Touched for prompts. Where Touched fires every time a body part collides, Triggered fires once per actual key press — much cleaner. No debounce needed because the player has to choose to interact.

The wirePickup function is a helper. By naming the logic and calling it from a loop, you keep the script readable. It also makes Stage 4's "spawn new pickups from a dropper" much easier — you'll just call wirePickup(newCoin) after creating each one.

The FindFirstChildWhichIsA("ProximityPrompt") is a defensive check. If you forgot to add the prompt to one of your pickups, the function bails out instead of crashing. Same idea as the SpawnLocation loop's GetAttribute filter — the script tolerates partially-built parts gracefully.

The CoinValue attribute pattern mirrors StageNumber. Two different mechanics (pad payouts and pickup payouts), same trick: data on the part, generic code in the script. As your tycoon grows, more mechanics will use more attributes (Cost, SpeedMultiplier, RespawnTime) — but each one fits this pattern.

Script anatomy

How this script wires every pickup it can find

The function does the work of wiring one pickup. The loop finds every CoinValue-tagged part in Workspace and calls the function on each one. New pickup tomorrow? Tag it, the script picks it up.

local function wirePickup(pickup)
local prompt = pickup:FindFirstChildWhichIsA("ProximityPrompt")
local value = pickup:GetAttribute("CoinValue")
if not prompt or not value then return end

prompt.Triggered:Connect(function(player)
if not player or not player:FindFirstChild("leaderstats") then return end
player.leaderstats.Coins.Value = player.leaderstats.Coins.Value + value
pickup:Destroy()
end)
end

for _, part in ipairs(workspace:GetDescendants()) do
if part:GetAttribute("CoinValue") then
wirePickup(part)
end
end
  1. Line 1Take one pickup and do all setup for it.

    Naming this as a function means it can be called from anywhere. Stage 4 (dropper) will call it after spawning a new coin part.

  2. Lines 2–4Defensive checks.

    Find the ProximityPrompt inside the pickup. Read its CoinValue. If either is missing, bail out — don't crash, don't wire half a pickup.

  3. Lines 6–10The Triggered event handler.

    Triggered already passes the player who pressed the key — no GetPlayerFromCharacter walk-up needed. Award the attribute's value, then Destroy the part to remove it from the game.

  4. Lines 13–17Scan all of Workspace for pre-placed pickups.

    GetDescendants walks the entire Workspace tree (deeper than GetChildren). That way you can group pickups inside a Folder named 'Pickups' if you want — the loop still finds them.

Try this

Learning beat

Try this

Three short experiments. Predict before you run, then test your guess.

Predict first

Add a CoinValue attribute (value 1) to your RestStop part. Don't add a ProximityPrompt to it. Press Play. Walk on the rest stop. Predict what happens. Then check Output — was there an error?

Compare

Change one pickup's HoldDuration in Properties from 0 to 3. Now compare collecting a 0-hold pickup vs a 3-hold one. Which feels right for a common pickup? Which would you save for a rare drop? Why does a hold time change the perceived value?

Connect

Right now you place pickups by hand. In Stage 4 you'll build a dropper that spawns new pickups every few seconds. Look at the wirePickup function — what part of the spawning loop will need to call it?

Test your stage

  • Press ▶ Play. Walk the planks to the Stage 4 yellow pad. Counter goes up by 4 (Stage 4's payout).
  • Walk near a coin pickup. "Collect" prompt appears. Press E. Coin disappears, counter ticks up by its CoinValue.
  • The gold (5-coin) pickup pays 5; regular ones pay 1.
  • Walked-past pickups stay until collected; collected ones don't come back this session.
  • Reset character. Collected pickups remain gone (they were destroyed). Walk back — only the un-collected ones remain.
  • Design check. Are the pickups visible on the walkway, but require a small detour or pause to grab? If they're directly on the safest path, they're free money. If they're impossible to grab without falling, they're frustrating. Aim for "I have to look up from the planks for a second."

If it breaks

  • No "Collect" prompt appears when I walk near the coin. The ProximityPrompt either isn't there or has Enabled = false. Open the pickup in Explorer — there should be a ProximityPrompt indented inside it.
  • Prompt appears but pressing E does nothing. The script's loop never wired this pickup. Most common cause: the pickup is missing the CoinValue attribute. The loop skips anything without it.
  • Pressing E gives me a coin but doesn't destroy the pickup. Re-check the pickup:Destroy() line in the script. If you wrote pickup.Destroy() (dot, not colon), Lua won't run it — colons are how you call methods on objects.
  • Pickups respawn when I press Play again. That's correct — they're placed in Workspace, so each Play session starts with all of them. If you want pickups to stay collected between sessions, you'd save state with DataStoreService (Stage 4).
  • The gold pickup pays 1 like all the others. You forgot to set its CoinValue attribute to 5. Click the gold pickup, Properties → Attributes — confirm CoinValue = 5, not 1.
  • Studio errors with Triggered is not a valid member of Part. You connected to Part.Triggered instead of ProximityPrompt.Triggered. Re-check that the connection is on the prompt object: prompt.Triggered:Connect(...).
Coach notes

The biggest pedagogical risk at Stage 3 is campers thinking the script defines the coin amount. The script defines the mechanic — the amount lives on the part. Walk every camper through the difference by changing a pickup's CoinValue attribute (no script edit) and seeing the payout flip.

  • Common failure: campers duplicate the pickup (Ctrl+D) and forget the attribute was on the original. Both copies should keep the attribute (Ctrl+D copies attributes). If they re-add the prompt manually, they sometimes leave the attribute off.
  • Some campers will want to animate the coin (rotation, bobbing). Encourage it as a stretch — but warn that adding a while true do to spin the coin without Anchored = true will make it fall.
  • 45 minutes total. Plank build + checkpoint takes 10, pickup recipe + prompt + attribute takes 10, script + scattering pickups takes 25.