Listener 监听器
什么是监听器
Listener 监听器类用于监听某个事件的发生,并作出相应的处理。
例如,下面的代码创建了一个监听鼠标按下的事件:
// 监听器的回调函数
auto callback = [](Event* evt)
{
// 判断事件类型是否是鼠标按下
if (evt->type == Event::MouseDown)
{
// 鼠标按下事件发生了
// 作出相应处理
}
};
// 创建监听器
auto lis = gcnew Listener(callback);
// 让某个节点使用这个监听器
node->addListener(lis);
上面的代码也许晦涩难懂,简单来说,当一个事件发生时,事件会逐一发送给每一个节点(node),节点再将事件转发给监听器,监听器收到事件时会调用回调函数(callback)来处理这个事件。
监听器可以监听到的事件有以下几种:
// 事件类型枚举
enum Type
{
MouseMove, // 鼠标移动
MouseDown, // 鼠标按下
MouseUp, // 鼠标抬起
MouseWheel, // 鼠标滚轮滑动
KeyDown, // 按键按下
KeyUp // 按键抬起
};
下面的回调函数示例给出了每种类型事件的处理方式:
// 监听器的回调函数
// 展示了所有事件的处理方式
auto callback = [](Event* evt)
{
if (evt->type == Event::MouseMove)
{
// 鼠标移动事件发生了
// 将事件类型转换为事件的实际类型
auto mouseEvt = (MouseMoveEvent*)evt;
mouseEvt->x; // 鼠标 x 坐标
mouseEvt->y; // 鼠标 y 坐标
}
else if (evt->type == Event::MouseDown)
{
// 鼠标按下事件发生了
// 将事件类型转换为事件的实际类型
auto mouseEvt = (MouseDownEvent*)evt;
mouseEvt->x; // 鼠标 x 坐标
mouseEvt->y; // 鼠标 y 坐标
mouseEvt->button; // 鼠标按键键值 MouseCode
}
else if (evt->type == Event::MouseUp)
{
// 鼠标抬起事件发生了
// 将事件类型转换为事件的实际类型
auto mouseEvt = (MouseUpEvent*)evt;
mouseEvt->x; // 鼠标 x 坐标
mouseEvt->y; // 鼠标 y 坐标
mouseEvt->button; // 鼠标按键键值 MouseCode
}
else if (evt->type == Event::MouseWheel)
{
// 鼠标滚轮滑动事件发生了
// 将事件类型转换为事件的实际类型
auto mouseEvt = (MouseWheelEvent*)evt;
mouseEvt->x; // 鼠标 x 坐标
mouseEvt->y; // 鼠标 y 坐标
mouseEvt->delta; // 鼠标滚轮滑动幅度
}
else if (evt->type == Event::KeyDown)
{
// 键盘按下事件发生了
// 将事件类型转换为事件的实际类型
auto keyEvt = (KeyDownEvent*)evt;
keyEvt->key; // 键盘按键键值 KeyCode
keyEvt->count; // 按键触发次数
}
else if (evt->type == Event::KeyUp)
{
// 键盘抬起事件发生了
// 将事件类型转换为事件的实际类型
auto keyEvt = (KeyUpEvent*)evt;
keyEvt->key; // 键盘按键键值 KeyCode
keyEvt->count; // 按键触发次数
}
};
使用监听器实现按钮
ButtonListener
按钮事件监听器提供了按钮基础功能,它可以添加到任何一个节点上,所以它可以让一段文字或者一个精灵变成按钮。
例如,下面的代码创建了一个点击后退出游戏的按钮
// 假设有一个精灵 sprite,把它变成退出游戏的按钮
// 创建点击按钮后的回调函数
auto callback = [](ButtonEvent evt)
{
if (evt == ButtonEvent::Clicked)
{
// 点击了按钮,退出游戏
Game::quit();
}
};
// 给 sprite 添加监听器
auto lis = gcnew ButtonListener(callback);
sprite->addListener(lis);
// 游戏暂停时,让这个按钮继续工作
lis->ignoreGamePaused();
查看更多关于回调函数的内容
ButtonEvent
是按钮相关事件,它的定义如下
// 按钮事件
enum class ButtonEvent
{
MouseEntered, // 鼠标浮于按钮上
MouseExited, // 鼠标从按钮上移出
Pressed, // 鼠标按下
Clicked, // 鼠标点击
};
实现开关按钮
开关按钮用来实现有 “开” 和 “关” 两种状态的按钮,例如背景音乐的开关等,ToggleButtonListener
开关按钮事件监听器提供了开关按钮功能,它可以添加到任何一个节点上。
例如,下面的代码创建了一个可以控制音乐的播放与停止的按钮
// 假设有一个精灵 sprite,把它变成控制音乐播放的按钮
// 创建点击按钮后的回调函数
auto callback = [](ButtonEvent evt, bool state)
{
if (evt == ButtonEvent::Clicked)
{
// 点击了按钮
if (state)
{
// 按钮现在是打开状态,播放音乐
MusicPlayer::resume("music.wav");
}
else
{
// 按钮现在是关闭状态,停止音乐
MusicPlayer::pause("music.wav");
}
}
};
// 给 sprite 添加监听器
auto lis = gcnew ToggleButtonListener(true /* 默认是打开状态 */, callback);
sprite->addListener(lis);
// 游戏暂停时,让这个按钮继续工作
lis->ignoreGamePaused();
查看更多关于回调函数的内容
监听器的启动和暂停
创建监听器后,可以调用 start
和 stop
函数启动和暂停一个监听器
auto lis = gcnew Listener();
// 启动监听器(默认就是启动状态)
lis->start();
// 暂停监听器
lis->stop();
监听器的添加和移除
创建监听器后,需要将其添加到节点上,才可以接收发送到该节点的事件:
auto lis = gcnew Listener();
// 添加监听器
node->addListener(lis);
// 移除监听器
node->removeListener(lis);
监听器可以有名字,通过名字可以启动、暂停、移除指定的监听器
auto lis = gcnew Listener();
node->addListener(lis);
// 设置监听器的名称
lis->setName("my_listener");
// 启动名称为 my_listener 的监听器
node->startListener("my_listener");
// 暂停名称为 my_listener 的监听器
node->stopListener("my_listener");
// 移除名称为 my_listener 的监听器
node->removeListener("my_listener");
也可以启动、暂停、移除一个节点上的所有监听器
// 启动所有监听器
node->startAllListeners();
// 暂停所有监听器
node->stopAllListeners();
// 移除所有监听器
node->removeAllListeners();
自定义事件
出了上面几种预先定义的事件,用户也可以自己定义事件。
下面的代码展示了如何创建自定义的事件:
// 自定义事件类型
enum MyEventType
{
// 第一个类型,为预定义事件类型最后一个值 + 1
First = Event::Type::Last + 1
};
// 自定义事件
struct MyEvent
: public Event
{
// 自定义事件的类型为 First
MyEvent() : Event(MyEventType::First) {}
// 自定义事件的成员变量
int value = 0;
};
使用下面的代码将自定义事件分发给节点及其所有子节点:
// 创建自定义事件
MyEvent* evt = gcnew MyEvent;
// 设置自定义事件的成员变量
evt->value = 3;
// 分发该事件,事件会发送给节点及其所有子节点
node->dispatch(evt);
在监听器中处理自定义事件:
// 回调函数处理
auto callback = [](Event* evt)
{
// 判断事件类型是否是鼠标按下
if (evt->type == Event::MouseDown)
{
// 自定义事件发生了
// 将事件类型转换为事件的实际类型
auto myEvt = (MyEvent*)evt;
myEvt->value; // 获取自定义事件的成员变量
}
};