成就
1. 概述
成就服务允许您为玩家设置多个成就,然后将这些成就打包到各种外循环功能中,例如成就、任务、战斗通行证等。游戏可以使用客户端 SDK 访问成就服务,以检索成就进度并为玩家领取奖励。
2. PGOS 中的 Goal
Goal 与 PGOS 中的几项服务密切相关:
玩家数据 / 玩家钱包:成就服务监控玩家数据和虚拟货币的变化,以更新玩家成就的进度。
游戏内物品:成就服务使用游戏内物品作为玩家的成就奖励。
玩家物品栏 / 邮件:奖励将发放到玩家的物品栏中,可选择邮件作为自动发放方式。
3. 关键概念
成就中定义的任务挑战仅针对个人玩家。
成就服务建立在四个关键概念之上:简单成就、高级成就、成就计划和玩家成就。
3.1 简单成就
一个简单的奖励对象,定义实现成就的条件和奖励。
3.1.1 属性参考
Goal ID:用户可分配的成就 ID,该 ID 必须在标题区域内唯一。提交后不可更改。
Display Name:成就的显示名称。
Icon:用于记录向玩家显示的成就图标的资源地址。
Description:物品的描述。
Tags:您可以使用此字段存储用于对成就进行分类的信息。
Achieve Data Source:成就数据的数据源。选项包括玩家数据和虚拟货币。
选择玩家数据时,成就关注的玩家数据键由Achieve Data字段指定。
选择虚拟货币(VC)时,成就关注的 VC 代码由Achieve Data字段指定。
Achieve Data Value:成就关注的玩家数据键或 虚拟货币代码。当成就在成就计划中可用时,PGOS 将检查并监控玩家的玩家数据值或 VC 金额是否满足成就达成条件(即是否不小于“达成数据值”字段中指定的值)。
- 提示
只有整数类型的玩家数据键可以用作Achieve Data。
Achieve Value: 玩家达成成就的Achieve Data的价值。
Algorithm Type: 计算玩家当前成就值是否满足Achieve Value的算法。选项包括Absolute和Increment。
- 当选择绝对时,PGOS 将仅关注玩家的玩家数据值或 虚拟货币 数量是否达到了达成值。
- 当选择增量时,PGOS 将关注玩家在成就生效期间的玩家数据值或虚拟货币数量的增量是否满足达成值。
奖励:玩家达成成就后可获得的奖励。奖励将从游戏内物品和虚拟货币中选择,允许为空。
奖励方式:玩家达成成就后获得奖励的方式。选项包括邮件自动发送和手动发送。
3.1.2 简单成就中的成就数据算法
成就数据算法定义了如何计算玩家朝着成就的进度。本节介绍不同算法对简单成就的影响。
绝对
- Achieve Data示例:
{
"Achieve Data Source":"PlayerData",
"Achieve Data":"adventure_level",
"Achieve Value":30,
"Algorithm Type":"ABSOLUTE"
}
算法描述:样本数据的意思是,玩家的冒险等级达到30级,即可达成成就。
Increment 增量
- Achieve Data示例:
{
"Achieve Data Source":"PlayerData",
"Achieve Data":"monster_killed",
"Achieve Value":30,
"Algorithm Type":"INCREMENT"
}算法描述:通过成就调度机制获取简单成就后,PGOS 将监控玩家的 monster_killed 字段变化,并累计玩家的增量。当玩家的 monster_killed 字段累计增量达到 30 时,该玩家即达成成就。
下图可以直观地展示这两种算法的区别:
如果使用player data作为Achieve data source,且Algorithm Type为Increment,PGOS 在记录成就数据增量时,只能响应来自接口集合 Incr(OneOf)MyKVData
或 (Batch)Incr(OneOf)PlayerKVData
的数据变化。
3.2 高级成就
一个二维的分层奖励对象。其中一个维度定义为Tiers 层级,另一个维度定义为Passes 通行证。
3.2.1 概念解释:
Goal ID: 用户可以指定的成就标识符,该标识符在title region内必须是唯一的。一旦提交,将无法更改。
Display Name: 成就的名字
Icon: 用于记录向玩家展示的成就图标的资源地址。
Description: 物品描述。
Tags: 您可以使用此字段来存储用于对成就进行分类的信息。
Achieve Data Source: 成就数据的数据源。选项包括Player Data和Virtual Currency。
- 选择Player Data时,成就关注的player data key由Achieve Data字段指定。
- 选择Virtual Currency时,成就关注的Vritual Currency代码由Achieve Data字段指定。
Achieve Data: 成就关注的player data key或 VC 代码。一旦成就在成就计划中可用,PGOS 将检查并监控玩家的player data value或 VC value是否满足成就的达成条件(即是否不小于“Achieve Data”字段中指定的值)。
提示只有整数类型的player data key可以用作Achieve Data。
Algorithm Type:
用于计算“Achieve Value”是否满足的算法。选项包括“Absolute 绝对值”和“Increment 增量值”。
- 选择“Absolute 绝对值”时,PGOS 将仅关注player data value或 VC value是否达到“Achieve Data value”。
- 选择“Increment 增量值”时,PGOS 将关注成就生效期间玩家的player data value或 VC value的增量是否满足“Achieve Data value”。
Tiers: 简单成就可以设置多个等级,将一个挑战分解成多个渐进的小挑战,并允许为每个等级分配奖励。玩家可以通过提升成就数据来晋级到新的等级,每次完成一个等级都会获得奖励。
- Tier ID: 层的标识符,由 PGOS 分配。
- Display Name: 层级名称,非必需字段。
- Order: 层级顺序。
- Achieve Value: 玩家达到该等级的Achieve Data的值。
- 当 算法类型 为 绝对值 时,值的含义是达到该层级时 Achieve Data 的绝对值。
- 当 算法类型 为 增量值 时,值的含义是达到该层级时 Achieve Data 的增量。
- Rewards: 玩家达到等级后可获得的奖励。分配奖励至等级时,需要指定奖励所属的通行证。奖励将从游戏内物品和虚拟货币中选择,允许为空。
Passes: 简单成就可以包含多个通行证,让玩家获得特定类别的奖励。通行证可以通过授予玩家特定物品来激活,也可以默认激活。通行证与等级构成了简单成就中分配奖励的两个维度。
- Pass ID: 通行证的标识符,由 PGOS 分配。
- Display Name: 通行证名称,非必需字段。
- Description: 通行证描述,非必需字段。
- Icon: 用于记录玩家看到的通行证图标的资源地址。
- Pass Item: 指定用于激活玩家通行证的游戏内物品。只要玩家拥有此物品,通行证就会被激活。留空表示通行证将默认对玩家生效。
Reward Way: 玩家达成成就后获得奖励的方式。选项包括自动直接获得奖励、自动邮件获得奖励和手动发放奖励。
选择不同的算法类型时,*Achieve Value的含义并不相同,更多详细信息请参见层级中对Achieve Value的概念解释。
3.2.2 简单成就中的Achieve Data算法
Achieve Data算法定义了如何计算玩家朝着成就前进的进度。本节将介绍不同算法在简单成就中的效果。
借助简单成就,一项巨大的挑战可以分解成多个渐进层级。下方的示例数据基于上一节中简单成就的示例数据,并简要介绍了两种成就类型之间的关系
Absolute
Achieve Data示例:将字段“adventure_level”的成就值分为三个等级。
{
"Achieve Data Source":"PlayerData",
"Achieve Data":"adventure_level",
"Tiers":[
{
"Tier Order":1,
"Achieve Value":10
},
{
"Tier Order":2,
"Achieve Value":20
},
{
"Tier Order":3,
"Achieve Value":30
}
],
"Algorithm Type":"ABSOLUTE"
}算法描述:
- 如果玩家的
adventure_level
值达到 10,则该玩家达到 1 阶等级。 - 如果玩家的
adventure_level
值达到 20,则该玩家达到 2 阶等级。 - 如果玩家的
adventure_level
值达到 30,则该玩家达到 2 阶等级。
- 如果玩家的
Increment
Achieve Data示例: 将字段“adventure_level”的达成值分为三个等级。
{
"Achieve Data Source":"PlayerData",
"Achieve Data":"monster_killed",
"Tiers":[
{
"Tier Order":1,
"Achieve Value":10
},
{
"Tier Order":2,
"Achieve Value":10
},
{
"Tier Order":3,
"Achieve Value":10
}
],
"Algorithm Type":"INCREMENT"
}算法描述:通过成就调度机制获取简单成就后,PGOS 将监控玩家的 monster_killed 字段的变化,并累计玩家的增量。每当玩家的
monster_killed
字段累计增量达到 10 时,即进入新的等级。
下图可以直观地展示这两种算法的区别:
3.3 成就计划排期
上文已介绍过简单成就和高级成就的定义,但需要注意的是,玩家无法在创建成就后立即挑战这些成就,因为在大多数游戏场景中,成就并非永久存在,它们可能会在特定时间开启和关闭,也可能在某些循环周期内开启。为了支持多样化的应用场景,我们引入了Goal Schedule的概念。
3.3.1 可用周期
成就计划排期可以定义多个(成就的)可用时段,您可以自由地将成就安排到这些可用时段中。玩家只有在成就计划处于可用时段时才能挑战该成就。
对于每个可用时段中的每个成就,PGOS 都会为挑战该成就的玩家创建一个名为 Player Goal 的对象,该对象记录玩家对该成就的挑战进度。这一点非常重要,因为这意味着同一个成就出现在不同的可用时段,对玩家来说将是不同的挑战(Player Goal)。
3.3.2 当前周期和下一个周期
这两个概念对于排期查询非常重要,它们的定义如下:
- 当前周期:距离当前时间最近的可用周期,该周期已生效。这表示该周期正在生效或刚刚完成。
- 下一个周期:距离当前时间最近的可用周期,该周期尚未生效。这表示即将生效的周期。
从定义中可以看出,当前时段和下一时段的指向会随着玩家访问赛程的时间点不断变化。对于当前周期,玩家可以访问其全部信息,包括玩家在可用时段内的成就。对于下一周期,玩家可以访问其开始和结束时间,相当于发布预览。
3.3.3 成就发布计划
计划发布后,计划中所有可用时段将生效。成就计划可以随时发布或停用,也可以在预设时间提前发布
已发布:
- 游戏客户端只能访问已发布的计划。
- 已发布的计划中,只有可用时段才会生效。这意味着玩家的挑战进度将在这些时段内被记录。
已撤回:
- 已撤回的计划将无法在游戏客户端访问。
- 已撤回的计划中的可用时段将不会生效。这意味着玩家在计划撤回期间的挑战进度将不会被记录。
- 撤回计划期间,玩家的挑战进度将被暂停。这意味着,如果计划再次发布,玩家的挑战进度将恢复,而不是重置。
3.4 玩家成就
玩家成就记录了每位玩家挑战特定成就的进度以及奖励领取情况。
3.4.1 简单玩家成就的关键属性
- Player Goal ID:玩家成就的 ID。成就出现在不同的可用时间段时,玩家成就 ID 会有所不同。
- Achieve Value:简单成就的达成值。
- Current Value::玩家朝着成就的挑战进度。
- Is Achieved:成就达成时为 True,否则为 false。
- Is Claimed:奖励已领取时为 True,否则为 false。
3.4.2 高级玩家成就关键属性
- Player Goal ID:玩家成就的 ID。成就出现在不同的可用时段时,玩家成就 ID 会有所不同。
- Current Tier ID:玩家当前正在挑战的层级。
- Current Value:玩家当前层级的挑战进度。
- 当“算法类型”为“绝对值”时,当前值与玩家成就数据的值相同。
- 当“算法类型”为“增量值”时,当前值是玩家成就数据在当前层级获得的增量值。
- Passes::成就包含的所有通行证,以及激活状态。
- Tiers:简单成就的部分层级信息,记录各层级的成就值以及奖励信息。
下图说明了四个关键概念之间的关系。
4. 管理简单成就
4.1 准备成就数据
玩家数据和虚拟货币可作为简单成就和高级成就的成就数据源。因此,在开始使用成就之前,您需要阅读以下预备文档。
4.2 创建一个简单成就
- 在 PGOS 管理门户中,打开菜单“ Engagement”,然后选择“Goals”。
在Goal页面,点击Add Goal按钮即可创建新Goal。此外,您还可以在Goal页面查看和筛选已创建的所有Goals。
将Type切换为Simple Goal,并在Goal创建页面填写必填字段。字段说明请参阅doc。
如果需要,为Goal添加奖励。
点击 Submit 按钮完成创建, 这个 goal 会被添加到 goals list.
5. 管理高级成就
5.1 准备Achieve Data
玩家数据和虚拟货币可作为简单成就和高级成就的成就数据源。因此,在开始使用成就之前,您需要阅读以下预备文档。
5.2 准备通行证物品
如果您想定义一个需要由成就中的特定物品激活而非默认激活的通行证,建议在创建简单成就时提前准备好通行证物品的定义。
- 阅读以下文档了解如何定义游戏内物品:doc。
5.3 创建高级成就
创建高级成就的过程与创建简单成就基本相同,通过类型字段切换要创建的成就类型。
与简单成就不同,创建高级成就时无需立即填写Achieve Data Value。因为高级成就的成就数据值是在其层级中定义的。
5.4 编辑Pass
- 在“成就”选项卡中,选择要修改或添加Pass的成就,然后点击成就名称以打开成就编辑器页面。
- 在成就编辑页面,选择“Pass”选项卡,您将看到默认创建的Pass。默认通行证没有Pass Item,您可以编辑或删除它。
- 点击Add Pass按钮,并在弹出的Pass创建页面上填写必填字段。字段说明请阅读doc。
5.5 编辑等级
- 在成就编辑页面,选择“Pass”选项卡,您将看到默认创建的通行证。默认通行证没有通行证项目,您可以编辑或删除它。
- 在简单成就的层级页面上,单击Add One Tier按钮为简单成就创建一个单独的层级。
- 在简单成就的层级页面,点击“Batch Create Tiers”按钮,即可一次性创建多个层级。对于使用不同算法类型的简单成就,层级创建页面提供了不同的填写成就数据值的方式。
当算法类型为增量值时:
当算法类型为绝对值时:
5.6 为Tiers分配奖励
- 在“Tiers”选项卡中,选择要添加奖励的等级。
- 在等级编辑页面,点击添加奖励按钮,为该Tier分配奖励。请注意,您必须选择每个奖励所属的Pass。最后,编辑完成后,请务必点击提交按钮。
5.7 导入/导出Tiers
您无法通过Batch Create Tiers功能自由指定每个Tier的成就数据值,需要手动为每个Tier添加奖励。因此,我们支持从 .xlsx 文件批量导入Tier数据。点击Batch Import Tiers,选择要导入的本地文件。
6. 管理计划
6.1 创建成就计划
- 在成就页面,选择“Schedule”选项卡以显示计划列表。点击“Add a Schedule”按钮创建成就计划。
在Schedule创建页面填写必填字段。
- Rewards Way将应用于Schedule中的所有成就。
创建新的计划后,点击计划列表中的计划名称即可打开计划的详细信息页面。
- Current State显示计划的当前发布状态。
- Latest Publish Time显示计划的上次发布间隔时间。
- 对于每个新创建的计划,Available Periods将为空。
- 可以在Basic Information选项卡中修改计划名称和描述。
6.2 6编辑Schedule中的可用时段
- 点击修改按钮,激活Schedule的编辑模式。
进入编辑模式后,您可以根据需要点击Add a Period或Batch Add Periods来创建一个或多个时间周期。
需要输入周期的开始和结束时间才能创建单个可用周期。系统提供了多个预设时间间隔,方便您更快地创建周期。
Batch Add Periods 功能旨在创建多个长度和间隔相同的周期。此功能可用于构建每日任务、每周任务等功能。
- Start Time:第一个可用周期的开始时间。
- Period Count:批量创建的可用周期数。
- Period Length:每个周期的长度。
- Period Gap:相邻周期之间的时间间隔。
- End Time:根据以上输入自动计算的最后一个周期的结束时间。
单击Submit以提交对计划的更改。
6.4 将成就分配到可用时段
- 可以在Schedule的可用时段中添加或删除成就。
- 点击Apply to All Periods,快速将当前选定周期的成就同步到所有其他周期。
- 单击Submit以提交对计划的更改。
6.5 发布和停用计划
计划发布后,所有可用时段将生效。成就计划可以随时发布或停用,也可以在预设时间提前发布。
- 打开计划页面,选择要发布的计划,然后点击Operations列中的Publish按钮。
- 填写发布的开始和结束时间,点击Submit确认发布。
- 单击已发布计划的Operations列中的Retire按钮即可将其撤销
7. 玩家成就
- 在 PGOS 管理门户中,打开菜单“Players”,然后选择“Query.”。
- 在玩家查询页面选择查询对象
- 打开玩家详情页面的“Goals”标签页。下方将列出该玩家的所有玩家成就,并提供多种搜索选项。
- 点击查看玩家简单成就的详细信息.
- 点击 + Achieve Value 来增加玩家成就的成就值.
- 点击查看简单成就的详细信息.
- 点击 + Achieve Value 来增加玩家成就的成就值.
- Total Achieve Value显示的是玩家在玩家成就中累计的成就值增量。
8. 使用 PGOS SDK 访问成就
8.1 查询玩家成就
玩家可以通过 SDK 访问已发布计划中的玩家成就,查看成就状态、奖励领取状态以及到期日期。调用客户端成就模块的 GetGoalsSchedule
方法:
#include "PgosSDKCpp/Public/PgosSDKCpp.h"
#include "PgosSDKCpp/Public/Core/PgosErrorCode.h"
void SomeUObjectClass::QueryPublishedSchedule()
{
auto goal = IPgosSDKCpp::Get().GetClientGoalAPI();
FString schedule_id = "schedule_xxxxxx";
if (goal)
{
goal->GetGoalsSchedule(schedule_id,
[](const FPgosResult& Ret, const GoalsSchedule* Response) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("GetGoalsSchedule Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("GetGoalsSchedule Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
由于简单成就可能包含大量的层级,因此 GetGoalsSchedule
接口不会返回该简单成就的所有层级,我们提供了分页查询接口。调用 Client Goal 模块的 BatchGetGoalTiers
方法可以查询指定订单范围的层级:
#include "PgosSDKCpp/Public/PgosSDKCpp.h"
#include "PgosSDKCpp/Public/Core/PgosErrorCode.h"
void SomeUObjectClass::QueryHyperGoalTiers()
{
auto goal = IPgosSDKCpp::Get().GetClientGoalAPI();
FString player_goal_id = "some_hyper_player_id";
uint32_t start_order = 50;
uint32_t query_count = 20;
if (goal)
{
goal->BatchGetGoalTiers(player_goal_id,
start_order,
query_count,
[](const FPgosResult& Ret, const GetGoalTiersResult* Response) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("BatchGetGoalTiers Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("BatchGetGoalTiers Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
8.2 领取已达成成就(等级)的奖励
玩家可以领取特定等级的奖励。调用客户端成就模块的 ClaimTierRewards
方法:
#include "PgosSDKCpp/Public/PgosSDKCpp.h"
#include "PgosSDKCpp/Public/Core/PgosErrorCode.h"
void SomeUObjectClass::CliameRewardsfoATier()
{
auto goal = IPgosSDKCpp::Get().GetClientGoalAPI();
FString player_goal_id = "some_hyper_player_id";
FString tier_id = "some_tier_id";
if (goal)
{
goal->ClaimTierRewards(player_goal_id,
tier_id,
[](const FPgosResult& Ret, const ClaimGoalsRewardResult* Response) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("ClaimGoalsRewardResult Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("ClaimGoalsRewardResult Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
玩家可以针对特定成就领取奖励。调用客户端成就模块的“ClaimGoalRewards”方法:
#include "PgosSDKCpp/Public/PgosSDKCpp.h"
#include "PgosSDKCpp/Public/Core/PgosErrorCode.h"
void SomeUObjectClass::CliameRewardsfoAGoal()
{
auto goal = IPgosSDKCpp::Get().GetClientGoalAPI();
FString player_goal_id = "some_hyper_player_id";
if (goal)
{
goal->ClaimGoalRewards(player_goal_id,
[](const FPgosResult& Ret, const ClaimGoalsRewardResult* Response) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("ClaimGoalRewards Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("ClaimGoalRewards Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}
玩家可以领取特定schedule的奖励。调用客户端成就模块的“ClaimScheduleRewards”方法:
#include "PgosSDKCpp/Public/PgosSDKCpp.h"
#include "PgosSDKCpp/Public/Core/PgosErrorCode.h"
void SomeUObjectClass::CliameRewardsfoASchedule()
{
auto goal = IPgosSDKCpp::Get().GetClientGoalAPI();
FString schedule_id = "some_schedule_id";
if (goal)
{
goal->ClaimScheduleRewards(player_goal_id,
[](const FPgosResult& Ret, const ClaimGoalsRewardResult* Response) {
if (Ret.err_code == (int32)Pgos::PgosErrCode::kSuccess)
{
UE_LOG(LogTemp, Log, TEXT("ClaimScheduleRewards Success"));
}
else
{
UE_LOG(LogTemp, Log, TEXT("ClaimScheduleRewards Failed: err_code=%d, err_msg=%s"), Ret.err_code, *Ret.msg);
}
});
}
}