搭建多人协同怪物讨伐
构建一个多名成员攻击同一只怪物、并在其生命值降到 0 之前持续共享结果的实时讨伐玩法。Webspace 的通用 shared-resource 处理器会在服务器端统一处理攻击、生命值变化和按行动发放的奖励。
开始之前
- 需要部署架构和 API 的权限。
- 必须向要使用实时功能的成员授予
send和receive权限。 - 将讨伐目标的创建 API 配置为仅管理员可用。
从完成的架构开始
下载共享资源游戏架构(.sfn)中包含本文使用的三张表的列与权限,以及 shared-resource 处理器设置。 所有语言版本的文档共用此文件,文件中的表和列说明均为英文。
- 下载文件,上传到团队文件夹或个人文件夹,然后用架构编辑器打开。
- 在
API 构建的部署设置中确认数据库标识符。为避免默认值resource_game与现有数据库重复,请改为monster_raid_team_a这样的新标识符。 - 检查权限和处理器设置后,部署架构。
此文件是共享资源后端结构示例。由于 includeClient 为 false,不会自动生成游戏界面,也不包含初始怪物数据。需要另外制作使用下方 API 和 WebSocket 事件的界面,并创建讨伐目标。
将数据拆分为三张表
共享资源结构将以下三类数据分开存放。
| 表 | 存储内容 |
|---|---|
game_resources | 怪物代码、状态、当前与最大生命值、版本和奖励物品 |
game_actions | 行动 ID、发起攻击的成员、实际伤害、结果生命值和奖励数量 |
game_inventory | 各成员的物品和累计数量 |
game_actions 的行动 ID 用于区分重试。即使再次发送同一个行动 ID,生命值和奖励也不会被重复计算。
设置实时处理器
开启实时功能,并将事件处理器选为 shared-resource。如果使用默认表名,处理器设置的结构如下。
{
"resourcesTable": "game_resources",
"actionsTable": "game_actions",
"inventoryTable": "game_inventory",
"actionPower": 1,
"rewardPerAction": 1,
"maxClientAmount": 1,
"broadcast": "namespace"
}
broadcast 为 namespace 时,连接到同一个 Webspace 实时命名空间的客户端会一起收到结果事件。为 actor 时,只向发起行动的成员发送结果。
创建讨伐目标
以管理员权限调用 game_resources/create 创建怪物。
{
"code": "RAID-1",
"kind": "monster",
"status": "active",
"current_value": 10000,
"max_value": 10000,
"version": 0,
"reward_item_code": "monster-core"
}
打开界面时,从 game_resources 的查询 API 读取当前生命值和版本。新建连接或连接恢复后,再次查询 REST API,即可以当前服务器状态为准校正界面。
通过 WebSocket 发送攻击
已登录的成员订阅实时连接后,发送 resource-game.act 事件。
{
"type": "webspace:send",
"data": {
"dbName": "monster_raid_team_a",
"event": "resource-game.act",
"payload": {
"actionId": "attack-00000001",
"resourceCode": "RAID-1",
"amount": 1
}
}
}
dbName 使用部署时指定的 数据库标识符。
actionId 由英文字母、数字、_ 和 - 组合而成,长度为 8~80 个字符。省略 amount 时为 1;发送值时,请使用处理器 maxClientAmount 范围内的整数。
服务器处理完成后会发送 resource-game.action-applied。
{
"actionId": "attack-00000001",
"resourceId": 1,
"currentValue": 9999,
"version": 1,
"rewardQuantity": 1,
"duplicate": false
}
界面只有在收到此结果后才更改生命值。客户端直接发送 resource-game.action-applied 的请求会被拒绝。
显示生命值和奖励
- 确认
resourceId是当前正在查看的怪物。 - 确认
version大于上一次的结果。 - 用
currentValue更新生命值显示。 currentValue为 0 时,显示共同击败完成状态。- 个人物品从
game_inventory/list重新查询。
对 game_inventory 应用只能读取成员本人数据的所有者权限。不要仅凭结果事件中的 rewardQuantity 推测其他成员的持有量。
注意事项
- 攻击力和奖励由服务器的处理器设置决定,而不是客户端的值。
- 资源变更、行动记录和奖励累计在同一个事务中处理。
- 当前的通用结构按行动提供奖励。击败排名或击败者专属奖励需要另行设计。
- 响应延迟也不视为成功。使用同一个
actionId重新确认,可以防止重复应用。