Repository navigation
Pickups
Berke edited this page Oct 10, 2026
·
1 revision
Pickups are plain entity scripts that compare distances every frame. For a nicer look, add BobAndSpin to the same Entity.
Collected items are recorded in the shared Global table so any other script (a door, the HUD,
an exit) can react:
| Key | Meaning |
|---|---|
Global.coins |
Number of coins collected |
Global.keys[name] |
true once the key called name has been collected |
Attach to: the item Entity.
-- Scripts/Pickups/Pickup.lua (entity script)
public Entity player = nil
public enum(Health, Coin, Key) kind = Health
public number amount = 25
public string keyName = "red"
public number pickupRadius = 14
local KIND_HEALTH, KIND_COIN, KIND_KEY = 0, 1, 2
local transform
-- Returns true if the pickup was used up. It stays in the world if it wasn't.
local function Apply()
if kind == KIND_HEALTH then
local health = player:GetScript("Health")
if not health.isValid or health.currentHealth >= health.maxHealth then
return false -- already at full health, leave it for later
end
health:Heal(amount)
Debug.Print("+" .. amount .. " health")
return true
elseif kind == KIND_COIN then
Global.coins = (Global.coins or 0) + amount
return true
elseif kind == KIND_KEY then
Global.keys = Global.keys or {}
Global.keys[keyName] = true
Debug.Print("Picked up the " .. keyName .. " key")
return true
end
return false
end
function Start()
transform = entity.transform
if player == nil then
Debug.LogWarning("Pickup " .. entity.name .. " has no player assigned")
end
end
function Update()
if player == nil or not player.isValid then return end
local p = player.transform.position
local me = transform.position
local dx, dz = p.x - me.x, p.z - me.z
-- Flat distance, so a height difference doesn't count against the radius.
if math.sqrt(dx * dx + dz * dz) > pickupRadius then return end
if Apply() then
local sound = entity.audioSource
if sound ~= nil then sound:Play() end
entity:Destroy()
end
endNotes
- Health pickups are only consumed if the player actually needs the health.
-
Global.coins = (Global.coins or 0) + amountworks even before anything has created the counter, since a missing value isnilandnil or 0is0. - Destroying the Entity also removes its
AudioSource, so the sound may be cut off. If that happens, play the pickup sound from anAudioSourceon the player instead. - Enum options are numbered from
0in the order they appear in the annotation, which is why theKIND_...constants matchenum(Health,Coin,Key).
Attach to: a UI Entity with a UIText component.
-- Scripts/Pickups/CoinCounter.lua (entity script)
local label
local shown = -1
function Start()
label = entity.uiText
if label == nil then
Debug.LogError("CoinCounter: " .. entity.name .. " has no UIText")
return
end
Global.coins = Global.coins or 0
end
function Update()
if label == nil then return end
local coins = Global.coins or 0
-- Only touch the text when the number changes.
if coins ~= shown then
shown = coins
label.text = "Coins: " .. math.floor(coins)
end
endNotes
- Writing UI text every frame works, but only assigning it when the value changes is cheaper and is a good habit.
-
math.floormakes25.0print as25.