Skip to content

MailBox

云风 edited this page Jan 22, 2024 · 1 revision

消息信箱

信箱 (mailbox) 是 ECS 的一部分,它是对 ecs 基础功能的一个补充。

在开发 Ant 的过程中,我们发现只有 System 和 Component 不能满足所有的需要。数据如果只存在于 component 中,有些信息用 component 传递很不方便。所以,我们增加了消息和信箱的概念。

消息广播

一条消息是由多个 lua 值构成的 lua 数组组成,第一个值通常是字符串。

world:pub { "message_name", ... }

这样就可以广播一条消息,消息的第一个值约定用来区分消息类型,它是一个表示消息是什么的字符串。

消息信箱

在同一个 Lua 虚拟机内,只有可以访问 world 对象,就可以通过订阅消息创建出一个信箱:

local mb = world:sub { "message_name" }

这样就构造了一个信箱,所有第一个值为 "message_name" 的消息都会发到这个信箱内。信箱也可以匹配不止一个 Lua 值。

消息是广播的。所以,你可以为相同的消息前缀创建多个信箱,每个信箱都会收到相同的消息。消息只会投递到 pub 消息那一刻之前创建出来的信箱中。如果你先 pub 了一条消息,之后才创建可以截获这条消息的信箱,那么该信箱是不会收到这条消息的。

如果消息在广播那一刻没有发现有任何信箱会收到消息,该消息就立刻被销毁。

信箱可以通过 world:unsub() 销毁。

消息的 close 回调

如果消息中包含的 Lua 值需要在消息被销毁时做一些回收工作,固然,你可以给这些值加上 gc 方法,但更好的方法是给消息加一个 .close 函数。消息被销毁时会主动调用它,这个函数比Lua 的 gc 方法调用更即时。

消息处理

你可以在 ecs 系统中找到一个合适的 stage 实现一个消息处理函数。使用 for _, message, args in mailbox:unpack() 就可以将信箱中的消息逐条取出。

系统消息

Ant 引擎会将交互消息,如鼠标、键盘、手势等消息以系统消息的形式广播出去。如果你的游戏需要处理这些消息,创建信箱捕获它们,并在合适的 stage 里遍历信箱处理这些消息。注意:和许多其它游戏引擎不同,这些交互事件并不是通过 callback 函数实现的,而是通过信箱。如果你不创建对应的信箱,消息就会被抛弃掉;引擎也没有指定特定的 stage 处理它们,你可以在你喜欢的任何 stage 处理这些消息。和 callback 机制不同,pipeline + stage 的机制可以让你明确这些交互消息处理的时机,而 callback 机制下,你并不知道回调函数发生在什么时候。

例如,如果你想捕获键盘消息,在系统的初始化阶段创建一个信箱:

local kb_mb         = world:sub {"keyboard"}

在合适的 stage 中,遍历这个信箱:

for _, key, press, state in kb_mb:unpack() do
 	on_key(key, press)
end

这样你就模拟了 on_key 这个回调函数。


以下列出了用户会关心的大部分现有的系统消息。这个文档很可能过时,建议写一些实现的代码测试这些消息以了解消息的具体含义。

keyboard

  1. type : "keyborad"
  2. press : true / false 按下或抬起。
  3. state : 系统给出的数字状态值,包含有 ctrl shift 等按键的状态。

mouse

  1. type : "mouse"
  2. button : "LEFT" / "RIGHT" / "MIDDLE"
  3. action : "MOVE" / "DOWN" / "UP"
  4. x : X 坐标
  5. y : Y 坐标

touch

  1. type : "touch"
  2. x : X 坐标
  3. y : Y 坐标
  4. touchid
  5. state

gesture

  1. type : "gesture"
  2. what : "tap" / "pinch" / "longpress" / "pan" / "swipe"
  3. 根据不同手势,有不同的参数

size

  1. type : "size"
  2. width : 窗口改变大小后的宽度
  3. height : 窗口改变大小后的高度

dropfiles

  1. type : "dropfiles"
  2. filename : 从外部拖拽进窗口的文件名,供编辑器使用。
Clone this wiki locally