Skip to content
排行榜

排行榜

排行榜是游戏中最常见的一个功能,此功能已经内置在编辑器了,本节课就来教大家如何使用吧!

1.内置排行榜的构成

排行榜如下图所示(黑框框起来的部分):

①黄色框选部分:该部分为排行榜的标题,这个标题的文本可以自定义。

②红色框选部分:该部分为排行榜的字段,字段数量以及字段内容可以自行定义。

③蓝色框选部分:该部分为排行榜中的一条数据,排行榜会自动根据数据进行排序。

image-20230905182137433

2.设置排行榜的样式

编辑器内置了一个排行榜模块,可以通过LeaderboardModule来调用到与之相关的各种功能。

我们首先需要设置排行榜的样式,设置样式的代码需要在服务端进行设置。所以我们来到GameStart脚本中添加相关代码:

此次添加的主要内容:

定义了一个枚举FieldType,用来表示所有的排行榜字段类型

通过LeaderboardModule.setStyle设置了排行榜的标题内容以及字段间距

通过LeaderboardModule.addField向排行榜添加自定义字段

通过LeaderboardModule.showRankField向排行榜添加排名字段

ts
import { LevelData } from "./LevelData";
import { LevelManager } from "./LevelManager";
import { HelperUI } from "./UI/HelperUI";

/**所有的排行榜字段 */ 
export enum FieldType {
    Name,
    PointNumber
}

@Component
export default class GameStart extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {

        if (SystemUtil.isClient()) {
            LevelManager.instance.init()
            UIService.show(HelperUI);
        }

        if (SystemUtil.isServer()) {
            // 数据存储逻辑
            Event.addClientListener("SavePoint", (player: Player, pointNumber: number) => {
                // 使用数据中心存储数据
                // 改变数据
                DataCenterS.getData(player, LevelData).pointNumber = pointNumber
                // 存储数据
                DataCenterS.getData(player, LevelData).save(true)
            })

            // 在服务端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜", true, 10, 5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name, "玩家名")
            LeaderboardModule.addField(FieldType.PointNumber, "关卡号")
            LeaderboardModule.showRankField("排名", null, "未上榜")

        }
    }
}
import { LevelData } from "./LevelData";
import { LevelManager } from "./LevelManager";
import { HelperUI } from "./UI/HelperUI";

/**所有的排行榜字段 */ 
export enum FieldType {
    Name,
    PointNumber
}

@Component
export default class GameStart extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {

        if (SystemUtil.isClient()) {
            LevelManager.instance.init()
            UIService.show(HelperUI);
        }

        if (SystemUtil.isServer()) {
            // 数据存储逻辑
            Event.addClientListener("SavePoint", (player: Player, pointNumber: number) => {
                // 使用数据中心存储数据
                // 改变数据
                DataCenterS.getData(player, LevelData).pointNumber = pointNumber
                // 存储数据
                DataCenterS.getData(player, LevelData).save(true)
            })

            // 在服务端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜", true, 10, 5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name, "玩家名")
            LeaderboardModule.addField(FieldType.PointNumber, "关卡号")
            LeaderboardModule.showRankField("排名", null, "未上榜")

        }
    }
}

3.向排行榜 添加/删除/设置 数据

每当有玩家进入房间的时候,就需要向排行榜上添加一条数据;同时每当玩家通过新的检查点的时候,就需要更新排行榜上面的关卡号;最后,每当有玩家退出房间的时候,就需要将对应玩家的数据从排行榜上移除。

还是在GameStart脚本中添加逻辑:

此次添加的主要内容:

在服务端使用Player.onPlayerJoin来监听玩家进入房间的事件,然后再调用LeaderboardModule.addPlayer来向排行榜上添加数据。

在服务端使用Player.onPlayerLeave来监听玩家离开房间的事件,然后再调用LeaderboardModule.removePlayer来从排行榜上移除数据。

在SavePoint事件触发的时候,通过LeaderboardModule.setPlayerValue设置字段数据。

ts
import { LevelData } from "./LevelData";
import { LevelManager } from "./LevelManager";
import GameUI from "./UI/GameUI";
import { HelperUI } from "./UI/HelperUI";

/**所有的排行榜字段 */
export enum FieldType {
    Name,
    PointNumber
}

@Component
export default class GameStart extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {

        if (SystemUtil.isClient()) {
            LevelManager.instance.init()
            UIService.show(HelperUI);
        }

        if (SystemUtil.isServer()) {
            // 数据存储逻辑
            Event.addClientListener("SavePoint", (player: Player, pointNumber: number) => {
                // 使用数据中心存储数据
                // 改变数据
                DataCenterS.getData(player, LevelData).pointNumber = pointNumber
                // 存储数据
                DataCenterS.getData(player, LevelData).save(true)

                LeaderboardModule.setPlayerValue(player, FieldType.PointNumber, pointNumber)
                LeaderboardModule.setPlayerValue(player, FieldType.Name, player.character.displayName)
            })

            // 在服务端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜", true, 10, 5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name, "玩家名")
            LeaderboardModule.addField(FieldType.PointNumber, "关卡号")
            LeaderboardModule.showRankField("排名", null, "未上榜")

            // 当玩家进入游戏,向排行榜添加一条数据
            Player.onPlayerJoin.add((player: Player) => {
                LeaderboardModule.addPlayer(player)
            })


            // 当玩家退出游戏,将数据从排行榜上删除
            Player.onPlayerLeave.add((player: Player) => {
                LeaderboardModule.removePlayer(player)
            })
        }
    }
}
import { LevelData } from "./LevelData";
import { LevelManager } from "./LevelManager";
import GameUI from "./UI/GameUI";
import { HelperUI } from "./UI/HelperUI";

/**所有的排行榜字段 */
export enum FieldType {
    Name,
    PointNumber
}

@Component
export default class GameStart extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {

        if (SystemUtil.isClient()) {
            LevelManager.instance.init()
            UIService.show(HelperUI);
        }

        if (SystemUtil.isServer()) {
            // 数据存储逻辑
            Event.addClientListener("SavePoint", (player: Player, pointNumber: number) => {
                // 使用数据中心存储数据
                // 改变数据
                DataCenterS.getData(player, LevelData).pointNumber = pointNumber
                // 存储数据
                DataCenterS.getData(player, LevelData).save(true)

                LeaderboardModule.setPlayerValue(player, FieldType.PointNumber, pointNumber)
                LeaderboardModule.setPlayerValue(player, FieldType.Name, player.character.displayName)
            })

            // 在服务端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜", true, 10, 5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name, "玩家名")
            LeaderboardModule.addField(FieldType.PointNumber, "关卡号")
            LeaderboardModule.showRankField("排名", null, "未上榜")

            // 当玩家进入游戏,向排行榜添加一条数据
            Player.onPlayerJoin.add((player: Player) => {
                LeaderboardModule.addPlayer(player)
            })


            // 当玩家退出游戏,将数据从排行榜上删除
            Player.onPlayerLeave.add((player: Player) => {
                LeaderboardModule.removePlayer(player)
            })
        }
    }
}

4.将角色头顶昵称设置为233昵称

当游戏发布到线上之后,角色的头顶昵称一般都会使用233的用户昵称,具体代码如下:

GameStart脚本

在客户端启动的时候,通过 SystemUtil.isPIE 判断运行环境是编辑器环境还是线上环境。

如果是编辑器环境,就使用玩家名+userID的形式设置头顶昵称;

如果是线上环境,就通过AccountService.getNickName()获取到233昵称并设置。

ts
// 省略代码
......

@Component
export default class GameStart extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {

        if (SystemUtil.isClient()) {
            LevelManager.instance.init()
            UIService.show(HelperUI);

            // 将头顶昵称设置为233昵称
            const player = Player.localPlayer

            // 当游戏运行在编辑器上,是获取不到233昵称的
            if (SystemUtil.isPIE) {
                player.character.displayName = "玩家名" + player.userId
            } else {
                player.character.displayName = AccountService.getNickName()
            }

        }
        // 省略代码
        ......
		
    }
}
// 省略代码
......

@Component
export default class GameStart extends Script {

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {

        if (SystemUtil.isClient()) {
            LevelManager.instance.init()
            UIService.show(HelperUI);

            // 将头顶昵称设置为233昵称
            const player = Player.localPlayer

            // 当游戏运行在编辑器上,是获取不到233昵称的
            if (SystemUtil.isPIE) {
                player.character.displayName = "玩家名" + player.userId
            } else {
                player.character.displayName = AccountService.getNickName()
            }

        }
        // 省略代码
        ......
		
    }
}