---
metadata:
  - name: generator
    content: Diplodoc Platform v5.66.0
alternate:
  - https://yandex.com/dev/games/doc/en/sdk/sdk-multiplayer-sessions.md
  - https://yandex.com/dev/games/doc/hi/sdk/sdk-multiplayer-sessions.md
  - https://yandex.com/dev/games/doc/ko/sdk/sdk-multiplayer-sessions.md
  - https://yandex.com/dev/games/doc/ru/sdk/sdk-multiplayer-sessions.md
  - https://yandex.com/dev/games/doc/tr/sdk/sdk-multiplayer-sessions.md
  - https://yandex.com/dev/games/doc/vi/sdk/sdk-multiplayer-sessions.md
  - https://yandex.com/dev/games/doc/zh/sdk/sdk-multiplayer-sessions.md
  - href: https://yandex.com/dev/games/doc/zh/sdk/sdk-multiplayer-sessions.md
    type: text/markdown
    title: Markdown version
  - href: https://yandex.com/dev/games/doc/zh/llms.txt?revision=r21993288
    rel: describedby
---
> **Documentation Index:** Fetch the complete configuration index at https://yandex.com/dev/games/doc/zh/llms.txt?revision=r21993288

# 异步多人游戏

<!-- source: zh/_includes/script-common.md -->
<!-- source: zh/_includes/script/index-js.md -->

<!-- endsource: zh/_includes/script/index-js.md -->

<!-- source: zh/_includes/script/requirements-js.md -->

<!-- endsource: zh/_includes/script/requirements-js.md -->

<!-- source: zh/_includes/script/image-modal-js.md -->

<!-- endsource: zh/_includes/script/image-modal-js.md -->
<!-- endsource: zh/_includes/script-common.md -->

通过 `ysdk.multiplayer` 模块，您可以创建类似在线多人游戏的竞技模式。这样您无需：

- 编写和维护自己的服务器解决方案；
- 拥有快速寻找对手所需的临界玩家数量。

可通过SDK实现核心机制的流派示例：

