---
title: 机器人玩家创建指南
slug: world-sdk-guide-ch/Q6LpKIDWa8nn2YwHgYyra
docTags: 
createdAt: 2024-09-02T08:34:13.135Z
---

机器人玩家用于在没有足够的人开始多人世界时填补空缺，或者当玩家在游戏中离开时。

机器人玩家的行为需要为每个内容实现。

本指南描述了创建机器人玩家的一般方法。

:::hint{type="info"}
**📘&#x20;**&#x673A;器人玩家创建指南基于多人游戏指南。 \[[创建多人游戏](docId\:sPK-TARdrDZ3tD3r6GnAe)]
:::

## 步骤 1：创建一个机器人玩家

1-1. 添加一个名为 `IsBot` 的布尔值到多人游戏架构中。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-H8VrE4wHUDwRHCAiehWap-20240904-102422.png)



1-2. 在服务器脚本 index.ts 中定义以下函数以创建一个机器人玩家，并在所需位置调用它。

:::CodeblockTabs
index.ts

```typescript
// `CreateBot()` 方法用于创建一个具有给定 `userId` 的机器人玩家。
CreateBot(userId: string) {

    // 使用提供的 `userId` 为机器人玩家生成一个会话 ID。
    const sessionId = "Bot_" + userId;

  	// 检查是否已经存在具有相同会话 ID 的机器人玩家。如果是，则返回而不创建重复项。
    if (this.state.players.has(sessionId)) {
        return;
    }

    // 为机器人玩家创建一个新的 `Player` 对象。
    const player: Player = new Player();
    player.sessionId = sessionId;
    if (userId) {
        player.zepetoUserId = userId;
    }
    player.isBot = true;

  	// 使用会话 ID 作为键将机器人玩家添加到状态的玩家映射中。
    this.state.players.set(player.sessionId, player);
    this._botMap.set(sessionId, player);
}
```
:::



:::hint{type="success"}
**👍 提示**

- 特定用户的 userId 被提前存储，以便创建机器人角色。
- 您可以通过检查连接到服务器的 OnJoin 的客户端的 userId 来检查特定用户的 UserId。在服务器脚本中编写以下脚本后，从相关世界连接。
:::

:::CodeblockTabs
index.ts

```typescript
onJoin(client: SandboxPlayer) {
	console.log(client.userId);
}
```
:::



## 步骤 2：在客户端创建一个机器人玩家

2-1. 如果服务器在某个时刻创建了一个机器人玩家，客户端将在 OnJoinPlayer() 中将其识别为新玩家。

- 创建项目 > 创建 > ZEPETO > TypeScript，并将其重命名为 BotPlayerManager。
- 在 OnAddedPlayer() 中添加逻辑以创建每个玩家，并添加逻辑以区分机器人玩家并创建他们的 ZEPETO 角色。

:::CodeblockTabs
BotPlayerManager.ts

```typescript
import { ZepetoCharacter, ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { Room } from 'ZEPETO.Multiplay';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { ZepetoWorldMultiplay } from 'ZEPETO.World';

export default class BotPlayerManager extends ZepetoScriptBehaviour {

    public zepetoWorldMultiplay: ZepetoWorldMultiplay;

 	// 私有变量用于存储当前房间和机器人玩家数据。
    private _room: Room;
    private _botMapData: Map<string, ZepetoCharacter> = new Map<string, ZepetoCharacter>();

    Start() {
		
	 	// 监听来自 `ZepetoWorldMultiplay` 组件的 `RoomJoined` 事件。
        this.zepetoWorldMultiplay.RoomJoined += (room: Room) => {
        	this._room = room;
        }

	 	// 监听来自 `ZepetoPlayers.instance` 的 `OnAddedPlayer` 事件以处理新添加的玩家。
        ZepetoPlayers.instance.OnAddedPlayer.AddListener((userId: string) => {

		 	// 使用 `userId` 从房间状态获取当前玩家数据。
            const currentPlayer = this._room.State.players.get_Item(userId);

		 	// 检查玩家是否为机器人，如果是，则将其设置为机器人玩家。
            if (currentPlayer.isBot) {
                this.SetBotPlayer(currentPlayer.sessionId);
            }
        });
    }
}
```
:::



