Skip to main content

Coins

How can I make some coins that the hero can pick up by walking into them?

Games often involve picking things up by touching them. Coins, gems, shards, powerups, health packs, vegetables and more. Sometimes they have good effects, sometimes bad. All of these can be implemented in a similar way.

Step 1: Define a Coin

In this example, we will define a coin which can be worth different amounts. Bigger amounts will be bigger visually.

pub fn coin.Coin(pos, amount=1) {
use body=this, radius=(0.25 + 0.1 * amount), shape=Circle, color=#fb0
Body(pos=)
PolygonSprite(shading=0.5)
PolygonCollider(category=Category:Coin, sense=Category:All)

// ...
}
  • We have defined a specific category for coins, Category:Coin, so that we can easily apply different rules to coins than we do to other objects in the game.

  • The sense=Category:All parameter for PolygonCollider means the coin will not physically block anything. The hero will walk right through it and will not lose any momentum in the process.

Step 2: Handle collisions with the Hero

When the coin collides with the hero, we want to increase the hero's coin count and then remove the coin from the game. We also want to add some visual effects to make it feel more satisfying.

on BeforeCollide that {
if that.Category.Overlaps(Category:Hero) {
that.Owner.NumCoins += amount

TextSpark(
"+$" + amount, radius=1, velocity=@(0, -1), dissipate=2s, layer=1,
fade=1, stroke=0.2, taper=0,
)
repeat 5 { Spark(speed=10, luminous=1, glare=0.1, bloom=3, dissipate=0.5s) }
Expire
}
}
  • Touching a coin increases the hero's NumCoins property by the amount of the coin. We will define this property in the next step.
  • The TextSpark creates floating text that rises up and fades away, showing the player how many coins they picked up.
  • The Spark creates a burst of particles to make the coin pickup feel more satisfying.

Step 3: Count coins

We will create a property on the player called NumCoins to keep track of how many coins they have collected.

pub prop owner.NumCoins = 0

We are using a property because a property automatically sends signals whenever it changes, which will allow us to update the display of the coin count automatically.

Step 4: Display the coin count

We want to display the total number of coins at the top of the screen.

SpawnEachPlayer owner {
TopContent {
InsetPanel {
with NumCoins {
"You have: $" + NumCoins
}
}
}
// ...
}
  • We put this block inside SpawnEachPlayer so that in a multiplayer game, each player will only see their own coin count displayed on their screen.

  • The with block reruns its block of code every time the NumCoins property changes, keeping the display up to date with the current number of coins.

Step 5: Spawn some coins

Now we can spawn some coins in the world for the hero to pick up. In this example, we will just spawn 50 coins at random positions with random amounts.

repeat 50 {
Spawn coin {
Coin(
pos=@(20*SignedRandom, 20*SignedRandom),
amount=Floor(1 + 3*Random)
)
}
}

Full Code Listing

Don't forget, coins are just one example. You can use the same pattern to create other collectibles, powerups, or even hazards that the player can interact with by touching them.

pub tangible category Category:Hero
pub tangible category Category:Coin

pub prop owner.NumCoins = 0

pub game fn World.Main() {
SolidBackground(#333)
Camera(@(0, 0), radius=20)

BottomContent {
InsetPanel { "Arrow keys to move" }
}


repeat 50 {
Spawn coin {
Coin(
pos=@(20*SignedRandom, 20*SignedRandom),
amount=Floor(1 + 3*Random)
)
}
}

SpawnEachPlayer owner {
TopContent {
InsetPanel {
with NumCoins {
"You have: $" + NumCoins
}
}
}
Subspawn unit {
Hero
}
}
}

pub fn unit.Hero([owner]) {
use body=this, shape=Rectangle(width=2, height=2)
Body(pos=@(0, 0))
PolygonSprite(color=#0fb)
PolygonCollider(category=Category:Hero)

on BeforePhysics {
Move(0.25 * Joystick)
}
}

pub fn coin.Coin(pos, amount=1) {
use body=this, radius=(0.25 + 0.1 * amount), shape=Circle, color=#fb0
Body(pos=)
PolygonSprite(shading=0.5)
PolygonCollider(category=Category:Coin, sense=Category:All)

on BeforeCollide that {
if that.Category.Overlaps(Category:Hero) {
that.Owner.NumCoins += amount

TextSpark(
"+$" + amount, radius=1, velocity=@(0, -1), dissipate=2s, layer=1,
fade=1, stroke=0.2, taper=0,
)
repeat 5 { Spark(speed=10, luminous=1, glare=0.1, bloom=3, dissipate=0.5s) }
Expire
}
}
}
Open in Editor