SUI Move官方示例合约实践——游戏类:英雄游戏(hero)
Hero
) 用 魔剑(Sword
) 杀死凶猛的 野猪(Boar
),并用 血瓶(Potion
) 治疗自己的故事。new_game
) 新游戏,游戏的创建者即为当前游戏管理员。acquire_hero
),该合约接口会创建 剑(create_sword
) 及 英雄(create_hero
)send_potion
) 以及为玩家 创建具有特定属性的野猪(send_boar
)slay
) 来获得经验值,以及为自己进行 补血(heal
)、 配备新剑(equip_sword
)、 解除装备(remove_sword
)https://github.com/MystenLabs/sui/blob/main/sui_programmability/examples/games/sources/hero.move
合约较长,这里仅介绍一下对外的方法
new_game
)新游戏GameInfo
对象,所有玩家均能访问GameAdmin
发送给游戏创建者,用户后续为玩家 发送血槽(send_potion
) 以及为玩家 创建具有特定属性的野猪(send_boar
)时的权限验证 /// Anyone can create run their own game, all game objects will be
/// linked to this game.
public entry fun new_game(ctx: &mut TxContext) {
create(ctx);
}
/// Create a new game. Separated to bypass public entry vs init requirements.
fun create(ctx: &mut TxContext) {
let sender = tx_context::sender(ctx);
let id = object::new(ctx);
let game_id = object::uid_to_inner(&id);
transfer::freeze_object(GameInfo {
id,
admin: sender,
});
transfer::transfer(
GameAdmin {
game_id,
id: object::new(ctx),
boars_created: 0,
potions_created: 0,
},
sender
)
}
acquire_hero
)create_sword
) 及 英雄(create_hero
) public entry fun acquire_hero(
game: &GameInfo, payment: Coin<SUI>, ctx: &mut TxContext
) {
let sword = create_sword(game, payment, ctx);
let hero = create_hero(game, sword, ctx);
transfer::public_transfer(hero, tx_context::sender(ctx))
}
/// It all starts with the sword. Anyone can buy a sword, and proceeds go
/// to the admin. Amount of magic in the sword depends on how much you pay
/// for it.
public fun create_sword(
game: &GameInfo,
payment: Coin<SUI>,
ctx: &mut TxContext
): Sword {
let value = coin::value(&payment);
// ensure the user pays enough for the sword
assert!(value >= MIN_SWORD_COST, EINSUFFICIENT_FUNDS);
// pay the admin for this sword
transfer::public_transfer(payment, game.admin);
// magic of the sword is proportional to the amount you paid, up to
// a max. one can only imbue a sword with so much magic
let magic = (value - MIN_SWORD_COST) / MIN_SWORD_COST;
Sword {
id: object::new(ctx),
magic: math::min(magic, MAX_MAGIC),
strength: 1,
game_id: id(game)
}
}
/// Anyone can create a hero if they have a sword. All heroes start with the
/// same attributes.
public fun create_hero(
game: &GameInfo, sword: Sword, ctx: &mut TxContext
): Hero {
check_id(game, sword.game_id);
Hero {
id: object::new(ctx),
hp: 100,
experience: 0,
sword: option::some(sword),
game_id: id(game)
}
}
send_potion
)以及创建具有特定属性的野猪(send_boar
) /// Admin can create a potion with the given `potency` for `recipient`
public entry fun send_potion(
game: &GameInfo,
potency: u64,
player: address,
admin: &mut GameAdmin,
ctx: &mut TxContext
) {
check_id(game, admin.game_id);
admin.potions_created = admin.potions_created + 1;
// send potion to the designated player
transfer::public_transfer(
Potion { id: object::new(ctx), potency, game_id: id(game) },
player
)
}
/// Admin can create a boar with the given attributes for `recipient`
public entry fun send_boar(
game: &GameInfo,
admin: &mut GameAdmin,
hp: u64,
strength: u64,
player: address,
ctx: &mut TxContext
) {
check_id(game, admin.game_id);
admin.boars_created = admin.boars_created + 1;
// send boars to the designated player
transfer::transfer(
Boar { id: object::new(ctx), hp, strength, game_id: id(game) },
player
)
}
slay
)来获得经验值和升级剑 /// 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);
}
英雄的攻击力算法
计算公式是:经验×生命值+剑的攻击力
,如果英雄的生命值为0或者没有剑,英雄的攻击力直接为0,将无法进行战斗。剑的攻击力还包括跟购买金额成正比的魔法加成。
/// Strength of the hero when attacking
public fun hero_strength(hero: &Hero): u64 {
// a hero with zero HP is too tired to fight
if (hero.hp == 0) {
return 0
};
let sword_strength = if (option::is_some(&hero.sword)) {
sword_strength(option::borrow(&hero.sword))
} else {
// hero can fight without a sword, but will not be very strong
0
};
// hero is weaker if he has lower HP
(hero.experience * hero.hp) + sword_strength
}
/// Strength of a sword when attacking
public fun sword_strength(sword: &Sword): u64 {
sword.magic + sword.strength
}
循环计算野猪生命值-英雄攻击力
以及英雄生命值-野猪攻击力
,当野猪生命值≤英雄攻击力时,则英雄获胜;反之当英雄生命值<野猪攻击力时,则英雄失败。
// 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;
};
当英雄持有剑,每消灭一次野猪,剑的力量将会增强1。
if (option::is_some(&hero.sword)) {
level_up_sword(option::borrow_mut(&mut hero.sword), 1)
};
fun level_up_sword(sword: &mut Sword, amount: u64) {
sword.strength = sword.strength + amount
}
heal
)、配备新剑(equip_sword
)、 解除装备(remove_sword
) /// Heal the weary hero with a potion
public fun heal(hero: &mut Hero, potion: Potion) {
assert!(hero.game_id == potion.game_id, 403);
let Potion { id, potency, game_id: _ } = potion;
object::delete(id);
let new_hp = hero.hp + potency;
// cap hero's HP at MAX_HP to avoid int overflows
hero.hp = math::min(new_hp, MAX_HP)
}
/// Add `new_sword` to the hero's inventory and return the old sword
/// (if any)
public fun equip_sword(hero: &mut Hero, new_sword: Sword): Option<Sword> {
option::swap_or_fill(&mut hero.sword, new_sword)
}
/// Disarm the hero by returning their sword.
/// Aborts if the hero does not have a sword.
public fun remove_sword(hero: &mut Hero): Sword {
assert!(option::is_some(&hero.sword), ENO_SWORD);
option::extract(&mut hero.sword)
}
别名 | 地址 | 角色 |
---|---|---|
Jason | 0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a |
游戏创建者、管理员 |
Alice | 0x2d178b9704706393d2630fe6cf9415c2c50b181e9e3c7a977237bb2929f82d19 |
游戏玩家 |
Bob | 0xf2e6ffef7d0543e258d4c47a53d6fa9872de4630cc186950accbd83415b009f0 |
游戏玩家 |
export JASON=0x5c5882d73a6e5b6ea1743fb028eff5e0d7cc8b7ae123d27856c5fe666d91569a
export ALICE=0x2d178b9704706393d2630fe6cf9415c2c50b181e9e3c7a977237bb2929f82d19
export BOB=0xf2e6ffef7d0543e258d4c47a53d6fa9872de4630cc186950accbd83415b009f0
切换到Jason账号
$ sui client publish --gas-budget 100000000
Transaction Digest: DRKGSzaAGRrBLgMb6kpAdANyqgDKiyubhVyvUysRFM5i
export PACKAGE_ID=0xdd885f1dd16dcfbcda184e19c0d1d362eb81e29c378bd3d24a38fe834b2b268b
切换到Jason
sui client call --function new_game --package $PACKAGE_ID --module hero --gas-budget 10000000
#PACKAGE_ID::hero::GameInfo
export GAME_INFO=0x3d26abc88995856b3556f15e9e32a6ea4afc944f943e21172f1ed8c3c1e72053
#PACKAGE_ID::hero::GameAdmin
export GAME_ADMIN=0x9fc8129b82a016244a40a862d7a4042c82c1ddfad7390761156ccb6ecb4a0732
sui client object $GAME_INFO
sui client object $GAME_ADMIN
切换到Alice,购买的最低金额为100
export COIN_ALICE=0xed8011355d3ba606f65261d6afa89b432cc26ec3cf7b86839078da05648c9918 # 含有800
sui client call --function acquire_hero --package $PACKAGE_ID --module hero --args $GAME_INFO $COIN_ALICE --gas-budget 10000000
# PACKAGE_ID::hero::Hero
export HERO=0x5db6138c68a64be3ad503855fa3fde30d4e313be82537185852aa39b9e92239f
sui client object $HERO
切换到Jason
export HP=10
export STRENGTH=10
sui client call --function send_boar --package $PACKAGE_ID --module hero --args $GAME_INFO $GAME_ADMIN $HP $STRENGTH $ALICE --gas-budget 10000000
export BOAR=0xc8155205f5e598480fc47d3ecb9727a3f00b82a968f6940e2b3cba082501d4f3
sui client object $BOAR
切换到Alice,执行攻击操作,一轮攻击后,野猪战败,英雄收货经验值和剑攻击力的增强。
sui client call --function slay --package $PACKAGE_ID --module hero --args $GAME_INFO $HERO $BOAR --gas-budget 10000000
0->10
1->2
切换到Jason
export POTENCY=50
sui client call --function send_potion --package $PACKAGE_ID --module hero --args $GAME_INFO $POTENCY $ALICE $GAME_ADMIN --gas-budget 10000000
export POTION=0x561c37b3d03381d1c0e9c4a5182c32164120c4e4d036e47efce1681282d0d67d
sui client object $POTION
切换到Alice
sui client call --function heal --package $PACKAGE_ID --module hero --args $HERO $POTION --gas-budget 10000000
可见玩家生命值从90提升到140
sui client object $HERO
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!