- **益智游戏**： 异步会话可以在相邻的游戏板上播放，可以增加按时间或分数的竞争。适合的游戏示例：[空当接龙在线！](https://yandex.com/games/app/211144){.external} (来自 KosmosGames)，[Match Arena - 消消乐！](https://yandex.com/games/app/96787){.external} (来自 PecPoc Piggy)。
- **跑酷和赛车游戏**： 对手的会话可以显示为“阴影”，与玩家一起在关卡中移动 (鬼魂驾驶机制)。适合的游戏示例：[疯狂赛车 2](https://yandex.com/games/app/374739){.external} (来自 JL studio) 中的“极速竞赛”模式，[疯狂摩托](https://yandex.com/games/app/233231){.external} (来自 haoda games)。
- **策略和自动战斗游戏**： 可以实现与其他玩家战术对抗的战斗。适合的游戏示例：[Ludus](https://yandex.com/games/app/376147){.external} (来自 Positron Dynamics)，[Like a King](https://yandex.com/games/app/140656){.external} (来自 Vladimir Saponenko)，[TOYS: Crash Arena](https://yandex.com/games/app/291515){.external} (来自 Mad Pixel)。



## 概念 {#concept}

1. 用户 A 游戏时，SDK 记录关键事件（按键、状态变化）及其时间。
2. 这些事件作为时间线（事务列表）保存在服务器上。
3. 用户 B 启动游戏时，已保存的时间线中的对手将加载到他的会话中。
4. SDK 实时重现对手的动作，营造同时游戏的感觉。



## 初始化和加载会话 {#init}

要开始使用异步多人游戏，请调用方法 `ysdk.multiplayer.sessions.init()`。该方法进行初始初始化和加载对手的游戏会话。 其中进行初始化和加载对手的游戏会话。

该方法返回[已加载会话的数组](#response-format)。

接受以下参数：

#|
|| **参数** | **类型** | **描述** ||
|| `count` | `number` | 确定要加载的会话数量。 确定要加载的会话数量。响应中的最大会话数为 10 个。 ||
|| `isEventBased` | `boolean` | 通过事件[初始化工作](#use)的标志。 ||
|| `maxOpponentTurnTime` | `number` | 限制对手的回合时间，并设置发送事件`multiplayer-sessions-transaction`之间的最大间隔（以毫秒为单位）。 如果指定了该参数，则对手每次超过`maxOpponentTurnTime`的回合都将缩短为指定值。 默认情况下，对手的回合时间不受限制。

{% cut "`maxOpponentTurnTime` 工作示例" %}

记录会话中的对手以2–10秒的间隔进行回合，参数`maxOpponentTurnTime`的值为5000毫秒。 在这种情况下，该对手的所有操作，无论原始回合时长如何，都将在不超过5秒内发生。

{% endcut %} ||
|| `meta` | `object` | 用于筛选的用户参数`meta1`、`meta2`、`meta3`。 它们采用`{ min: %number%, max: %number% }`对象的形式，并在[保存会话](#push)时设置。 例如，如果`meta1`中存储了游戏得分，而`meta2`中存储了玩家等级，您可以加载与当前用户在这些参数上相近的已保存会话。 ||
|#

{% note warning %}

加载会话时，必须至少设置三个 `meta` 参数中的一个，并且 `count` 参数的值要大于零。否则，多人游戏将仅初始化为记录。 否则，多人游戏将仅初始化为录制模式。

{% endnote %}

{% list tabs %}

- 请求示例

  ```javascript showLineNumbers
  ysdk.multiplayer.sessions.init({
      count: 2, // 要加载的对手会话数量（最多为10）。
      isEventBased: true, // 通过事件初始化工作的标志。
      maxOpponentTurnTime: 200, // 限制对手的回合时间（毫秒）。
      [meta](*meta): {
          meta1: {
              min: 0,
              max: 6000
          },
          meta2: {
              min: 2,
              max: 10
          }
      }
  }).then((opponents) => console.log(opponents));
  ```

- ES2017 异步/等待的请求示例

  ```javascript showLineNumbers
  const work = async () => {
      const opponents = await ysdk.multiplayer.sessions.init({
          count: 2, // 要加载的对手会话数量（最多为10）。
          isEventBased: true, // 通过事件初始化工作的标志。
          maxOpponentTurnTime: 200, // 限制对手的回合时间（毫秒）。
          [meta](*meta): {
              meta1: {
                  min: 0,
                  max: 6000
              },
              meta2: {
                  min: 2,
                  max: 10
              }
          }
      });

      console.log(opponents);
  };

  work();
  ```

{% endlist %}

#### 回答格式 {#response-format}

```javascript showLineNumbers
[
    {
        [id](*id): string;
        [meta](*meta): {
            meta1: number;
            meta2: number;
            meta3: number;
        };
        [player](*player): {
            avatar: string;
            name: string;
        };
        [timeline](*timeline): [
            {
                [id](*timeline_id): string;
                [payload](*payload): object | string | undefined;
                [time](*time): number;
            },
            ...
        ];
    },
    ...
]
```

#|
|| **参数** | **类型** | **描述** ||
|| `id` | `string` | 会话标识符。 ||
|| `meta` | `object` | 自定义参数 `meta1`、`meta2`、`meta3`。例如，游戏中的分数或玩家等级。 例如，游戏得分或玩家等级。 ||
|| `player` | `object` | 对手玩家信息:
- `avatar: string` —— 用户头像的URL；
- `name: string` —— 玩家的姓名。
||
|| `timeline` | `array` | 描述游戏会话的事件时间线数组：
- `id: string` —— 事件的唯一标识；
- `payload` —— 事件数据：反映游戏世界中变化原因的信息（例如，角色的新坐标或鼠标点击）；
- `time: number` —— 游戏开始后的时间，考虑暂停（毫秒）。
||
|#



## 游戏会话记录 {#record}

{% note alert %}

最大的单个会话记录大小为200 KB。

{% endnote %}

使用SDK记录用户的游戏会话（带时间戳的事件序列）。 事件可以是益智游戏中棋盘上棋子的移动，或跑酷游戏中键盘或鼠标按键的按下。

在用户输入连续的游戏中，例如跑酷游戏，可以在特定时间间隔内人工生成事件，记录角色状态的指标——坐标、能量水平等。这也可以是游戏中的随机事件——奖励、地震。

游戏中发生的事件以事务的形式保存。 每个事务都有：

#|
|| **参数** | **类型** | **描述** ||
|| `id` | `number` | 事件的唯一标识符。 ||
|| `payload` | `object` | 事件数据：反映游戏世界中变化本质和原因的信息（例如，角色的新坐标或鼠标按钮的按下）。 包含“键—值”对的对象。 ||
|| `time` | `number` | 游戏开始的时间，包含暂停的修正。 ||
|#

在游戏过程中，使用 [commit()](#commit) 方法保存 `payload`。 这样会形成交易列表——游戏会话的时间线（`timeline`）。

在游戏结束时，通过方法 [push()](#push) 将会话保存到服务器。保存后，会话可以在下一个游戏中加载并回放。 保存后，会话可以在下一场游戏中加载并回放。


### ysdk.multiplayer.sessions.commit() {#commit}

该方法固定当前游戏会话的交易。 事件数据（[payload](*payload)）会传入其中。

{% note warning %}

交易的其他参数——标识符 (`id`) 和游戏开始时间 (`time`)——是在 SDK 中计算的，因此及时发送 `payload` 非常重要。

{% endnote %}

#### 示例 {#commit-ex}

```javascript showLineNumbers
// 第一次交易。
ysdk.multiplayer.sessions.commit({ x: 1, y: 2, z: 3, health: 67 });

// .......

// 下一次交易。
ysdk.multiplayer.sessions.commit({ x: 4, y: -2, z: 19, health: 15 });

// .......
```


### ysdk.multiplayer.sessions.push() {#push}

该方法用于将时间线保存到远程服务器。 在游戏结束时调用。

`meta1`、`meta2`、`meta3` 的值在保存会话时设置。 至少需要定义一个 [meta参数](*meta)。

#### 示例 {#push-ex}

```javascript
ysdk.multiplayer.sessions.push({ meta1: 12, meta2: -2 });
```


## 使用会话 {#use}

要选择如何处理加载的对手会话，请在方法 [init()](#init) 中传递所需的 `isEventBased` 标志值：

#|
|| **值** | **描述** ||
|| `isEventBased: true` | 通过事件处理。 ||
|| `isEventBased: false` | 自行处理。 ||
|#

{% list tabs %}

- 通过事件

  客户端通过 `ysdk.on()` 订阅事件 `multiplayer-sessions-transaction` 和 `multiplayer-sessions-finish`，而 SDK 自行加载共有会话并根据其中指定的时间戳发出事件：

  - 在游戏过程中，对手的交易会在从会话开始记录时间的时刻到达 `multiplayer-sessions-transaction` 处理器，但会考虑对手回合时间限制（`maxOpponentTurnTime`，方法 [init()](#init) 的参数）。

  - 当会话结束时，将调用 `multiplayer-sessions-finish` 处理器，并提供游戏结束的对手的标识符。

  ```javascript showLineNumbers
  ysdk.multiplayer.sessions.init({
      count: 2, // 要加载的对手会话数量（最多为10）。
      isEventBased: true, // 通过事件初始化工作的标志。
      maxOpponentTurnTime: 200, // 限制对手的回合时间（毫秒）。
      [meta](*meta): {
          meta1: {
              min: 0,
              max: 6000
          },
          meta2: {
              min: 2,
              max: 10
          }
      }
  });

  // 在此处我们接收当前需要执行的事务数组：
  // 当前事务以及由于游戏可能出现卡顿而延迟的事务。
  ysdk.on('multiplayer-sessions-transaction', ({ opponentId, transactions }) => {
      console.log(opponentId, transactions);
      // 在游戏场景中应用 transaction.payload 的数据。
  });

  ysdk.on('multiplayer-sessions-finish', (opponentId) => console.log(opponentId));
  ```

  多人游戏的启动和暂停由[游戏玩法标记](https://yandex.com/dev/games/doc/zh/sdk/sdk-game-events.md#gameplay)方法控制：

  ```javascript showLineNumbers
  // 启动多人模式。
  ysdk.features.GameplayAPI.start();

  // 暂停多人模式。
  ysdk.features.GameplayAPI.stop();
  ```

- 自己的解决方案

  多人游戏初始化方法 [init()](#init) 返回加载的对手会话数组，包含带有事务的时间线。

  自行获取和处理数据：

  ```javascript showLineNumbers
  const start = (opponent) => {
      console.log('player', opponent.player);
      console.log('timeline', opponent.timeline);

      // 实现使用时间轴和播放器数据的机制。
  };

  const work = async () => {
      const opponents = await ysdk.multiplayer.sessions.init({
          count: 2, // 要加载的对手会话数量（最多为10）。
          isEventBased: false, // 通过事件初始化工作的标志。
          maxOpponentTurnTime: 200, // 限制对手的回合时间（毫秒）。
          [meta](*meta): {
              meta1: {
                  min: 0,
                  max: 6000
              },
              meta2: {
                  min: 2,
                  max: 10
              }
          }
      });

      console.log('opponents', opponents);

      for (let i = 0; i < opponents.length; i++) {
          start(opponents[i]);
      }
  };

  work();
  ```

{% endlist %}


---

<!-- source: zh/_includes/sdk/sdk-support.md -->
{% note info %}

支持服务员工帮助将成品游戏发布到 Yandex Games 平台。 关于开发和测试的具体问题，其他开发者会在[Discord 社区](https://discord.com/invite/wU4p3whr4T){.external}中给出针对性解答。

{% endnote %}

如果在使用 Yandex Games SDK 时遇到问题或有疑问，请联系技术支持：

<!-- source: zh/_includes/button-chat.md -->
<a href="https://yandex.com/chat/#/user/a4fa5c06-75db-9b38-6eea-b1673785f7d5">
  <span class="button">写入聊天信息</span>
</a>
<!-- endsource: zh/_includes/button-chat.md -->
<!-- endsource: zh/_includes/sdk/sdk-support.md -->

[*id]: 会话标识符。

[*meta]: 自定义参数 `meta1`、`meta2`、`meta3`，它们在保存会话时设置。例如，游戏分数或玩家等级。 例如，游戏得分或玩家等级。

[*player]: 对手玩家的信息：
- `avatar: string` —— 用户头像的URL；
- `name: string` —— 玩家姓名。

[*timeline]: 描述游戏会话的事件时间轴数组：
- `id: string` —— 事件的唯一标识符；
- `payload` —— 事件数据：反映游戏世界变化本质、原因的信息（例如，角色的新坐标或鼠标点击）；
- `time: number` —— 从游戏开始到事件发生的时间（毫秒），考虑了暂停的影响。

[*timeline_id]: 事件的唯一标识符。

[*payload]: 事件数据：反映游戏世界变化本质、原因的信息（例如，角色的新坐标或鼠标点击）。

[*time]: 从游戏开始到事件发生的时间，考虑了暂停的影响。