2-2. 编写 SetBotPlayer 函数，以将标签和同步组件添加到机器人玩家，并创建控制它们的脚本。

- 将 \_botMapData 设置为以 Map 格式保存机器人玩家数据，以管理机器人玩家。

:::CodeblockTabs
BotPlayerManager.ts

```typescript
// `SetBotPlayer()` 方法用于将玩家设置为机器人。
SetBotPlayer(userId: string) {

    // 使用他们的 `userId` 获取与机器人玩家关联的 ZEPETO 角色。
    const bot = ZepetoPlayers.instance.GetPlayer(userId).character;

    // 将角色的名称设置为 `userId` 以便识别。
    bot.gameObject.name = userId;

    // 使用他们的 `userId` 作为键，将机器人玩家的数据存储在 `_botMapData` 映射中。
		this._botMapData.set(userId, bot);
}
```
:::



:::hint{type="success"}
**👍 提示**
您可以向 SetBotPlayer() 添加额外的脚本或设置，以控制机器人玩家的行为。
:::



## 步骤 3：在客户端创建一个机器人玩家按钮

对于需要一定数量玩家才能开始的世界，有时玩家数量不足，您必须等待很长时间才能开始游戏。

在这种情况下，您可以通过添加一个机器人玩家来启动世界。

3-1. 在 index.ts 中注册一个函数，当服务器接收到来自客户端的消息时执行 CreateBot()。

```typescript
async OnCreate() {

	 	// 处理 "CreateBot" 消息，该消息使用给定的 userId 创建一个机器人玩家。
    this.onMessage("CreateBot", (client, message) => {
        this.CreateBot(message);
    });
}
```



3-2. 在客户端脚本 BotPlayerManager.ts 中，编写一个函数将 "CreateBot" 消息发送到服务器。

- 执行函数的方法是通过按下按钮发送消息。
- 通过消息将要创建的机器人玩家的用户 ID 作为字符串发送。

:::CodeblockTabs
BotPlayerManager.ts

```typescript
public buttonCreateBot: Button;
public botPlayerId: string;

Start() {	

	 	// 为 "创建机器人" 按钮添加点击监听器，以发送消息以创建一个机器人玩家。
	 	this.buttonCreateBot.onClick.AddListener(() => {
            this._room.Send("CreateBot", this.botPlayerId);
    });
}
```
:::



3-3. 现在，当你运行服务器和运行时，你可以看到当你按下按钮时会创建机器人玩家。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-7RPcD4Sy06GPGzi3Z-LZQ-20240904-102422.png)



## 步骤 4：通过添加机器人玩家来启动世界

当没有足够的玩家来启动世界时，你可以添加机器人玩家来启动世界。

4-1. 在服务器脚本中，在 OnJoin 期间添加以下代码，以检查玩家数量，并在至少有四名玩家时启动世界。

- 在 CreateBot() 中添加一个函数以检查玩家数量。
- 在 StartWorld() 函数中添加一个计数器以记录游戏次数。

:::CodeblockTabs
index.ts

```typescript
 async onJoin(client: SandboxPlayer) {

 	// 在玩家加入后检查房间中的玩家数量。
	this.CheckPlayerNumber();
}

// `CheckPlayerNumber()` 方法检查房间中的玩家数量，并在至少有四名玩家时启动世界。
CheckPlayerNumber() {

	// 将当前房间中的玩家数量打印到控制台。
	console.log(`玩家数量, ${this.state.players.size}`);

	// 如果房间中至少有四名玩家，则启动世界。
	if (this.state.players.size >= 4) {
 	this.StartWorld();
	}
}

// `CreateBot()` 方法用于创建具有给定 `userId` 的机器人玩家。
CreateBot(userId: string) {

	// 使用提供的 `userId` 为机器人玩家生成会话 ID。
	const sessionId = "Bot_" + userId;

	// 检查是否已经存在具有相同会话 ID 的机器人玩家。如果存在，则返回而不创建重复项。
 	if (this.state.players.has(sessionId)) {
	return;
	}

	// 为机器人玩家创建一个新的 `Player` 对象。
	const player: Player = new Player();
 	player.sessionId = sessionId;
	if (userId) {
		player.zepetoUserId = userId;
	}
	player.isBot = true;

	// 使用会话 ID 作为键将机器人玩家添加到状态的玩家映射中。
	this.state.players.set(player.sessionId, player);
	this._botMap.set(sessionId, player);

	// 在添加机器人玩家后检查房间中的玩家数量。
	this.CheckPlayerNumber();
}


private playTime: number = 0;

// `StartWorld()` 方法增加游戏时间并向所有客户端广播 "StartWorld" 消息。
StartWorld() {
		this.playTime += 1;

    // 打印一条消息，指示世界的开始和当前的游戏时间。
    console.log("开始世界！");
    this.broadcast("StartWorld", this.playTime);
} 
```
:::



