In the fifth video of Encode Club’s Sui series, we show how to create characters and items, and how to make them interact, for a role playing game (RPG).

The Sui Foundation partnered with Encode Club to offer a series of six developer-focused videos. This series will range from the basics of Sui to tutorials about building smart contracts and working with objects in Sui.

Learning Highlights

Due to Sui's object-centric programming model, as well as its scalability, Sui promises to be the first blockchain to truly deliver a web2 experience to web3. The forefront of this experience includes gaming. Games are both complex in nature to program, as well as requiring robust infrastructure to ensure a seamless experience for players. Thanks to the aforementioned two points, Sui is up to the challenge.

Let’s look at a coding example for an on-chain RPG in Sui. The following example is adapted from Sam Blackshear’s hero.move code.

The Objects

/// Our hero!
struct Hero has key, store {
id: UID,
/// Hit points. If they go to zero, the hero can't do anything
hp: u64,
/// Experience of the hero. Begins at zero
experience: u64,
/// The hero's minimal inventory
sword: Option<Sword>,
/// An ID of the game user is playing
game_id: ID,
}

The above code defines our playable character. As you can see from its fields, this Hero is comparable to other characters in RPGs. It has hit points (HP), experience, and an inventory.

/// The hero's trusty sword
struct Sword has key, store {
id: UID,
/// Constant set at creation. Acts as a multiplier on sword's strength.
/// Swords with high magic are rarer (because they cost more).
magic: u64,
/// Sword grows in strength as we use it
strength: u64,
/// An ID of the game
game_id: ID,
}

The above code shows our hero’s sword. Note that this sword has the key and store abilities. To recap from previous lessons in this series, key means it’s an ownable asset, and can exist in top-level storage. Move objects in this category can also be accessed from external APIs, creating Sui’s unique possibility of using items across multiple games. And store means that this object is freely wrappable and transferable.

/// A creature that the hero can slay to level up
struct Boar has key {
id: UID,
/// Hit points before the boar is slain
hp: u64,
/// Strength of this particular boar
strength: u64,
/// An ID of the game
game_id: ID,
}

Above, we define a boar, non-playable character (NPC) or enemy in our game. Similar to other games of this genre, we can create NPCs for our Hero to fight and gain experience, or shop for items and receive quests.

The Action

/// Slay the `boar` with the `hero`'s sword, get experience.
/// Aborts if the hero has 0 HP or is not strong enough to slay the boar
public entry fun slay(
game: &GameInfo, hero: &mut Hero, boar: Boar, ctx: &TxContext
) {
check_id(game, hero.game_id);
check_id(game, boar.game_id);
let Boar { id: boar_id, strength: boar_strength, hp, game_id: _ } = boar;
let hero_strength = hero_strength(hero);
let boar_hp = hp;
let hero_hp = hero.hp;
// attack the boar with the sword until its HP goes to zero
while (boar_hp > hero_strength) {
// first, the hero attacks
boar_hp = boar_hp - hero_strength;
// then, the boar gets a turn to attack. if the boar would kill
// the hero, abort--we can't let the boar win!
assert!(hero_hp >= boar_strength , EBOAR_WON);
hero_hp = hero_hp - boar_strength;
};
// hero takes their licks
hero.hp = hero_hp;
// hero gains experience proportional to the boar, sword grows in
// strength by one (if hero is using a sword)
hero.experience = hero.experience + hp;
if (option::is_some(&hero.sword)) {
level_up_sword(option::borrow_mut(&mut hero.sword), 1)
};
// let the world know about the hero's triumph by emitting an event!
event::emit(BoarSlainEvent {
slayer_address: tx_context::sender(ctx),
hero: object::uid_to_inner(&hero.id),
boar: object::uid_to_inner(&boar_id),
game_id: id(game)
});
object::delete(boar_id);
}

The action shown in the above code describes the slay function. At a high level, this function first checks to make sure that the Hero and the Boar both belong to the same game instance. Then the duel between the Hero and the Boar takes place, with a check to ensure that the Hero’s HP cannot reach zero. Once the duel is complete, the hero gains experience proportional to the Boar, and the Hero’s Sword grows in strength by one (if the Hero is wielding a Sword). Finally, the function emits an event, BoarSlayEvent. Events in Move let indexers track on-chain actions, an important means of achieving a universally recognized object state.

The code examples above give a brief excerpt of Sam’s hero.move code. This code serves as a valuable example for game builders on Sui and, as it’s open source, feel free to fork the repo and build your own game!

Watch the Whole Series

  1. What's Sui?
  2. Smart Contracts
  3. Creating Objects and NFTs
  4. Dynamic Fields and Collections
  5. RPG Building Basics
  6. Deploy a Game to the Blockchain
Author

Sam Blackshear

Co-Founder, CTO, Mysten Labs, Creator of Move Language

CTO of Mysten Labs and inventor of Move language. Former Principal Engineer at Meta.

Read more like this

How to get a SuiNS Name

Walk through the steps to purchase and register SuiNS names.

3min read
Adeniyi Abiodun

Announcing Sui Tokenomics

Sui’s economic model has been designed at the frontier of blockchain economic and incentives research.

7min read
Sui Foundation

Recap 8/3 Sui AMA: Technical Writing with Randall & Clay

This AMA covers technical writing with members of Mysten Labs.

9min read
Sui Foundation

Sui Bridge Goes Live on Testnet with Incentive Program

Help test the Sui Bridge today by interacting with the testnet implementation and participating in the bug bounty.

5min read
Sui Foundation

Move 2024: Macro Functions Guide

Move 2024 beta edition now gives developers the ability to replace common loops with macro functions.

11min read
Sam Blackshear

Access Crypto Market Data APIs on Sui with Birdeye

Birdeye's APIs and WebSockets let builders integrate real-time crypto market data into their DeFi apps.

5min read
Sui Foundation