消息机制--游戏的事件侦听模块设计

本文分享了在Egret引擎中实现游戏消息机制的代码示例,包括消息监听、触发及处理流程,适用于游戏各模块间的事件传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

游戏中一定有消息机制,负责游戏各模块间的消息、事件传递,下面是我自己在Egret中用到的事件侦听模块代码,分享给大家看看,也欢迎大家讨论更好的实现。

MessageCenter.ts文件

/**
 * 消息处理类
 */
class MessageCenter {
    private dict:any;
    private eVec:Array<MessageVo>;
    private lastRunTime:number;
    private type:number;

    /**
     * 构造函数
     * @param type 0:使用分帧处理 1:及时执行
     */
    public constructor(type:number) {
        this.type = type;
        this.dict = {};
        this.eVec = new Array<MessageVo>();
        this.lastRunTime = 0;
        if (this.type == 0) {
            egret.setInterval(this.run, this, 20);
        }
    }

    /**
     * 获取一个单例
     * @returns {any}
     */
    public static getInstance<T extends BaseClass>(...args: any[]): T | any {
        var Class: any = this;
        if (!Class._instance) {
            Class._instance = new Class(...args);
        }
        return Class._instance as T;
    }

    /**
     * 清空处理
     */
    public clear() {
        this.dict = {};
        this.eVec.splice(0);
    }

    /**
     * 添加消息监听
     * @param type 消息唯一标识
     * @param listener 侦听函数
     * @param listenerObj 侦听函数所属对象
     *
     */
    public addListener(type:string, listener:Function, listenerObj:any):void {
        var arr:Array<any> = this.dict[type];
        if (arr == null) {
            arr = new Array<any>();
            this.dict[type] = arr;
        }

        //检测是否已经存在
        var i:number = 0;
        var len:number = arr.length;
        for (i; i < len; i++) {
            if (arr[i][0] == listener && arr[i][1] == listenerObj) {
                return;
            }
        }

        arr.push([listener, listenerObj]);
    }

    /**
     * 移除消息监听
     * @param type 消息唯一标识
     * @param listener 侦听函数
     * @param listenerObj 侦听函数所属对象
     */
    public removeListener(type:string, listener:Function, listenerObj:any):void {
        var arr:Array<any> = this.dict[type];
        if (arr == null) {
            return;
        }

        var i:number = 0;
        var len:number = arr.length;
        for (i; i < len; i++) {
            if (arr[i][0] == listener && arr[i][1] == listenerObj) {
                arr.splice(i, 1);
                break;
            }
        }

        if (arr.length == 0) {
            this.dict[type] = null;
            delete this.dict[type];
        }
    }

    /**
     * 移除某一对象的所有监听
     * @param listenerObj 侦听函数所属对象
     */
    public removeAll(listenerObj:any):void {
        var keys = Object.keys(this.dict);
        for (var i:number = 0, len = keys.length; i < len; i++) {
            var type = keys[i];
            var arr:Array<any> = this.dict[type];
            for (var j = 0; j < arr.length; j++) {
                if (arr[j][1] == listenerObj) {
                    arr.splice(j, 1);
                    j--;
                }
            }

            if (arr.length == 0) {
                this.dict[type] = null;
                delete this.dict[type];
            }
        }
    }

    /**
     * 触发消息
     * @param type 消息唯一标识
     * @param param 消息参数
     *
     */
    public dispatch(type:string, ...param:any[]):void {
        if (this.dict[type] == null) {
            return;
        }

        var vo:MessageVo = ObjectPool.pop(MessageVo);
        vo.type = type;
        vo.param = param;
        if (this.type == 0) {
            this.eVec.push(vo);
        }
        else if (this.type == 1) {
            this.dealMsg(vo);
        }
        else {
            Log.trace("MessageCenter未实现的类型");
        }
    }

    /**
     * 运行
     *
     */
    private run():void {
        var currTime:number = egret.getTimer();
        var inSleep:boolean = currTime - this.lastRunTime > 100;
        this.lastRunTime = currTime;
        if (inSleep) {
            while (this.eVec.length > 0) {
                this.dealMsg(this.eVec.shift());
            }
        } else {
            while (this.eVec.length > 0) {
                this.dealMsg(this.eVec.shift());
                if ((egret.getTimer() - currTime) > 5) {
                    break;
                }
            }
        }
    }

    /**
     * 处理一条消息
     * @param msgVo
     */
    private dealMsg(msgVo:MessageVo):void {
        var listeners:Array<any> = this.dict[msgVo.type];
        var i:number = 0;
        var len:number = listeners.length;
        var listener:Array<any> = null;
        while (i < len) {
            listener = listeners[i];
            listener[0].apply(listener[1], msgVo.param);
            if (listeners.length != len) {
                len = listeners.length;
                i--;
            }
            i++;
        }
        msgVo.dispose();
        ObjectPool.push(msgVo);
    }
}

class MessageVo {
    public type:string;
    public param:any[];

    public constructor() {
    }

    public dispose():void {
        this.type = null
        this.param = null;
    }
}

TestA.ts注册消息响应1

MessageCenter.getInstance(0).addListener("EnterForeground", this.dealWithEnterForegroundQuery1, this);

TestB.ts注册消息响应1

MessageCenter.getInstance(0).addListener("EnterForeground", this.dealWithEnterForegroundQuery2, this);

TestC.ts发送消息通知

App.NotificationCenter.dispatch("EnterForeground");

TestA,TestB都可以收到"EnterForeground"消息通知,然后分别执行对应代码即可。
发送通知的时候,也可以传递参数,在接受消息处理逻辑的函数,接受对应参数即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值