:::hint{type="success"}
- 在服务器上，当真实玩家加入房间时，会执行 OnJoin。因此，当通过 CreateBot 创建一个 Bot 玩家时，以及当玩家通过 OnJoin 进入时，checkPlayerNumber() 会增加人数。
:::



4-2. 在客户端脚本 BotPlayerManager.ts 中，编写 StartWorld()，当从服务器接收到 StartWorld 消息时执行。

:::CodeblockTabs
BotPlayerManager.ts

```typescript
Start() {

	// 监听来自 `ZepetoWorldMultiplay` 组件的 `RoomJoined` 事件。
	this.zepetoWorldMultiplay.RoomJoined += (room: Room) => {

 	// 为 "StartWorld" 消息类型添加消息处理程序。    
	this._room.AddMessageHandler("StartWorld", (playTime: number) => {
    	this.StartWorld(playTime);
  });   
}

// 当世界以提供的 `playTime` 启动时调用 `StartWorld()` 方法。
StartWorld(playTime: number) {

	// 打印世界启动消息以及 `playTime`。
  console.log(`开始世界 : ${playTime}`);
}
```
:::



4-3. 在运行时，当玩家数量超过 4 个（包括 Bot 玩家）时，您可以在服务器控制台和客户端控制台上看到名为 World Start 的日志。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-Lctng3ajZYOFKBpMbP_UJ-20240904-102422.png)



## 步骤 5：同步 Bot 玩家位置

以下是示例代码，它将添加的机器人玩家移动到本地玩家的位置并同步移动位置。

5-1. 首先，编写代码以在服务器的 index.ts 中接收到来自客户端的消息时移动机器人玩家，`MoveBot`。

```typescript
async OnCreate() {

 	// 处理 "MoveBot" 消息，该消息将机器人玩家移动到指定位置。
	this.onMessage("MoveBot", (client, message) => {
        this.MoveBot(client, message);
 	});
}  

// `MoveBot()` 方法根据接收到的消息将机器人玩家移动到指定位置。
MoveBot(client: SandboxPlayer, message: string) {
    // 解析从客户端接收到的 JSON 消息以提取位置信息。
    const position = JSON.parse(message);

    // 创建一个新的消息对象，包含用户的会话 ID 和解析后的位置信息。
    const newMessage = {
        user: client.sessionId,
        positionX: position.x,
        positionY: position.y,
        positionZ: position.z
    }

    // 将 "MoveBotToPosition" 消息广播给所有客户端，消息数据作为 JSON 字符串。
    this.broadcast("MoveBotToPosition", JSON.stringify(newMessage));
}
```



5-2. 在客户端脚本 BotPlayerManager.ts 中，编写 SendBotPosition()，当按下 buttonCallBot 时将本地玩家位置发送到服务器。

- 然后编写代码，当从服务器接收到消息 MoveBotToPosition 时，将所有 Bot 玩家移动到消息中包含的位置。

:::CodeblockTabs
BotPlayerManager.ts

