@TangWill
2019-06-15T10:38:15.000000Z
字数 19673
阅读 945
DataStruct在游戏中,我们常常需要实现弹出一个模态对话框,比如说游戏暂停,退出提示对话框等
对话框特点如下:
1.可定制的,比如说背景图,标题,文本,按钮等,根据需要添加和设置
2.需要屏蔽对话框下层的触摸
3.为了友好的效果显示,把不可触摸的部分变为灰色
Dialog.h
#ifndef __DIALOG_H__#define __DIALOG_H__#include "cocos2d.h"#include "ui/CocosGUI.h"#include "Theme.h"#include "Network.h"#include "User.h"#define SCREEN_WIDTH 1200#define SCREEN_HEIGHT 900USING_NS_CC;using namespace cocos2d::ui;using std::string;class Dialog final :public LayerColor{public:Dialog() : menu(nullptr), labelMenu(nullptr), backGround(nullptr), title(nullptr), contentText(nullptr) {}~Dialog();bool init() override;CREATE_FUNC(Dialog);static Dialog* create(const string& background, const Size& size);// touch事件监听bool onTouchBegan(Touch* touch, Event* event) override { return true; }void onTouchMoved(Touch* touch, Event* event) override {}void onTouchEnded(Touch* touch, Event* event) override {}void onEnter() override;void onExit() override;// 添加标题void setTitle(const string& title, int fontSize = 20);// 添加文本内容void setContentText(const string& text, const int fontSize, const int padding, const int paddingTop);// 添加button、label或listViewbool addButton(MenuItem* menuItem) const;bool addLabel(MenuItem* menuItem) const;void addListView(bool dialogType, bool inMenu, bool classical, bool noLeadingIn = true);private:Theme* theme = Theme::getInstance();// 文字内容两边和顶部的空白区int contentPadding = 0;int contentPaddingTop = 0;Size dialogContentSize;// 初始化scene中心位置,方便使用const Point center = Point(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);int position = 11; // 滚动条位置bool rank = false; // 对话框类型bool rankType = false; // 排行榜类型bool isInMenu = true; // 排行榜是否在menuScenebool isClassical = true; // 游戏模式bool changed = false; // 判断排行榜是否改变ListView* listView = nullptr;Label* nameLabel = nullptr;Label* rankLabel = nullptr;Label* scoreLabel = nullptr;Label* content = nullptr;Layout* layout = nullptr;EventListenerMouse* listenerMouse = nullptr;// 排行榜vector<pair<string, int>> classicalRank;vector<pair<string, int>> plusRank;void backgroundFinish(); // 初始化对话框内容及布局void initRankDialog(); // 初始化排行榜对话框void initNormalDialog(); // 初始化普通对话框void getRankByType(bool type); // 获取排行榜内容// set and getCC_SYNTHESIZE_RETAIN(Menu*, menu, MenuButton);CC_SYNTHESIZE_RETAIN(Menu*, labelMenu, MenuLabel);CC_SYNTHESIZE_RETAIN(ui::Scale9Sprite*, backGround, BackGround);CC_SYNTHESIZE_RETAIN(Label*, title, LabelTitle);CC_SYNTHESIZE_RETAIN(Label*, contentText, LabelContentText);};#endif
Dialog.cpp
#include "Dialog.h"Dialog::~Dialog(){CC_SAFE_RELEASE(menu);CC_SAFE_RELEASE(labelMenu);CC_SAFE_RELEASE(contentText);CC_SAFE_RELEASE(title);}bool Dialog::init(){if (!LayerColor::init()) return false;// 初始化需要的 Menu button菜单auto menu = Menu::create();menu->setPosition(Size::ZERO);setMenuButton(menu);// label菜单auto labelMenu = Menu::create();labelMenu->setPosition(Size::ZERO);setMenuLabel(labelMenu);// 添加layer的事件监听事件auto listener = EventListenerTouchOneByOne::create();listener->onTouchBegan = CC_CALLBACK_2(Dialog::onTouchBegan, this);listener->onTouchMoved = CC_CALLBACK_2(Dialog::onTouchMoved, this);listener->onTouchEnded = CC_CALLBACK_2(Dialog::onTouchEnded, this);auto dispatcher = Director::getInstance()->getEventDispatcher();dispatcher->addEventListenerWithSceneGraphPriority(listener, this);// 设置背景版透明,达到对话框下层变灰暗效果setColor(Color3B(0, 0, 0));setOpacity(128);return true;}Dialog* Dialog::create(const string& background, const Size& size){auto layer = Dialog::create();layer->setBackGround(Scale9Sprite::create(background));layer->dialogContentSize = size;return layer;}#pragma region Overridevoid Dialog::onEnter(){LayerColor::onEnter();Layer::onEnter();_eventDispatcher->pauseEventListenersForTarget(this->getParent(), true); // 阻止事件向下传递//添加背景图片auto background = getBackGround();background->setContentSize(dialogContentSize);background->setPosition(Point(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2));this->addChild(background, 0, 0);// 弹出效果Action* dialog = Sequence::create(ScaleTo::create(0.0f, 0.0f),ScaleTo::create(0.3f, 1.0f),CallFunc::create(CC_CALLBACK_0(Dialog::backgroundFinish, this)),nullptr);background->runAction(dialog);}void Dialog::onExit(){Layer::onExit();LayerColor::onExit();_eventDispatcher->resumeEventListenersForTarget(this->getParent(), true); // 还原事件监听}#pragma endregion#pragma region Add Componentvoid Dialog::setTitle(const string& title, const int fontSize/*=20*/){const auto label = Label::createWithTTF(title, theme->semiBoldFont, fontSize);setLabelTitle(label);}void Dialog::setContentText(const string& text, const int fontSize, const int padding, const int paddingTop){const auto label = Label::createWithTTF(text, theme->semiBoldFont, fontSize);setLabelContentText(label);contentPadding = padding;contentPaddingTop = paddingTop;}bool Dialog::addButton(MenuItem* menuItem) const{// 添加精灵菜单项const auto center = Point(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);menuItem->setPosition(center);getMenuButton()->addChild(menuItem);return true;}bool Dialog::addLabel(MenuItem* menuItem) const{// 添加标签菜单项const auto center = Point(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2);menuItem->setPosition(center);getMenuLabel()->addChild(menuItem);return true;}void Dialog::addListView(bool dialogType, bool inMenu, bool classical, bool noLeadingIn){// 预加载排行榜,解决卡顿if (noLeadingIn && User::getInstance()->isConnected()){classicalRank = Network::getInstance()->getRank(true);plusRank = Network::getInstance()->getRank(false);}// 设置窗口类型为排行榜窗口,并判断排行榜显示游戏模式rank = dialogType;isInMenu = inMenu;isClassical = classical;}#pragma endregionvoid Dialog::backgroundFinish(){// 判断窗口类型为排行榜窗口或普通窗口,true为排行榜窗口if (rank){initRankDialog();}else{initNormalDialog();}rank = false; // 默认为普通对话框}void Dialog::initNormalDialog(){// 显示对话框标题if (getLabelTitle()){getLabelTitle()->setPosition(center + Vec2(0, dialogContentSize.height / 2 - title->getContentSize().height / 2 - 15));this->addChild(getLabelTitle());}// 显示文本内容if (getLabelContentText()){auto content = getLabelContentText();content->setLineBreakWithoutSpace(true);content->setMaxLineWidth(dialogContentSize.width - 2 * contentPadding);content->setPosition(Vec2(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2));content->setHorizontalAlignment(TextHAlignment::LEFT);this->addChild(content);}// 添加label或button,并设置其位置//labelthis->addChild(getMenuLabel());auto adaptHeight = 0;if (title) adaptHeight = title->getContentSize().height;const auto labelHeight = (dialogContentSize.height - adaptHeight -40) / (getMenuLabel()->getChildrenCount() + 2);// 布局labelMenuItemauto labels = getMenuLabel()->getChildren();auto i = 0;for (auto menuItem : labels){auto node = dynamic_cast<Node*>(menuItem);node->setPosition(Point(SCREEN_WIDTH / 2,(SCREEN_HEIGHT + dialogContentSize.height / -adaptHeight + 50) /2 - dialogContentSize.height / 2.5 + labelHeight * (getMenuLabel()->getChildrenCount() - i)));i++;}// buttonthis->addChild(getMenuButton());const auto buttonWidth = dialogContentSize.width / (getMenuButton()->getChildrenCount() + 1);auto nodes = getMenuButton()->getChildren();i = 0;for (auto menuItem : nodes){auto node = dynamic_cast<Node*>(menuItem);node->setPosition(Point(SCREEN_WIDTH / 2 - dialogContentSize.width / 2 + buttonWidth * (i + 1),SCREEN_HEIGHT / 2 - dialogContentSize.height / 2.5));i++;}}void Dialog::initRankDialog(){// 显示对话框标题if (getLabelTitle()){getLabelTitle()->setPosition(center + Vec2(0, dialogContentSize.height / 2 - 75.0f));this->addChild(getLabelTitle());}this->addChild(getMenuButton());// 添加button,设置布局const auto buttonWidth = dialogContentSize.width / (getMenuButton()->getChildrenCount() + 1);auto nodes = getMenuButton()->getChildren();auto i = 0;for (auto menuItem : nodes){auto node = dynamic_cast<Node*>(menuItem);node->setPosition(Point(SCREEN_WIDTH / 2 - dialogContentSize.width / 2 + buttonWidth * (i + 1),SCREEN_HEIGHT / 2 - dialogContentSize.height / 2.5));i++;}listView = ListView::create();listView->setDirection(ScrollView::Direction::VERTICAL);listView->setTouchEnabled(true);listView->setBounceEnabled(true);listView->setBackGroundImageScale9Enabled(true);listView->setAnchorPoint(Point(0.5f, 0.5f));listView->setContentSize(Size(500, 400));listView->setPosition(Point(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2));listView->setScrollBarAutoHideTime(0);listView->setScrollBarColor(Color3B::WHITE);this->addChild(listView);//添加鼠标事件侦听listenerMouse = EventListenerMouse::create();listenerMouse->setEnabled(true);listenerMouse->onMouseScroll = [&](EventMouse* event){const auto y = event->getScrollY(); //滚轮上滑y值大于0,下滑y值小于0if (y > 0){if (position % 11 < 10)position++;listView->scrollToPercentVertical(10 * (position % 11), 0.5, true);}else{if (position % 11 > 0)position--;listView->scrollToPercentVertical(10 * (position % 11), 0.5, true);}};_eventDispatcher->addEventListenerWithSceneGraphPriority(listenerMouse, this);// 不同游戏模式的排行榜切换按钮auto changeTypeButton = Button::create(theme->menuChangeTypeButtonNormalBackground,theme->menuChangeTypeButtonSelectedBackground,theme->menuChangeTypeButtonDisabledBackground); // 切换到进阶auto backTypeButton = Button::create(theme->menuBackTypeButtonNormalBackground,theme->menuBackTypeButtonSelectedBackground,theme->menuBackTypeButtonDisabledBackground); // 切换到经典changeTypeButton->setPosition(Point(SCREEN_WIDTH / 2 + listView->getContentSize().width / 2 + 50,SCREEN_HEIGHT / 2));backTypeButton->setPosition(Point(SCREEN_WIDTH / 2 - listView->getContentSize().width / 2 - 50,SCREEN_HEIGHT / 2));backTypeButton->setOpacity(0); // 切换经典初始不可见backTypeButton->addTouchEventListener([&, changeTypeButton, backTypeButton](Ref* sender, ui::Widget::TouchEventType type){if (type == Widget::TouchEventType::ENDED){title->setString("经典挑战排行");backTypeButton->setOpacity(0);changeTypeButton->runAction(FadeIn::create(0.25));if (changed)getRankByType(true);changed = false;}});changeTypeButton->addTouchEventListener([&, changeTypeButton, backTypeButton](Ref* sender, ui::Widget::TouchEventType type){if (type == Widget::TouchEventType::ENDED){title->setString("进阶挑战排行");changeTypeButton->setOpacity(0);backTypeButton->runAction(FadeIn::create(0.25));if (!changed)getRankByType(false);changed = true;}});// 如果在menuScene中,排行榜可切换,gameScene中排行榜不可切换if (isInMenu){this->addChild(changeTypeButton);this->addChild(backTypeButton);}// 根据游戏模式初始化排行榜this->getRankByType(isClassical);}void Dialog::getRankByType(bool type){rankType = type;if (content){this->removeChild(content);listView->setScrollBarEnabled(true);listView->setScrollBarAutoHideTime(0);}if (!(rankType ? classicalRank.empty() : plusRank.empty())){if (listView->getChildrenCount() > 0)listView->removeAllChildren();for (auto i = 0; i < 10; i++){auto icon = ImageView::create(theme->iconSet + std::to_string(i) + ".png");layout = Layout::create();layout->setLayoutType(Layout::Type::ABSOLUTE);layout->setContentSize(Size(500, icon->getContentSize().height + 30));icon->setPosition(Vec2(icon->getContentSize().width / 2 + 60, 30));layout->addChild(icon);layout->setBackGroundColorType(Layout::BackGroundColorType::NONE);rankLabel = Label::createWithTTF(std::to_string(i + 1), theme->semiBoldFont, 30);rankLabel->setPosition(Vec2(icon->getContentSize().width / 2 + 10, 30));layout->addChild(rankLabel);if (i > (rankType ? classicalRank.size() : plusRank.size()) - 1){nameLabel = Label::createWithTTF("------------------", theme->markerFeltFont, 30);nameLabel->setPosition(Vec2(icon->getContentSize().width + nameLabel->getContentSize().width / 2 + 75,30));layout->addChild(nameLabel);scoreLabel = Label::createWithTTF("---------", theme->markerFeltFont, 30);scoreLabel->setPosition(Vec2(465 - scoreLabel->getContentSize().width / 2, 30));layout->addChild(scoreLabel);}else{nameLabel = Label::createWithTTF(rankType ? classicalRank.at(i).first : plusRank.at(i).first,theme->semiBoldFont, 30);nameLabel->setPosition(Vec2(icon->getContentSize().width + nameLabel->getContentSize().width / 2 + 75,30));layout->addChild(nameLabel);scoreLabel = Label::createWithTTF(std::to_string(rankType ? classicalRank.at(i).second : plusRank.at(i).second),theme->semiBoldFont, 30);scoreLabel->setPosition(Vec2(465 - scoreLabel->getContentSize().width / 2, 30));layout->addChild(scoreLabel);}listView->pushBackCustomItem(layout);listView->setBottomPadding(icon->getContentSize().height);}}else{if (listView->getChildrenCount() > 0)listView->removeAllChildren();listView->setScrollBarEnabled(false);setContentText("抱歉! 网络连接失败!", 36, 60, 20);content = getLabelContentText();content->setLineBreakWithoutSpace(true);content->setMaxLineWidth(dialogContentSize.width - 2 * contentPadding);content->setPosition(Vec2(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2));content->setHorizontalAlignment(TextHAlignment::LEFT);this->addChild(content);}}
最近在做个小的示例项目,确定后打算用cocos2dx框架来做UI部分,毕竟它易于使用还跨平台,像我这样几乎完全没有cocos2dx基础的童鞋,也能快速上手。在开发过程中,我想像在桌面应用中那样,弹出一个窗口并给出一些文本提示。无奈好像cocos2dx并没有给出现成可用的东西,只能自己琢磨实现了。考虑过后,打算通过Layer类来构建一个子类,然后在Scene中去显示该Layer,从而模拟出“窗口”的效果。我查阅了一些资料发现,网上有很多类似的实现代码,但他们大多已经过时,因这两年cocos2dx的版本变化好像挺大。
按照上述的思路构建子类测试后发现,监听的事件不会被“阻隔”,例如:我们在Scene中监听了鼠标和键盘,然后在Scene中去添加了该Layer,并在该Layer中也监听了鼠标点击事件,当我们在该Layer中点击鼠标时,Scene中也会触发该事件。这就导致了一些奇怪的现象,和预期不符合。本文将试着简介如何用一种足够简单的方法,构建这样一个“模态对话框类”并解决包含事件不“阻隔”在内的几乎所有问题。
在开始前,先简要说明一下环境。本次实验编写于Linux平台。因实验于PC平台,我在示例所监听的都是鼠标和键盘事件,对于移动平台的触摸事件未做任何测试,但理论上也是可行的,具体请读者自测和变更,以适应特定的场景。
#ifndef MYGAME_POPUPLAYER_H#define MYGAME_POPUPLAYER_H#include "cocos2d.h"USING_NS_CC;class PopupLayer:public cocos2d::Layer{public:PopupLayer();virtual ~PopupLayer();private:std::string backgroundImage;EventListenerMouse *listenerMouse;public:virtual bool init() override;CREATE_FUNC(PopupLayer);static PopupLayer* create(const std::string backgroundImage);bool setBackgroundImage(const std::string &backgroundImage);void okMenuItemCallback(Ref *pSender);void cancelMenuItemCallback(Ref *pSender);/*** Event callback that is invoked every time when Node enters the 'stage'.* If the Node enters the 'stage' with a transition, this event is called when the transition starts.* During onEnter you can't access a "sister/brother" node.* If you override onEnter, you shall call its parent's one, e.g., Node::onEnter().* @lua NA*/virtual void onEnter() override;/*** Event callback that is invoked every time the Node leaves the 'stage'.* If the Node leaves the 'stage' with a transition, this event is called when the transition finishes.* During onExit you can't access a sibling node.* If you override onExit, you shall call its parent's one, e.g., Node::onExit().* @lua NA*/virtual void onExit() override;};#endif //MYGAME_POPUPLAYER_H
首先 PopupLayer继承自Layer类,你也可以继承自其他Layer类,如LayerColor,这样你可以获得不同的特性。这里仅仅定义了两个数据成员,一个std::string用于存储整个“窗口”的背景图文件名,一个EventListenerMouse指针存储鼠标监听器,稍后可以看到是如何使用它们的。最后,来看看添加了哪些成员方法。首先,我重写了基类的init()方法,如果你对cocos2dx不陌生,那么你应该知道在该方法中要做哪些事情。其次,我使用 CREATE_FUNC 宏来构建了一个默认的静态create()方法,这基本上也是cocos2dx的传统。为了进一步满足需求,我还提供了静态create()方法的一个重载,它将包含一个参数用于指定背景资源名。setBackgroundImage()方法可以用来设置和更改背景资源。okMenuItemCallback()和cancelMenuItemCallback()是“模态对话框”上两个按钮的回调方法。最后我还重写了基类的onEnter()和onExit()方法,这两个方法至关重要,稍后你将看到它们是如何相互配合完成整个功能的。
cocos2dx使用一个类对象前,总是先调用它的静态create()方法来创建该类的一个实例,所以我们先从它开始介绍。
PopupLayer* PopupLayer::create(const std::string backgroundImage){PopupLayer *pl = new(std::nothrow) PopupLayer();if (pl && pl->setBackgroundImage(backgroundImage) && pl->init()){pl->autorelease();return pl;}else{delete pl;pl = nullptr;return nullptr;}}
可以看到,我们只增加了setBackgroundImage()方法的调用。接着就是init()方法了。
bool PopupLayer::init(){// 1. super init firstif ( !Layer::init() ){return false;}auto visibleSize = Director::getInstance()->getVisibleSize();Vec2 origin = Director::getInstance()->getVisibleOrigin();this->setAnchorPoint(Vec2::ZERO);// add "HelloWorld" splash screen"auto sprite = Sprite::create(backgroundImage);// position the sprite on the center of the screensprite->setPosition(Vec2(visibleSize.width/2, visibleSize.height/2));// add the sprite as a child to this layerthis->addChild(sprite, 1);auto label = Label::createWithTTF("Are u sure exit?", "fonts/Marker Felt.ttf", 24);label->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2 + 50));label->setColor(Color3B(255,0,0));this->addChild(label, 1);auto okMenuItem = MenuItemFont::create("OK", CC_CALLBACK_1(PopupLayer::okMenuItemCallback, this));okMenuItem->setPosition(Vec2(visibleSize.width / 2 - 100, visibleSize.height / 2 - 50));okMenuItem->setColor(Color3B(255,0,0));auto cancelMenuItem = MenuItemFont::create("Cancel", CC_CALLBACK_1(PopupLayer::cancelMenuItemCallback, this));cancelMenuItem->setPosition(Vec2(visibleSize.width / 2 + 100, visibleSize.height / 2 - 50));cancelMenuItem->setColor(Color3B(255,0,0));auto pMenu = Menu::create(okMenuItem, cancelMenuItem, NULL);pMenu->setPosition(Vec2::ZERO);this->addChild(pMenu, 1);return true;}
init()方法也足够简单,创建了一个sprite来作为背景,一个label来显示一些文本信息和两个菜单按钮,并设置了这两个菜单按钮的回调方法。
最后是onEnter()方法和onExit()方法,这是两个重点。onEnter()方法是在该“模态对话框”Layer显示时会被调用。相反,onExit()方法会在它消失时被调用。这两个机制可以用来做一些事情。
void PopupLayer::onEnter(){Layer::onEnter();if (listenerMouse == nullptr){listenerMouse = EventListenerMouse::create();listenerMouse->onMouseDown = [](EventMouse* event) {};}if (listenerMouse){_eventDispatcher->pauseEventListenersForTarget(this->getParent(), true);_eventDispatcher->addEventListenerWithSceneGraphPriority(listenerMouse, this);}}void PopupLayer::onExit(){Layer::onExit();if (listenerMouse){_eventDispatcher->removeEventListener(listenerMouse);_eventDispatcher->resumeEventListenersForTarget(this->getParent(), true);}}
在onEnter()方法中,我们先创建一个鼠标监听对象,并设置了它的回调函数,只不过回调函数为空,什么也不做。然后通过eventDispatcher对象的pauseEventListenersForTarget()方法来暂停“模态对话框”父级窗口的事件监听器,并把自己的监听器添加到事件分发器中。所谓的父级窗口指的是“模态对话框”的下层Layer。这里是“模态对话框”下层Layer屏蔽事件监听的关键所在,如果不屏蔽它,则在“模态对话框”上发生的监听事件也会传递给它的下层Layer。也有的文章说可以设置监听器的优先级来解决该问题,但我没能找到解决方法。
在onExit()方法中,我们来做一些清理还原工作,因为onExit()方法被调用,意味着“模态对话框”Layer即将消失,所以我们从事件分发器中删除它的鼠标监听器,并重新启用它下层Layer的事件监听器。这样便可以还原。
最后,来看看如何使用它。我通过cocos2dx创建了一个新工程,并对HelloWorld场景做了一些小的改动,以方便测试。下面是它的init()方法。
bool HelloWorld::init(){//////////////////////////////// 1. super init firstif ( !Layer::init() ){return false;}auto visibleSize = Director::getInstance()->getVisibleSize();Vec2 origin = Director::getInstance()->getVisibleOrigin();/////////////////////////////// 2. add a menu item with "X" image, which is clicked to quit the program// you may modify it.// add a "close" icon to exit the progress. it's an autorelease objectauto closeItem = MenuItemImage::create("CloseNormal.png","CloseSelected.png",CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,origin.y + closeItem->getContentSize().height/2));// create menu, it's an autorelease objectauto menu = Menu::create(closeItem, NULL);menu->setPosition(Vec2::ZERO);this->addChild(menu, 1);/////////////////////////////// 3. add your codes below...// add a label shows "Hello World"// create and initialize a labelauto label = Label::createWithTTF("Hello World", "fonts/Marker Felt.ttf", 24);// position the label on the center of the screenlabel->setPosition(Vec2(origin.x + visibleSize.width/2,origin.y + visibleSize.height - label->getContentSize().height));// add the label as a child to this layerthis->addChild(label, 1);auto label1 = Label::createWithTTF("Press the Enter key or click the left mouse button.", "fonts/Marker Felt.ttf", 12);// position the label on the center of the screenlabel1->setPosition(Vec2(origin.x + visibleSize.width/2, 100));// add the label as a child to this layerthis->addChild(label1, 1);// add "HelloWorld" splash screen"auto sprite = Sprite::create("HelloWorld.png");// position the sprite on the center of the screensprite->setPosition(Vec2(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));// add the sprite as a child to this layerthis->addChild(sprite, 0);//添加鼠标事件侦听auto listenerMouse = EventListenerMouse::create();listenerMouse->setEnabled(true);listenerMouse->onMouseDown = [&](EventMouse* event) {int mouseBtn = event->getMouseButton();if (0 == mouseBtn) {auto sprite = Sprite::create("HelloWorld.png");sprite->setPosition(event->getLocationInView().x, event->getLocationInView().y);sprite->setScale(0.5f,0.5f);this->addChild(sprite, 1);}};_eventDispatcher->addEventListenerWithSceneGraphPriority(listenerMouse, this);//添加键盘事件监听auto listenerKeyboard = EventListenerKeyboard::create();listenerKeyboard->setEnabled(true);listenerKeyboard->onKeyPressed = [&](EventKeyboard::KeyCode keycode, Event* event){if(EventKeyboard::KeyCode::KEY_ENTER == keycode){auto pl = PopupLayer::create("background.png");pl->setScale(0.5f,0.5f);pl->setParent(this);pl->setPosition(Vec2(visibleSize.width/2, visibleSize.height/2));pl->setAnchorPoint(Vec2(0.5f,0.5f));this->addChild(pl, 2);}};_eventDispatcher->addEventListenerWithSceneGraphPriority(listenerKeyboard, this);return true;}
我在里面增加了一个label,用于显示一些提示信息。增加了鼠标左键的事件监听,并在点击的位置绘制一张图片。这样做可以很好的演示当“模态对话框”Layer打开后,是否有效的屏蔽了下层Layer的事件监听。最后,添加了键盘监听,当我们敲击Enter键后,“模态对话框”Layer就会显示出来。值得特别注意的是,我调用了这样一个方法 pl->setParent(this); 用于设置了“模态对话框”Layer的父级Node,这是基类给提供的一个方法,千万别忘了设置它,其他的都足够简单了。
好了,你可以试着获取完整的代码,并编译运行一下,希望能解决你的问题或者给你一些新的思路。最后,我不太了解cocos2dx框架,如果本文或者示例中有什么错误或者不规范的地方,请指正,谢谢。