RPG 构建基础 - Encode ClubSui 系列 #5

在这六个教学视频中的第五个视频中,Shayan 将介绍在Sui 上创建角色扮演游戏的基础知识。

RPG 构建基础 - Encode ClubSui 系列 #5

Encode ClubSui 系列的第五个视频中,我们将展示如何为角色扮演游戏(RPG)创建角色和物品,以及如何让它们互动。

Sui 基金会与编码俱乐部(Encode Club)合作,提供了六个以开发者为中心的系列视频。该系列视频从Sui 的基础知识到构建智能合约和在Sui 中处理对象的教程。

学习重点

由于Sui 以对象为中心的编程模型及其可扩展性,Sui 有望成为第一个真正为 Web3 提供 Web2 体验的区块链。这种体验的前沿包括游戏。游戏编程性质复杂,同时需要强大的基础设施来确保玩家获得无缝体验。得益于上述两点,Sui 可以应对这一挑战。

让我们看看Sui 中链上 RPG 的编码示例。以下示例改编自Sam Blackshear 的 hero.move 代码

物品

/// 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,
}

上面的代码定义了我们的游戏角色。从它的字段中可以看出,这个 "英雄 "与 RPG 游戏中的其他角色类似。它有命中点(HP)、经验和库存。

/// 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,
}

上面的代码显示了我们的英雄之剑。请注意,这把剑具有密钥和存储能力。回顾一下本系列前面的课程,key 意味着它是一个可拥有的资产,可以存在于顶级存储空间中。Move 这类对象也可以从外部 API 访问,从而创造了Sui独特的跨多个游戏使用物品的可能性。而 store 则表示该对象可以自由封装和转移。

/// 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,
}

以上,我们定义了游戏中的野猪、非玩家角色(NPC)或敌人。与其他同类型游戏类似,我们可以为英雄创建 NPC,让他战斗并获得经验,或购买物品并接受任务。

行动

/// 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);
}

上面代码中的动作描述了杀死功能。在高层次上,该函数首先会检查英雄和野猪是否属于同一个游戏实例。然后,英雄和野猪进行决斗,并检查确保英雄的 HP 不能为零。决斗结束后,英雄获得的经验值与野猪的经验值成正比,英雄之剑的强度增加 1(如果英雄使用的是剑)。最后,函数会发出一个事件 BoarSlayEvent。Move 中的事件可让索引器跟踪链上操作,这是实现普遍认可的对象状态的重要手段。

上面的代码示例简要摘录了 Sam 的 hero.move 代码。该代码为Sui 上的游戏开发者提供了一个宝贵的示例,由于它是开源的,因此可以自由地 fork 该 repo 并开发自己的游戏!

观看整个系列

  1. Sui 是什么?
  2. 智能合约
  3. 创建对象和 NFT
  4. 动态字段和集合
  5. RPG 构建基础
  6. 在区块链上部署游戏