1. 背景
学习 Move 基础语法以来,自我感觉需要一个自行设计的小项目练手。
现设计一个卡牌对战小游戏功能如下:
css
- [ ] 玩家每次参与对战获取一定对血量和行动值,回合制对战,直到一方血量归 0,游戏结束
- [ ] 卡牌拥有攻击力和防御力,卡牌参与对战后不可再作他用
- [ ] 每回合结束,双方卡牌随机变换攻击力与防御力,全靠运气
- [ ] 玩家每次行动消耗行动值,防守增加行动值
- [ ] 其他
2. 合约部分
2.1 初始化函数
需要两个共享对象记录卡牌与所有的对局,分别命名为CardRecord
, BattleRecord
rust
fun init(ctx: &mut TxContext) {
let battle_record = BattleRecord {
id: object::new(ctx),
battles: vector::empty<ID>(),
};
let card_record = CardRecord {
id: object::new(ctx),
cards: vector::empty<ID>(),
};
share_object(battle_record);
share_object(card_record)
}
2.2 铸造卡牌
rust
fun mint_card(clock:&Clock,ctx: &mut TxContext) : Card {
let (attack, defense) = random_strength_clock(clock);
Card {
id: object::new(ctx),
attack,
defense,
}
}
这里用到随机数,有几种生成方式:
- 使用
CLOCK
或者交易摘要生成; - 使用天气预言机;
简单点就使用CLOCK
获取时间戳作为随机数。
rust
fun random_strength_clock(clock: &Clock) :(u64, u64){
let ms = clock::timestamp_ms(clock);
let random_attack = ms % MAX_ATTACK_DEFEND_STRENGTH;
if (random_attack == 0) {
random_attack = MAX_ATTACK_DEFEND_STRENGTH / 2;
};
(random_attack, MAX_ATTACK_DEFEND_STRENGTH - random_attack)
}
2.3 创建对局
结构体定义
rust
struct Battle has key,store {
id: UID,
name: String,
status: u64, // 记录对局状态
cards: Table<address, Card>, // 对战人卡片
players: vector<address>, // 玩家
player_status: Table<address, PlayerStatus>, // 双方状态
moves: Table<address, u64>, // 当前回合行动,判断是否回合结束
winer: Option<address>,
}
2.4 行动
对应函数public entry fun move_choice(choice: u64, battle: &mut Battle, ctx: &mut TxContext)
当双方行动结束时结算当前玩家状态,对应函数fun resolve_battle(battle:&mut Battle,ctx: &TxContext)
2.5 部署到测试网
记录以下三个值
bash
TESTNET_CARD_PACKAGE_ID = "0x43c21577794c10f7f36d3269d50736c45f9dc4d0c77e3c7d0f219b0a3fd0ae4d";
CARD_RECORD: string = "0x7d6444bffd59a7b348613637422a1f335305204e4fea5be1d86d325c3eaf108b";
BATTLE_RECORD = "0x2b1b5fc902bf675dc6acf48b61a13a27989383c4f9fba460c03c103c41faf800";
3. 页面部分
3.1 如何获取到对局中的玩家状态
思路:全剧共享对象BattleRecord
获取到Battle_id
,拿到当前对象。
接下来要用到动态字段获取才能知道玩家状态数据,这个过程需要多次查询请求。
jsx
// 获取对局对象
const { battleData } = useSuiClientQuery("getObject", {
id: battleId ? battleId : "",
options: {
showContent: true,
showOwner: true,
},
});
// 通过 table_id 获取内容
const { players } = client.getDynamicFields({
parentId: battleData.player_status.fields.id.id,
})
4. 试玩
4.1 铸造卡牌
打开页面,首先连接钱包登陆。 点击Mint Card For Free
铸造卡牌,稍等一会即可在All Your Cards
区域看到你的卡牌。
4.2 创建对局
点击Begin Game
跳转到新页面,输入房间名(仅英文)创建对局,此时默认使用你的第一张卡牌放入对局中(此卡牌已转移所有权,不再属于你)。
点击Join
可以进入房间
4.2 另一玩家加入对局
另准备一个钱包地址,Mint Card
--> Begin Game
--> Join
,即可加入目标房间进行战斗,默认使用你的第一张卡牌。
4.3 行动
接下来双方分别进行攻击和防御操作,直到一方血量归零,决出胜负为止。
星航计划 QQ群:79489587