【cocos2dx】监听安卓机的返回键

来源:互联网 发布:网络市场调研报告范文 编辑:程序博客网 时间:2024/06/05 23:59

2016-02-19新增-------------------------------------------------------------------------------------------------------------

--quick-cocos2d-x_2.2.6

--返回按键监听self.layer = display.newLayer()self.layer:addNodeEventListener(cc.KEYPAD_EVENT, function(event)  if event.key == "back" then  --self.mainPopup:show("要退出吗", true)--再按一次返回键退出end  end)self.layer:setKeypadEnabled(true)self:addChild(self.layer)

原文-----------------------------------------------------------------------------------------------------------------------------

(Cocos-2.2.6 & Framework-3.5)

在玩cocos2d-x的时候,每次真机实测,都要按home键来‘退出’游戏,因为没有监听返回键,这让我想起了某个版本的手机QQ,也是没有监听返回键来着。

来简单写一下cocos2d-x监听安卓的返回键。

 

简单的用helloworld项目来实验

首先在.h文件覆盖onKeyReleased函数。

virtual void onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event);

在.cpp中init函数里面注册键盘监听

bool HelloWorld::init(){//省略一些代码auto backKeyListener = EventListenerKeyboard::create();backKeyListener->onKeyReleased = CC_CALLBACK_2(HelloWorld::onKeyReleased, this);_eventDispatcher->addEventListenerWithSceneGraphPriority(backKeyListener, this);}

之后捕捉返回键(不排除手机机型问题和引擎版本问题引起keyCode的不同,keyCode请自行真机测试,我这里三星S4的返回键对应KEY_BACK)

void HelloWorld::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event){if (keyCode == EventKeyboard::KeyCode::KEY_BACK){Director::getInstance()->end();}}

好了,很简单。返回键按下立马退出。但是也太简单了,我们比较常见的app或者游戏的返回键监听一般设计成这两种形式:

1、“再按一次返回键退出”。2、弹出对话框确认退出。

 

先来第一种。

我们要实现“再按一次返回键退出”,那就得让程序知道,用户到底按了几次返回键。

另外,这两次按下返回键的间隔也应该有个限制,总不能,第一按下的时候,提示“再按一次返回键退出”,过了10分钟再按返回键就直接退出了。

相应的步骤大概是这样。


在上一段的代码基础上,.h文件里面声明一个bool变量来标记是否按了第一次。

bool m_keyBackFlag;

之后在init函数里面初始化为false

m_keyBackFlag = false;

然后HelloWorld::onKeyReleased要改挺多,因为我们要区别对待是否按了第一次返回键,所以先套一个if(!m_keyBackFlag)else,之后再分别编写。

