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);
            
            // 在客户端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜", true, 10, 5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name, "玩家名")
            LeaderboardModule.addField(FieldType.PointNumber, "关卡号")
            LeaderboardModule.showRankField("排名", null, "未上榜")
        }

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

        }
    }
}
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);
            
            // 在客户端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜", true, 10, 5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name, "玩家名")
            LeaderboardModule.addField(FieldType.PointNumber, "关卡号")
            LeaderboardModule.showRankField("排名", null, "未上榜")
        }

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

        }
    }
}

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);
            
            // 在客户端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜", true, 10, 5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name, "玩家名")
            LeaderboardModule.addField(FieldType.PointNumber, "关卡号")
            LeaderboardModule.showRankField("排名", null, "未上榜")
        }

        if (SystemUtil.isServer()) {
            // 设置存储环境
            DataStorage.setTemporaryStorage(SystemUtil.isPIE)   
            // 数据存储逻辑
            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)
            })



            // 当玩家进入游戏,向排行榜添加一条数据
            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);
            
            // 在客户端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜", true, 10, 5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name, "玩家名")
            LeaderboardModule.addField(FieldType.PointNumber, "关卡号")
            LeaderboardModule.showRankField("排名", null, "未上榜")
        }

        if (SystemUtil.isServer()) {
            // 设置存储环境
            DataStorage.setTemporaryStorage(SystemUtil.isPIE)   
            // 数据存储逻辑
            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)
            })



            // 当玩家进入游戏,向排行榜添加一条数据
            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
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);

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

            // 当游戏运行在编辑器上,是获取不到233昵称的 
            if(SystemUtil.isPIE){ 
                player.character.displayName = "玩家名"+player.userId 
            }else{ 
                player.character.displayName = AccountService.getNickName() 
            } 
            
            
            // 在客户端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜",true,10,5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name,"玩家名")
            LeaderboardModule.addField(FieldType.PointNumber,"关卡号")
            LeaderboardModule.showRankField("排名",null,"未上榜")
            
        }

        if(SystemUtil.isServer()){
            // 设置存储环境
            DataStorage.setTemporaryStorage(SystemUtil.isPIE)
            // 数据存储逻辑
            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)
            })



            // 当玩家进入游戏,向排行榜添加一条数据
            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);

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

            // 当游戏运行在编辑器上,是获取不到233昵称的 
            if(SystemUtil.isPIE){ 
                player.character.displayName = "玩家名"+player.userId 
            }else{ 
                player.character.displayName = AccountService.getNickName() 
            } 
            
            
            // 在客户端设置排行榜的样式
            LeaderboardModule.setStyle("排行榜",true,10,5)
            // 设置排行榜的字段(玩家名称,关卡号)
            LeaderboardModule.addField(FieldType.Name,"玩家名")
            LeaderboardModule.addField(FieldType.PointNumber,"关卡号")
            LeaderboardModule.showRankField("排名",null,"未上榜")
            
        }

        if(SystemUtil.isServer()){
            // 设置存储环境
            DataStorage.setTemporaryStorage(SystemUtil.isPIE)
            // 数据存储逻辑
            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)
            })



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


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

}

5.在HelperUI中,添加排行榜按钮

打开HelperUI,拖动一个文本按钮到图中位置,并将按钮名字修改为mLeaderBoard_btn,最后点击“导出所有脚本”

image-20231031110459053

HelperUI脚本中,添加打开排行榜的逻辑:

ts
import { LevelManager } from "../LevelManager";
import HelperUI_Generate from "../ui-generate/HelperUI_generate";

export class HelperUI extends HelperUI_Generate{
    protected onAwake(): void {

        // 复位功能
        this.mRest_btn.onPressed.add(()=>{
            LevelManager.instance.jumpToPoint()
        })


        // 跳关功能
        this.mJump_btn.onPressed.add(()=>{
            LevelManager.instance.jumpToPoint( Number(this.mJump_input.text))
        })

        this.mLeaderBoard_btn.onPressed.add(()=>{
            LeaderboardModule.showPanel()
        })
    }
}
import { LevelManager } from "../LevelManager";
import HelperUI_Generate from "../ui-generate/HelperUI_generate";

export class HelperUI extends HelperUI_Generate{
    protected onAwake(): void {

        // 复位功能
        this.mRest_btn.onPressed.add(()=>{
            LevelManager.instance.jumpToPoint()
        })


        // 跳关功能
        this.mJump_btn.onPressed.add(()=>{
            LevelManager.instance.jumpToPoint( Number(this.mJump_input.text))
        })

        this.mLeaderBoard_btn.onPressed.add(()=>{
            LeaderboardModule.showPanel()
        })
    }
}