# 玩家互动系统

# 概述

玩家互动模块 interactivePropertySystem,用于实现玩家间赠送互动道具,可以实现 展现好友排行榜、玩家在排行榜中向好友赠送爱心 等常见场景。

在这一模块中,互动道具有属性 name ,它们通过 key(编号从 '1''50'env 值区分,即不同互动道具的 key env值不同。每种互动道具被分为两个部分:已有数量、待领取数量。 使用本系统之前,请确保已经在mogs管理端正确配置了互动道具信息

  • 已有数量:指玩家已经拥有的互动道具数量
  • 待领取数量:指其他玩家赠送了互动道具给本玩家,但本玩家还未领取的数量

**

本模块提供的能力有:

  • 可配置玩家向其他玩家赠送互动道具规则,如限定一个玩家每天最多向好友列表中的同一好友赠送 10 次,向所有好友赠送次数上限为 20 次
  • 获取玩家的 已有 和 待领取 的互动道具数量
  • 玩家领取待领取的互动道具
  • 玩家消耗一定数量的互动道具
  • 获取本玩家的好友列表,并在配置规则下,获得能否给该玩家赠送互动道具
  • 获取本玩家的受赠记录

接下来,本文将介绍如何在微信、QQ环境下使用玩家互动模块 interactivePropertySystem

# 注意事项

  1. 请先阅读文档 开放能力 - 关系链数据
  2. 如果您在 微信/QQ 平台下使用本模块,请确保每个互动道具的使用中对应的用户的普通型托管数据至少还有 7个 key 的空间! (如果您在项目中从未使用 setUserCloudStorage API,请忽略此段)

# 模块使用

# Introduction

以下将以 cocos creator 引擎(版本 2.4.2),发布到微信小游戏平台为例,介绍如何使用玩家互动模块。您需要创建两个 cocos creator 项目,第一个用于构建 微信小游戏 项目(以下称之为 主域 项目),第二个用于构建 微信小游戏开放数据域 项目(以下称之为 开放数据域 项目)。两个项目都需要安装 MOGS TOOLS,并通过 MOGS TOOLS 安装 SDK,需要 SDK 版本 >= 0.3。

主域项目可以实现的功能有:获取玩家互动道具数量、领取玩家待领取的互动道具,消耗一定数量的互动道具。

开放数据域项目可以实现的功能有:向其他玩家赠送互动道具、获取本玩家的好友列表,附带能否赠送道具信息、获取玩家的受赠记录。

关于 cocos creator 如何配置主域项目与开放数据域项目,见 接入微信小游戏的开放数据域 (opens new window)

# 主域项目

# 配置赠送规则与文案

首先,需要在游戏项目根目录下的 mogs.json 文件中配置 userInteractionmodifyFriendInteractiveStorageTemplates

userInteraction 字段用于配置玩家赠送规则,其中当 useInternalSchema 字段为 true 时,才能使用本模块的相关API,其他字段的含义如下:

  • key:限制单位,目前取值只有 date(每天)。
  • limit:在限制单位下的限制总次数,可以取任意正整数。如当 keydatelimit 为 20 时,意义为限制每天一个玩家只能向其他玩家赠送共 20 次。
  • repeatedSendLimit:在限制单位下对同一玩家的赠送次数。如当 keydaterepeatedSendLimit 为 10 时,意义为限制对同一个玩家一天最多赠送 10 次。
  • limitrepeatedSendLimit的值为默认配置,当每个互动道具没有配置相应值时,取默认配置

modifyFriendInteractiveStorageTemplates 字段用于配置互动文案,其中有字段 key, action, object, ratio,配置后当用户发生互动行为时,会生成文案 确认 ${action} ${nickname} ${object} x ${opNum * ratio}?

相关配置示例如下。

// mogs.json 文件样例
{
  // ...
  // 玩家互动配置
  "userInteraction": {
    "useInternalSchema": true,
    "key": "date",
    "limit": 20,
    "repeatedSendLimit": 10
  },
  "modifyFriendInteractiveStorageTemplates": [{
    "key": "1",
    "action": "赠送",
    "object": "金币",
    "ratio": 1
  }]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 常见功能实现

# 设置玩家分数

本模块通常与“玩家分数”配合使用(比如可以实现好友榜单),在游戏结束后,可以调用 mogs.setUserCloudStorage 设置当前玩家的普通型托管数据,其可以用于设置分数。示例代码如下。(注意,“设置玩家分数”这一需求,实际上是利用 关系链数据 的能力实现,详见文档 开放能力 - 关系链数据)

import mogs from '@timi/mogs-sdk';

// ...

await mogs.setUserCloudStorage({
  KVDataList: [
    {
      key: "score", // 分数 key 值(用于表示这个字段是“分数”)
      value: playerScore,  // 玩家分数
    },
  ],
});
1
2
3
4
5
6
7
8
9
10
11
12

如果希望 主域项目 和 开放数据域项目 都能够维护“玩家分数”,并且能够相对同步进行某些操作,可在 主域项目 调用 mogs.getOpenDataContext().postMessage 将“玩家分数”发送至 开放数据域项目,开放数据域项目中调用 mogs.onMessage 监听分数数据到来,并调用 mogs.setUserCloudStorage 设置分数。

# 获取/更新 互动道具

引入 interactivePropertySystem 后,需要调用 updateInteractiveProperty 更新互动道具信息,再通过 onInteractivePropertyChange 监听互动道具改变事件,最后通过 interactiveProperty 属性获取互动道具数量。示例代码如下。

// 引入 interactivePropertySystem
import { interactivePropertySystem } from '@timi/mogs-sdk';

// 使用前,需初始化
await interactivePropertySystem.initializeInteractiveProperty();
// 也可以通过初始化获取到互动道具的配置信息用于给业务方展示
const interactivePropertyConfig = await interactivePropertySystem.initializeInteractiveProperty();

// 监听互动道具改变信息
interactivePropertySystem.onInteractivePropertyChange(async () => {
  // 获取改变了的互动道具信息
  const ip = await interactivePropertySystem.interactiveProperty;
});

// ...

// 更新互动道具信息
interactivePropertySystem.updateInteractiveProperty({
  name: 'name_1',
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 领取互动道具数量

调用 receivePendingInteractiveProperty 可以领取待领取的互动道具。假设有一个按钮 Node 名为 nodeBtnReceive,您希望玩家点击该按钮即可领取互动道具,则代码可以如下。

nodeBtnReceive.on('click', async () => {
  // 领取待领取奖励
  await interactivePropertySystem.receivePendingInteractiveProperty({
    name: 'name_1'
  });
  // 结果通过事件监听得到
});
1
2
3
4
5
6
7
# 消耗互动道具

调用 consumeInteractiveProperty 可以消耗互动道具。假设有个按钮 Node 名为 nodePlayGame,您希望玩家点击该按钮时消耗10个互动道具并开始游戏,则代码可以如下。

nodePlayGame.on('click', async () => {
  try {
    await interactivePropertySystem.consumeInteractiveProperty({
      name: 'name_1'
      reason: 1,
      num: 10,
    });
    // 消耗成功,开始游戏逻辑
  } catch (e) {
    // 消耗失败,道具不足,提示用户道具不足
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
# 为开放数据域项目传递 openid

由于开放数据域项目部分 API 需要用户自己的 openid,其需要在主域项目中获取到用户的 openid 后,传递到开放数据域。主域传递 openid 示例代码如下。

// 使用 accountSystem 获取 openid
const data = await accountSystem.account;
// 向开放数据域传递用户 openid
// 注意:需要等待开放数据域 onMessage 执行后,才可以 postMessage
setTimeout(() =>  {
  mogs.getOpenDataContext().postMessage({
    selfOpenid: data.openId,
  });
}, 500);
1
2
3
4
5
6
7
8
9

# 构建项目

使用 cocos creator 自带的构建项目发布到微信小游戏,发布时填写“开放数据域代码目录”。(如不填写,会影响 checkInteractiveData.js 文件的生成!)

使用 微信开发者工具 打开输出目录,将 jsserver/checkInteractiveData.js 点击右键上传。(如不上传,会影响赠送规则校验!)

# 开放数据域项目

# 配置

配置文件 mogs.json 请保持与 主域项目 中的一致。

# 常用功能实现

# 获取主域项目传递的 openid

开放数据域项目部分 API 需要使用到玩家自身到 openid,可以调用 onMessage 接口获取主域传递的 openid,并保存。(注意:需要先 onMessagepostMessage

import mogs from '@timi/mogs-sdk-open';

mogs.onMessage((data) => {
  // 主域传递的是 openid
  if (data.selfOpenid) {
    // 存下来
    this.selfOpenid = data.selfOpenid;
  }
});
1
2
3
4
5
6
7
8
9
# 获取好友列表,包括是否可赠送交互道具

调用 interactivePropertySystem.storagesOfFriends 可获取好友列表及各个好友是否可赠送互动道具。假设某个场景需要渲染好友排行榜,并且每个好友旁边都有一个按钮 btnSend,用于给该好友赠送爱心,示例代码可以如下。使用时,以下接口调用应该在 主域初始化函数 await interactivePropertySystem.initializeInteractiveProperty(); 执行完成之后

import { interactivePropertySystem } from '@timi/mogs-sdk-open';

// 获取好友列表
const userData = await interactivePropertySystem.storagesOfFriends({
  // 附加的 key,一般用这个key来实现排行榜; 此处为 score ("score" 在之前使用 mogs.setUserCloudStorage 设置过,关于 setUserCloudStorage 的用法见 SDK 模块的 API 文档)
  keyList: ['score'],
  name: "name_1",
  // 玩家自己的 openid
  selfOpenid: this.selfOpenid,
});
userData.forEach(data => {
  // 获取玩家的 score
  const score = data.KVDataList.find(p => p.key === 'score').value;
  
  // ...

  // 假定函数 render 可渲染玩家列表中该好友的数据
  // nickname 为玩家的昵称
  // openid 为好友的 openid
  render({
    nickname: data.nickname,
    score: score,
    openid: data.openid,
  });

  // 渲染按钮,根据是否可领取渲染其交互状态
  if (data.canSendInteractiveProperty) {
    btnSend.getComponent(cc.Button).interactable = true;
  } else {
    btnSend.getComponent(cc.Button).interactable = false;
  }
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 给好友赠送互动道具

调用 interactivePropertySystem.sendInteractiveProperty 给指定好友赠送互动道具。此步骤一般在渲染好友列表时同步进行。示例代码如下。

// 假定 userData 为 storagesOfFriends API 的调用结果
userData.forEach(data => {
  // 渲染部分...

  // 假定 Node 节点 nodeBtnSend 为该玩家对应的赠送按钮节点
  nodeBtnSend.on('click', async () => {
    // 给玩家赠送互动道具
    // 假定 toUserOpenid 为玩家的 openid,其可在 storagesOfFriends API 获取
    // 注意:opNum 必须为 1,key 必须为 '1'
    await interactivePropertySystem.sendInteractiveProperty({
      name: 'name_1',
      opNum: 1,
      toUserOpenid: toOpenid,
    });
  });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 获取自己的受赠记录

调用 interactivePropertySystem.getSelfReceiveRecords 获取玩家自己的受赠记录,受赠记录会保留最近的 30 条。假定某个场景需要渲染玩家的受赠记录,示例代码如下。

// 获取受赠记录,可以批量获取多个互动道具受赠记录
const data = await interactivePropertySystem.getSelfReceiveRecords({
    selfOpenid,
    names: ["name_1"],
});

data.forEach(r => {
    // 假定 render 函数渲染一条受赠记录
    // nickname 为 赠予好友昵称
    // time 为 赠予时间,类型为 Date
    render({
      nickname: r.nickname,
      time: r.time,
    });
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 构建项目

使用 cocos creator 自带的构建目录发布到 微信小游戏开放数据域,发布目录需要指定到 主域项目 填写构建目录。

构建项目后,打开微信开发者工具预览效果。