```typescript
public buttonCallBot: Button;

Start(){    

	// 监听来自 `ZepetoWorldMultiplay` 组件的 `RoomJoined` 事件。
    this.zepetoWorldMultiplay.RoomJoined += (room: Room) => {
    		this._room = room;

        // 为 "StartWorld" 消息类型添加消息处理程序。
        this._room.AddMessageHandler("StartWorld", (playTime: number) => {
            this.StartWorld(playTime);
        });
       
	// 为 "Call Bot" 按钮添加点击监听器，以发送消息以发送 Bot 玩家位置。
	this.buttonCallBot.onClick.AddListener(() => {
				this.SendBotPosition();
	});
}  

// 此方法将本地玩家角色的位置发送到服务器以进行 Bot 移动同步。
SendBotPosition() {

    // 获取本地玩家角色的位置。
    const localPlayerPosition = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character.transform.position;

    // 创建一个包含本地玩家角色的 x、y 和 z 坐标的位置对象。
    const position = {
        x: localPlayerPosition.x,
        y: localPlayerPosition.y,
        z: localPlayerPosition.z
    }

    // 将位置对象转换为 JSON 字符串，并使用 "MoveBot" 消息类型将其发送到服务器。
    this._room.Send("MoveBot", JSON.stringify(position));
    }   

MoveBotToPosition(message) {

    // 解析从客户端接收到的 JSON 消息以提取位置信息。
    const jsonMessage = JSON.parse(message);
    const position = new Vector3(jsonMessage.positionX, jsonMessage.positionY, jsonMessage.positionZ);

    // 将 `_botMapData` 映射中的每个 Bot 角色移动到指定位置，并在 x 和 z 轴上添加一个小的随机偏移。
    this._botMapData.forEach((character: ZepetoCharacter) => {
        // 使用 `MoveToPosition()` 方法将角色移动到指定位置。
        // 在这里，向目标位置添加一个小的随机偏移，以为 Bot 创建自然的移动效果。
        character.MoveToPosition(position + new Vector3(Random.Range(0.5, 1), 0, Random.Range(0.5, 1)));
    });
}
```
:::



5-3. 现在，如果您在运行时创建一个 Bot 玩家并按下 buttonCallBot 按钮，您应该会看到创建的 Bot 玩家移动到本地玩家角色的位置。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-P_Alb5zIa4CoJJONXEvHQ-20240904-102428.png)



### BotPlayerManager.ts 完整代码

:::CodeblockTabs
BotPlayerManager.ts

```typescript
import { Random, Vector3 } from 'UnityEngine';
import { Button } from 'UnityEngine.UI';
import { ZepetoCharacter, ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { Room } from 'ZEPETO.Multiplay';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { ZepetoWorldMultiplay } from 'ZEPETO.World';

export default class BotPlayerManager extends ZepetoScriptBehaviour {

    // 公共属性，用于引用 Inspector 中所需的组件和设置。
    public zepetoWorldMultiplay: ZepetoWorldMultiplay;
    public buttonCreateBot: Button;
    public buttonCallBot: Button;
    public botPlayerId: string;

    // 私有变量，用于存储当前房间和机器人玩家数据。
    private _room: Room;
    private _botMapData: Map<string, ZepetoCharacter> = new Map<string, ZepetoCharacter>();

    Start() {

        // 监听来自 `ZepetoWorldMultiplay` 组件的 `RoomJoined` 事件。
        this.zepetoWorldMultiplay.RoomJoined += (room: Room) => {
            this._room = room;

            // 为 "StartWorld" 消息类型添加消息处理程序。
            this._room.AddMessageHandler("StartWorld", (playTime: number) => {
                this.StartWorld(playTime);
            });
        }

        // 监听来自 `ZepetoPlayers.instance` 的 `OnAddedPlayer` 事件，以处理新添加的玩家。
        ZepetoPlayers.instance.OnAddedPlayer.AddListener((userId: string) => {

            // 使用 `userId` 从房间状态中获取当前玩家数据。
            const currentPlayer = this._room.State.players.get_Item(userId);

            // 检查玩家是否为机器人，如果是，则将其设置为机器人玩家。
            if (currentPlayer.isBot) {
                this.SetBotPlayer(currentPlayer.sessionId);
            }
        });

        // 为 "Create Bot" 按钮添加点击监听器，以发送消息创建机器人玩家。
        this.buttonCreateBot.onClick.AddListener(() => {
            this._room.Send("CreateBot", this.botPlayerId);
        });

        this.zepetoWorldMultiplay.RoomJoined += (room: Room) => {
            this._room = room;

            this._room.AddMessageHandler("MoveBotToPosition", (message: string) => {
                this.MoveBotToPosition(message);
            });
        }

        // 为 "Call Bot" 按钮添加点击监听器，以发送消息发送机器人玩家位置。
        this.buttonCallBot.onClick.AddListener(() => {
            this.SendBotPosition();
        });
    }

    // `SetBotPlayer()` 方法用于将玩家设置为机器人。
    SetBotPlayer(userId: string) {

        // 使用其 `userId` 获取与机器人玩家相关联的 ZEPETO 角色。
        const bot = ZepetoPlayers.instance.GetPlayer(userId).character;

        // 将角色的名称设置为 `userId` 以便识别。
        bot.gameObject.name = userId;

        // 使用其 `userId` 作为键将机器人玩家的数据存储在 `_botMapData` 映射中。
        this._botMapData.set(userId, bot);
    }

    // `StartWorld()` 方法在世界开始时调用，提供的 `playTime`。
    StartWorld(playTime: number) {

        // 打印世界开始消息以及 `playTime`。
        console.log(`Start World : ${playTime}`);
    }

    // 此方法将本地玩家角色的位置发送到服务器以进行机器人移动同步。
    SendBotPosition() {

        // 获取本地玩家角色的位置。
        const localPlayerPosition = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character.transform.position;

        // 创建一个位置对象，包含本地玩家角色的 x、y 和 z 坐标。
        const position = {
            x: localPlayerPosition.x,
            y: localPlayerPosition.y,
            z: localPlayerPosition.z
        }

        // 将位置对象转换为 JSON 字符串，并使用 "MoveBot" 消息类型将其发送到服务器。
        this._room.Send("MoveBot", JSON.stringify(position));
    }

    // 当服务器从客户端接收到 "MoveBot" 消息时调用此方法，并将机器人角色移动到指定位置。
    MoveBotToPosition(message) {

        // 解析从客户端接收到的 JSON 消息以提取位置信息。
        const jsonMessage = JSON.parse(message);
        const position = new Vector3(jsonMessage.positionX, jsonMessage.positionY, jsonMessage.positionZ);

        // 将 `_botMapData` 映射中的每个机器人角色移动到指定位置，并在 x 和 z 轴上添加一个小的随机偏移。
        this._botMapData.forEach((character: ZepetoCharacter) => {
            // `MoveToPosition()` 方法用于将角色移动到指定位置。
            // 在这里，向目标位置添加一个小的随机偏移，以创建自然的机器人移动效果。
            character.MoveToPosition(position + new Vector3(Random.Range(0.5, 1), 0, Random.Range(0.5, 1)));
        });
    }
}
```
:::



