[开发者心得] 简单实现一个组队系统

[复制链接]
1266 |1
属于你的雨天 发表于 2023-7-31 11:15:23 | 显示全部楼层 |阅读模式
本帖最后由 属于你的雨天 于 2023-7-31 11:15 编辑

功能介绍
组队系统简单来说就是一个匹配机制系统,本系统中涉及到,加入匹配队列、离开匹配队列、加入等待队列等的同步操作。

一分钟快速上手
核心实现逻辑,就是在服务端做指令分发与同步操作。
其中核心API 就三个 C端的 reqStartMatch reqCancelMatch S端的 reqReMatch。
核心逻辑如下 就是在S端处理好 等待匹配的队列与 即将开始的队列以及同步操作。


export class MatchModuleS extends ModuleS<MatchModuleC, null>{

    /**即将开始的玩家队列 */
    private _willStartList: number[] = [];

    /**等待匹配的玩家队列 */
    private _waitList: number[] = [];

    /**当前匹配状态 */
    public curMatchState: EMatchState = EMatchState.Waiting;

    /**临时存储开始游戏的时间戳 */
    private _startGameTime: number = Date.now();
    async onStart() { }

    /**匹配时间 */
    private _matchGameTime: number = 30000;

    public onUpdate(dt: number): void {
        if (this.curMatchState === EMatchState.Waiting && this._willStartList.length > 0 && Date.now() >= this._startGameTime) {
            this.matchSuccessCallback();
        }
    }

    public onPlayerJoined(player: Gameplay.Player): void { }

    public onPlayerEnterGame(player: Gameplay.Player): void {
        let pid: number = player.getPlayerID();
        console.log("🚀 ~ file: MatchModuleS.ts:48 ~ MatchModuleS ~ onPlayerEnterGame ~ reenter", pid)
        this.playerCancelOrLeave(pid);
    }

    public onPlayerLeft(player: Gameplay.Player): void {
        let pid: number = player.getPlayerID();
        this.playerCancelOrLeave(pid);
    }

    /**玩家取消匹配或者离开 直接从所有列表中删除 */
    private playerCancelOrLeave(pid: number) {
        // 从即将开始游戏的列表中删除
        let willStartIndex = this._willStartList.indexOf(pid);
        if (willStartIndex >= 0) {
            let leavePid = this._willStartList[willStartIndex];
            this._willStartList.forEach(pid => {
                this.getClient(pid).net_resRemoteMatchList(leavePid);
            });
            this._willStartList.splice(willStartIndex, 1);
        }

        // 从等待列表中删除
        let waitIndex = this._waitList.indexOf(pid);
        if (waitIndex >= 0) {
            this._waitList.splice(waitIndex, 1);
            this.getClient(pid).net_resNoticeRoleAction("你已取消匹配!");
        }
    }

    /**匹配成功回调 */
    public matchSuccessCallback() {
        this.curMatchState = EMatchState.Going;
        if (this._willStartList.length > 0) {
            // 通知其他人正在游戏中
            Gameplay.getAllPlayers().forEach(player => {
                let pid: number = player.getPlayerID();
                if (this._willStartList.indexOf(pid) < 0) {
                    this.getClient(player).net_resShowGaming();
                }
            });
            // 通知队列中的人开始游戏
            for (const pid of this._willStartList) {
                this.getClient(pid).net_resStartGame("Game Start!");
            }
        }
        this._willStartList = [];
    }

    /**响应开始匹配游戏 */
    public net_resStartMatch(player?: Gameplay.Player) {
        if (!player) return;
        let pid: number = player.getPlayerID();

        // 若是在游戏中则加入等待队列
        if (this.curMatchState == EMatchState.Going) {
            if (this._waitList.indexOf(pid) < 0) {
                this._waitList.push(pid);
                this.getClient(pid).net_resNoticeRoleAction("你已加入等待匹配队列了......");
            } else {
                this.getClient(pid).net_resNoticeRoleAction("你已经在等待匹配队列中了......");
            }
            return;
        }

        // 直接加入即将开始的游戏的队列
        if (this.curMatchState == EMatchState.Waiting) {
            if (this._willStartList.length === 0) {
                this._startGameTime = Date.now() + this._matchGameTime;
            }
            if (this._willStartList.indexOf(pid) < 0) {
                this._willStartList.push(pid);
                let showCountTime = this._startGameTime - Date.now();
                for (const roleID of this._willStartList) {
                    this.getClient(roleID).net_resJoinMatchList(this._willStartList, showCountTime);
                }
            } else {
                this.getClient(pid).net_resNoticeRoleAction("你已经在匹配队列中了......");
            }
        }
    }

    /**响应取消匹配游戏 */
    public net_resCancelMatch(player?: Gameplay.Player) {
        if (!player) return;
        let pid: number = player.getPlayerID();
        pid && this.playerCancelOrLeave(pid);
    }

    /**重新匹配 */
    public reqReMatch() {
        this._willStartList = [];
        if (this._waitList.length > 0) {
            this._willStartList.push(...this._waitList);
            this._startGameTime = Date.now() + this._matchGameTime;
            for (const pid of this._willStartList) {
                this.getClient(pid).net_resJoinMatchList(this._willStartList, this._matchGameTime);
            }
            this._waitList = [];
        }
        this.curMatchState = EMatchState.Waiting;
    }

    /**测试修改匹配时间 */
    public changeMatchTime(time: number) {
        if (isNaN(time)) return;
        let newStartTime: number = time * 1000;
        this._startGameTime = Date.now() + newStartTime;
        for (const pid of this._willStartList) {
            this.getClient(pid).net_resJoinMatchList(this._willStartList, newStartTime);
        }
    }
}


演示效果如下

附上demo 编辑器版本是:Online_v0.25.0.4
matchModule.zip (116.85 KB, 下载次数: 72)
回复

使用道具 举报

kk 发表于 2023-7-31 17:06:02 | 显示全部楼层
6
回复

使用道具 举报

热门版块
快速回复 返回顶部 返回列表