前言

事件机制为我们的游戏开发提供了极大的方便,使得我们能在任意时候指定在什么操作时做什么操作、执行什么样的代码。

由于在恰当的时机会有相应的事件触发,我们能为这些事件指定相应的处理函数,就能在原本的流程中插入各种各样的个性化操作和处理,使得整个流程变得更加丰富。

事件应有的功能

在实现之前,我们首先来分析事件机制应该有的基本功能。

简单来说,事件必须要提供以下几种功能:

绑定事件

触发事件

取消绑定事件

定义事件存储的格式

interface IEvent {
    type: number,
    priority: number, 
    selectorTarget: any, 
    callback: (data) => void
} 

事件绑定

首先来实现事件的绑定,事件绑定必须要指定事件的类型和事件的处理函数。

那么除此之外还需要什么呢?我们是自定义事件,不需要像原生事件一样指定是冒泡阶段触发还是捕获阶段触发,也不需要像jQuery里一样可以额外指定那些元素触发。

而事件函数里面this一般都是当前实例,这个在某些情况下可能不适用,我们需要重新指定事件处理函数运行时的上下文环境。

然而有时候对同类事件,我们还需要对事件进行一个事件优先级的处理。

因此确定事件绑定时三个参数分别为:事件类型、事件处理函数、事件处理函数执行上下文、事件优先级。

on(type: number, callback: any, selectorTarget?: any, priority: number = 0) {
    if (!type || !callback) { 
        return;
    }
    let sub_cache: Array<IEvent> = this.event_cache[type] || [];
    let hasSame = false;
    for (let i = 0; i < sub_cache.length; i++) {
        if (sub_cache[i].callback === callback) {
            hasSame = true;
            break;
        }
    }
    if (hasSame) {
        return;
    } 
    let ievent: IEvent = {
        type: type,
        priority: priority, 
        selectorTarget: selectorTarget,
        callback: callback
    };
    if (priority > 0) {
        let isPush = true;
        for(let i = sub_cache.length - 1; i >=0; i--) {
            if ( sub_cache[i].priority > priority) {
                sub_cache.splice(i + 1, 0, ievent);
                isPush = false;
                break;
            }
        }
        if (isPush) {
            sub_cache.splice(0, 0, ievent);
        }
    } else {
        sub_cache.push(ievent);
    }
    this.event_cache[type] = sub_cache;
} 

事件触发

事件触发的基本功能就是去执行用户所绑定的事件,所以只用在事件触发时去检查有没有指定的执行函数,如果有则调用即可。

另外事件触发实际就是用户指定的处理函数执行的过程,而能进行很多个性化操作也都是在用户指定的事件处理函数中进行的,因此仅仅是执行这个函数还不够。还必须为当前函数提供必要的信息。因此事件触发时,事件处理函数的实参中必须包含当前事件的所传递的参数。

emit(type: number, params?: any) {
    if (!type) {
        return;
    }
    let sub_cache: Array<IEvent> = this.event_cache[type];
    if (!sub_cache) {
       return;
    }
    for (let i = 0; i < sub_cache.length; i++) {
        let ievent = sub_cache[i];
        if (ievent.selectorTarget) {
            ievent.callback.bind(ievent.selectorTarget)(params);
        } else {
            ievent.callback(params)
        }
    }
} 

事件取消

事件取消中需要做的就是已经绑定的事件处理函数移除掉即可

 off(type: number, callback: any) {
    if (!type || !callback) {
       return;
    }
    let sub_cache: Array<IEvent>  = this.event_cache[type];
    if (!sub_cache) {
        return;
    }
    for (let i = 0; i < sub_cache.length; i++) {
        if (sub_cache[i].callback === callback) {
            sub_cache.splice(i, 1);
            break;
        }
    }
    if (sub_cache.length == 0) {
        delete this.event_cache[type];
    }
} 




关注【游戏讲坛】微信公众号,获取最新动态!