MK框架也有消息号,但是在用户层可以隐藏,重要的是实现这两种方式我都没改框架层后续还可以扩展更多
并且支持两种消息号的方式
第一种
message Package {
/** 消息号 */
int32 id = 1;
/** 消息体 */
bytes data = 2;
}
第二种
message test {
int32 id [default = 100];
}
MK框架也有消息号,但是在用户层可以隐藏,重要的是实现这两种方式我都没改框架层后续还可以扩展更多
并且支持两种消息号的方式
第一种
message Package {
/** 消息号 */
int32 id = 1;
/** 消息体 */
bytes data = 2;
}
第二种
message test {
int32 id [default = 100];
}
底层看你自己选择了,萝卜青菜各有所爱,我是基于 proto 开发的
好好好,cv一下
不明白你这两种方式有啥区别,我是为了更贴合真实RPC调用才这样实现的,比如远程服务器有一个RPC服务:
Global.remotingInvoke("DemoService:sum", [1, 1000]).then(res => {
console.log("远程计算两数之间所有数字之和:" + res);
}).catch(err => {
console.log(err);
});
还可以如下这样:
服务端:
我是从 tsrpc 这个项目中第一次看到这种用法,这种无论怎样,都是要有一个数据和消息的关连关系来辅助类型推断。
要么在消息数据体 data 中,要么是对应关系映射表。
其中映射表的方式除了集中式(事件一般是集中式)。还可以用 global declare {
interface XX {
[event_name]: event_data_type
}
}
进行分布式定义。而这种机制可以泛化到【类型到类】【类型到函数】【类型到类型】,这种机制的复用让理解成本更低。
TS的类型比C#要强大,很多C#办不到或很难办到的,用TS就比较好实现。
按我的理解事件系统是为了解决“你中无我,我中无你,但是我们俩还想通信”,或者是为了达到“你中无我,我中无你”的状态而引入事件系统以求解耦。还有一种情况比较简单“你中有我,但是我中不能有你,因为可能循环引用”,虽然可以用接口去解决,但是也可以用事件系统达到目的。
题主的事件系统能搞这么复杂,也是让人头皮发麻,没有看下去的欲望,我一度以为我理解的事件系统和题主理解的不是一回事,我都懒得造轮子,感觉造出来也没啥意义,直接用的EventEmitter3,只是简单封装了下,封装的目的是为了方便使用仅此而已。
源码:
我觉得这就够了,而且type申明的类型构建后也擦除了
这个类型 最后其实就是直接调用了那个函数本身 不算是发消息就是找到那个对象的地址直接发消息差不多的样子,事件系统一般就是向世界抛出一个事件谁监听了这个时间 谁就可以获取到这个事件的数据
直接用game.emit 感觉一样的呀 
就是为了解耦才用事件,结果还给事件类型耦合起来…
楼主是为了解决数据类型约束,不过方案过于复杂
耦合的主体有区别,你说的是调用主体解耦。楼主说的是事件派发的数据类型约束
你这个 IEvent 类型方案其实和 MK 的类似,我以前尝试过,结论是:不好用。会有几个问题点
1、集中式的声明。有些逻辑其实是分包的,这个 IEvent 没有支持分布式定义。(当然 declare global 可解决这个问题)
2、所有事件都要声明(这个比较蛋疼,越用越难受)
3、事件处理函数有时候是多个函数。有的函数只心事件,不关心参数,通常是类似 refreshUI() 的刷新函数,而注册时就会报红,导致必须加 as any 这类的特殊处理。难受。
我的方案就是,通过约定做隐式数据约束。
emit<DATA = any>(name: string | number, data: DATA = null)
on<DATA = any>(name: string | number, cb: (data?: DATA) => any, ctx: any): EventBox;
于是,在开发的时候:
1、派发的地方有数据,前面的类型一定要补上,方便知道是什么数据类型;
2、监听的地方,一定根据派发的数据约束写上数据约束(不写表示只关心事件本身);
3、在新增消息处理函数的时候,只要查一下别的地方怎么用,然后做同样的约束。
4、派发数据更改时(重构)的时候。也是查下消息的引用。统一修改各个监听函数的处理逻辑的。
这套逻辑流程用起来最舒服。
ikun 2.5 year

最佩服一个事件系统都可以有自己一套理论的人了 
两个emitter 更难用