void HelloWorld::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event){if (keyCode == EventKeyboard::KeyCode::KEY_BACK){if (!m_keyBackFlag)// 在过去的1秒钟之内没按过返回键,提示信息再按一次{TTFConfig ttfConfig("fonts/jt.ttf", 24);auto pMessage = Label::createWithTTF(ttfConfig,"再按一次返回键", TextHAlignment::LEFT, Director::getInstance()->getWinSize().width * 0.7);pMessage->setPosition(Point(100, 80));this->addChild(pMessage);auto pMessageFadeOut = FadeOut::create(1.0f);auto pMessageMoveBy = MoveBy::create(1.0f, Vec2(0, 75));auto pSpawn = Spawn::create(pMessageMoveBy, pMessageFadeOut, nullptr);pMessage->runAction(pSpawn);m_keyBackFlag = true;this->scheduleOnce([=](float dt){this->m_keyBackFlag = false;},1,//1秒之内如果不按返回键,那么m_keyBackFlag变量重置"keyBackFlag");}else//在过去的1秒钟之内曾按下返回键,现在按的是第二下{Director::getInstance()->end();}}}

效果图

细心的同学可能发现了,我们的左下角的信息里节点数在涨个不停。原因是,虽然这个提示信息(Label)消失了,但是我们没有移除它。

所以,每次显示的提示信息(Label)都会一直存在于我们的项目中。所以我们要移除它。也就是,在它消失的那一刻,他的生命是周期也结束了。

我们既然写有了一个lambda,那就好好利用它。

首先在pMessage->runAction(pSpawn);下加一句pMessage->retain();。为什么,后面再提。

之后在lambda里面的this->m_keyBackFlag = false;后面加一句this->removeChild(pMessage);。

刚刚前面要调用pMessage的retain函数,原因是,我们需要在一段时间后才移除这个pMessage指针,但是呢,那个时候程序已经离开了这个代码快。

pMessage指针失效了,pMessage指向的Label还在(透明的)。所以我们需要调用retain(),让它摆脱cocos的内存管理机制,来让lambda能捕捉到它。

再上图


这回节点数就正常了。(因为只加了两行代码,请自行添加吧,我不贴代码了)

==========================================================================================

再看第二种,弹出确认框。

这里我先说一下,对话框的类我没有实现,只是用成员指针来模拟实现的。

弹出对话框的实现,bool变量的flag我还是留着的,防止按多次返回键来弹出创建多次对话框(因为我没有写对话框的类,只是当场创建精灵和按钮来模拟对话框的)

当然用别的方法来预防也是可以的。

相应的步骤大概是这样。


这里要解决的一个小问题是,在弹出退出确认框的时候,游戏本身的所有监听事件就要屏蔽了,防止被玩家误触。也可以说,弹出来的对话框优先级最高。

我这里大概的思路就是,先做一个遮盖层,这个层吸收所有的触摸事件,然后在这个层之上,创建对话框。

如果用户选择退出,则退出游戏。如果取消,则返回游戏,移除这个遮盖层和对话框。

思路是这样,实现起来可以用层(Layer),我这里不用层(Layer)来实现这个遮盖用的层。

我们用一个足够大ui::ImageView对象,设置交互性setTouchEnabled(true);,这样,就能做到我们想要的效果了。

当然,也可以用其他的有setTouchEnable成员的类,只不过,ui::ImageView的创建已经非常简便了。就用这个好了。

之后,再创建对话框,并且设置好回调函数就好了。

因为要用成员变量来模拟对话框,所以成员变量比较多,如果自己已经实现了对话框类,那么只要少量成员变量就好了。

.h文件中声明的变量和函数。我们依然需要覆盖onKeyReleased函数。另外声明两个回调函数,分别作为确定退出和取消退出的回调。

先上效果图。

对话框是用精灵和按钮模拟的,所以成员变量有点多,如果自己实现了对话框类的话,变量会少很多。

virtual void onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event);void testCallback(Ref* pSender);void testCallback2(Ref* pSender);bool m_keyBackFlag;ui::ImageView* m_cover;Sprite* m_outBox;Label* m_pMessage2;Label* m_pLabelYes;Label* m_pLabelNo;MenuItemLabel* m_pItemYes;MenuItemLabel* m_pItemNo;Menu* m_pm;

那么初始化的时候可以全部赋空指针。

bool HelloWorld::init(){    //省略了一些代码m_cover = nullptr;m_pMessage2 = nullptr;m_pLabelYes = nullptr;m_pLabelNo = nullptr;m_pItemYes = nullptr;m_pItemNo = nullptr;m_pm = nullptr;m_outBox = nullptr;m_keyBackFlag = false;//同样还要注册监听auto backKeyListener = EventListenerKeyboard::create();backKeyListener->onKeyReleased = CC_CALLBACK_2(HelloWorld::onKeyReleased, this);_eventDispatcher->addEventListenerWithSceneGraphPriority(backKeyListener, this);}void HelloWorld::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event){if (keyCode == EventKeyboard::KeyCode::KEY_BACK){if (!m_keyBackFlag){//遮挡层用ui::ImageView来吸收触屏事件<span style="white-space:pre"></span>m_cover = ui::ImageView::create("colorBG.png");m_cover->setPosition(Vec2(Director::getInstance()->getWinSize().width * 0.5, Director::getInstance()->getWinSize().height * 0.5));m_cover->setTouchEnabled(true);m_cover->setOpacity(128);this->addChild(m_cover);//下面都是对话框的模拟实现m_outBox = Sprite::create("outBox.png");m_outBox->setPosition(270, 450);this->addChild(m_outBox);TTFConfig ttfConfig("fonts/jt.ttf", 24);m_pMessage2 = Label::createWithTTF(ttfConfig,"确定要退出么?",TextHAlignment::LEFT, Director::getInstance()->getWinSize().width * 0.7);m_pMessage2->setPosition(Vec2(270, 500));this->addChild(m_pMessage2);m_pLabelYes = Label::createWithTTF(ttfConfig,"是的",TextHAlignment::LEFT, Director::getInstance()->getWinSize().width * 0.7);m_pLabelNo = Label::createWithTTF(ttfConfig,"不要",TextHAlignment::LEFT, Director::getInstance()->getWinSize().width * 0.7);m_pItemYes = MenuItemLabel::create(m_pLabelYes, CC_CALLBACK_1(HelloWorld::testCallback, this));m_pItemNo = MenuItemLabel::create(m_pLabelNo, CC_CALLBACK_1(HelloWorld::testCallback2, this));m_pItemYes->setPosition(Vec2(270, 450));m_pItemNo->setPosition(Vec2(270, 400));m_pm = Menu::create(m_pItemYes, m_pItemNo, nullptr);m_pm->setPosition(Vec2(0, 0));this->addChild(m_pm);m_keyBackFlag = true;}}}void HelloWorld::testCallback(Ref* pSender)//确定退出的回调{Director::getInstance()->end();}void HelloWorld::testCallback2(Ref* pSender)//取消退出的回调{//移除对话框CCLOG("testCallback2");this->m_keyBackFlag = false;this->removeChild(m_pMessage2);this->removeChild(m_pLabelYes);this->removeChild(m_pLabelNo);this->removeChild(m_pm);this->removeChild(m_pItemYes);this->removeChild(m_pItemNo);this->removeChild(m_outBox);this->removeChild(m_cover);}


0 0