### index.ts 服务器完整代码

```text
import { Sandbox, SandboxOptions, SandboxPlayer } from "ZEPETO.Multiplay";
import { DataStorage } from "ZEPETO.Multiplay.DataStorage";
import { Player, Transform, Vector3 } from "ZEPETO.Multiplay.Schema";

export default class extends Sandbox {

    storageMap: Map<string, DataStorage> = new Map<string, DataStorage>();

    // 保存机器人玩家的地图数据为 _botMap
    private _botMap: Map<string, Player> = new Map<string, Player>();
    private playTime: number = 0;

    constructor() {
        super();
    }

    onCreate(options: SandboxOptions) {

        // 当房间对象被创建时调用。
        // 处理房间对象的状态或数据初始化。

        this.onMessage("onChangedTransform", (client, message) => {

            this.state.players.get(client.sessionId);

            const player = this.state.players.get(client.sessionId);

            const transform = new Transform();
            transform.position = new Vector3();
            transform.position.x = message.position.x;
            transform.position.y = message.position.y;
            transform.position.z = message.position.z;

            transform.rotation = new Vector3();
            transform.rotation.x = message.rotation.x;
            transform.rotation.y = message.rotation.y;
            transform.rotation.z = message.rotation.z;

            if (player) {
                player.transform = transform;
            }
        });

        this.onMessage("onChangedState", (client, message) => {
            const player = this.state.players.get(client.sessionId);
            if (player) {
                player.state = message.state;
                player.subState = message.subState;
            }
        });

        // 处理 "CreateBot" 消息，该消息使用给定的 userId 创建一个机器人玩家。
        this.onMessage("CreateBot", (client, message) => {
            this.CreateBot(message);
        });

        // 处理 "MoveBot" 消息，该消息将机器人玩家移动到指定位置。
        this.onMessage("MoveBot", (client, message) => {
            this.MoveBot(client, message);
        });
    }

    // `CreateBot()` 方法用于使用给定的 `userId` 创建一个机器人玩家。
    CreateBot(userId: string) {

        // 使用提供的 `userId` 为机器人玩家生成一个会话 ID。
        const sessionId = "Bot_" + userId;

        // 检查是否已经存在具有相同会话 ID 的机器人玩家。如果存在，则返回而不创建重复。
        if (this.state.players.has(sessionId)) {
            return;
        }

        // 为机器人玩家创建一个新的 `Player` 对象。
        const player: Player = new Player();
        player.sessionId = sessionId;
        if (userId) {
            player.zepetoUserId = userId;
        }
        player.isBot = true;

        // 使用会话 ID 作为键将机器人玩家添加到状态的玩家映射中。
        this.state.players.set(player.sessionId, player);
        this._botMap.set(sessionId, player);

        // 在添加机器人玩家后检查房间中的玩家数量。
        this.CheckPlayerNumber();
    }

    // `CheckPlayerNumber()` 方法检查房间中的玩家数量，并在至少有四名玩家时启动世界。
    CheckPlayerNumber() {

        // 将房间中当前的玩家数量打印到控制台。
        console.log(`玩家数量, ${this.state.players.size}`);

        // 如果房间中至少有四名玩家，则启动世界。
        if (this.state.players.size >= 4) {
            this.StartWorld();
        }
    }

    // `StartWorld()` 方法增加游戏时间并向所有客户端广播 "StartWorld" 消息。
    StartWorld() {
        this.playTime += 1;

        // 打印一条消息，指示世界的开始和当前的游戏时间。
        console.log("开始世界！");
        this.broadcast("StartWorld", this.playTime);
    }

    // `MoveBot()` 方法根据接收到的消息将机器人玩家移动到指定位置。
    MoveBot(client: SandboxPlayer, message: string) {
        // 解析从客户端接收到的 JSON 消息以提取位置信息。
        const position = JSON.parse(message);

        // 创建一个新的消息对象，包含用户的会话 ID 和解析后的位置信息。
        const newMessage = {
            user: client.sessionId,
            positionX: position.x,
            positionY: position.y,
            positionZ: position.z
        }

        // 将 "MoveBotToPosition" 消息广播给所有客户端，消息数据作为 JSON 字符串。
        this.broadcast("MoveBotToPosition", JSON.stringify(newMessage));
    }

    async onJoin(client: SandboxPlayer) {

        // 创建在 schemas.json 中定义的玩家对象并设置初始值。
        console.log(`[OnJoin] 会话 ID : ${client.sessionId}, 哈希码 : ${client.hashCode}, 用户 ID : ${client.userId}`)

        const player = new Player();
        player.sessionId = client.sessionId;

        if (client.hashCode) {
            player.zepetoHash = client.hashCode;
        }
        if (client.userId) {
            player.zepetoUserId = client.userId;
        }

        // [DataStorage] 加载进入玩家的数据存储
        const storage: DataStorage = client.loadDataStorage();

        this.storageMap.set(client.sessionId, storage);

        let visit_cnt = await storage.get("VisitCount") as number;
        if (visit_cnt == null) visit_cnt = 0;

        console.log(`[OnJoin] ${client.sessionId} 的访问计数 : ${visit_cnt}`)

        // [DataStorage] 更新玩家的访问计数，然后保存存储
        await storage.set("VisitCount", ++visit_cnt);

        // 使用会话 ID 管理玩家对象，这是客户端对象的唯一键值。
        // 客户端可以通过将 add_OnAdd 事件添加到玩家对象来检查通过 set 添加的玩家对象的信息。
        this.state.players.set(client.sessionId, player);

        // 在玩家加入后检查房间中的玩家数量。
        this.CheckPlayerNumber();
    }

    onTick(deltaTime: number): void {
        //  它在服务器中每次设置时间时重复调用，并且可以使用 deltaTime 管理某个间隔事件。
    }

    async onLeave(client: SandboxPlayer, consented?: boolean) {

        // 通过设置 allowReconnection，可以保持电路的连接，但在基本指南中立即清理。
        // 客户端可以通过将 add_OnRemove 事件添加到玩家对象来检查已删除的玩家对象的信息。
        this.state.players.delete(client.sessionId);
    }
}
```

