In the previous RayLib 2D Challenge episode, animated shiny gold coins were spinning nicely. They were loaded from disk using a texture atlas, so adding animated gems or other objects would be ridiculously easy. But, poor Scarfy couldn't collect the coins, because the coin collection code hadn't been written yet. All he could do was push the coins over the cliff's edge.

Today, I'm going to add the missing code so that Scarfy can finally collect the coins, complete with a satisfying clinking sound.

Enabling Interaction Between Objects

How do we enable objects in the game world to interact beyond the basic physics simulation? The key is the physics engine's contact callback:

typedef std::function<void (PhysicsObject *thisObject, PhysicsObject *otherObject,
	b2Contact *contact, bool contactBegin)> POContactHandler;

A "contact handler" is called when a physics object starts or stops touching another object. This is how we can add custom behaviour, enabling objects to interact with each other in the game world.

Adding the contact handler to Scarfy sounds like the most logical thing to do. After all, Scarfy is the one that will be collecting the coins. However, I'm going to do it the other way round. That's because Scarfy will be interacting with a lot of objects, so his contact handler would have to check what object type it encountered, and call the correct routine.

By contrast, the coin knows that it's a collectable object, and that actors like Scarfy would like to collect it. So, if an actor touches it, then the coin can tell that actor to "collect me if you can," like this:

void collectableTouched(PhysicsObject *thisObject, PhysicsObject *otherObject, 
        b2Contact *contact, bool contactBegin) {
    if(!otherObject) {
        // The other object cannot interact with this object
        return;
    }
    Collectable *thisCollectable = static_cast<Collectable *>(thisObject->getActor());
    Actor *otherActor = otherObject->getActor();
    if(!otherActor) {
        // No actor touched this object
        return;
    }

    // Tell the other object to collect this (if it can)
    otherActor->collect(thisCollectable);
}

Actors that have a wallet will then call the coin's own collect() method to collect their winnings:

bool Actor::collect(Collectable *collectable) {
	if(walletValue != ACTOR_NO_WALLET) {
		walletValue += collectable->collect();
		return true;
	} 
	
	return false;
}

The Collectable's own collect() method, starts the coin collect animation and plays the collection sound (provided that they exist):

int Collectable::collect() {
    if(state != CS_AVAILABLE) {
        // This item has already been collected
        return 0;
    }

    state = CS_COLLECTING;

    if(collectSound) {
        collectSound->Play();
    }

    return itemValue;
}

Displaying the Coin Count

Collecting coins is fun, but sooner or later you'll want to know how much is in your wallet. How much gold do you have?

This is where a display overlay comes in. A display overlay is drawn over the top of the game to display useful information to the player(s). Here's the code to display the "gold count" in the top right-hand corner of the screen:

void GameOverlay::draw(const Scene &scene) {
    std::shared_ptr<const Actor> player = 
        std::dynamic_pointer_cast<const Actor>(scene.getPlayerAvatar());
    
    if(player) {
        Font titleFont = GetFontDefault();

        // Display the player's gold
        const char *goldText = TextFormat("Gold: %d", player->getWalletValue());
        raylib::Vector2 goldTextDim = MeasureTextEx(
            titleFont, goldText, GOLDTEXT_FONT_SIZE, GOLDTEXT_FONT_SPACING); 
        
        int screenWidth = GetScreenWidth();
        raylib::Vector2 goldTextPos(
            (float)(screenWidth - goldTextDim.GetX() - GOLDTEXT_X_OFFSET), 
            (float)GOLDTEXT_Y_OFFSET);
	    ::DrawTextEx(titleFont, goldText, goldTextPos, 
            GOLDTEXT_FONT_SIZE, GOLDTEXT_FONT_SPACING, GOLDTEXT_COLOUR);
    }
}

NOTE: I created a separate DisplayOverlay class to help keep the game engine and actual game code separate. The DisplayOverlay code defines the API to use an overlay, while the GameOverlay does the actual drawing.

All Done!

Scarfy can now run around collecting the coins, and we can see how much thanks to the overlay. Clink, clink clink!

Scarfy Collecting Coins

Download the Source Code

Click here to download the code.