本章简单介绍一下有关schedule和一个工具类:NotificationCenter。
1.有关schedule
关于他,我们主要简单知道怎么用就可以了,具体不进行深入探讨。
(1)scheduleupdate()和update(float dt)
this->scheduleUpdate(); void HelloWorld::update();(2)不用update函数,调用自己重新设计的函数
this->schedule(schedule_selector(HelloWorld::myUpdate)); void HelloWorld::myUpdate(float dt);指定回调函数时,常用*selector形式,常用的有:
schedule_seclctor():常用语定时器回调函数,函数无参数。 callfunc_seclctor():常用于定义动作回调函数,函数无参数。 callfuncN_seclctor():常用于定义动作回调函数,函数带一个Node*参数。 callfuncND_seclctor():常用于定义菜单回调函数,但一个CCObject*参数。 menu_seclctor:常用于定义菜单回调函数。指定固定时间的定时调用声明方法:
this->scheduleOnce(schedule_selector(myupdate),2.0f);(3)停止定时器的调用,unSchedule
this->unscheduleUpdate(); this->unschedule(schedule_selector(HelloWorld::myupdare)); this->unshcduleAllSeclector();//all call back will stop(4)schedule并非定时很精确
不管是默认的update还是自定义的update,都是在同一个线程里面,所以某个函数占用时间过长,那么其他函数被调用的时间就有可能延后。所以schedule和scheduleOnce都存在这样的时间偏差。下面,我们用timerc类利用dt来进行时间累计,看看1秒的定时调用如何偏差;
#ifndef _TIME_H_ #define _TIME_H_ #include"cocos2d.h" USING_NS_CC; class Timerc:public Node { public: CREATE_FUNC(Timerc); virtual bool init(); virtual void update(float dt); void start(); float getcurrenttime(); private: float m_time; }; #endif
#include"Timer.h" bool Timerc::init() { return true; } void Timerc::update(float dt) { m_time += dt; log("Timer::update() %f",m_time); } float Timerc::getcurrenttime() { return m_time; } void Timerc::start() { m_time = 0; this->scheduleUpdate(); }以上这个类,纯粹用来计时。以检验下面一秒调用的偏差:
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" #include "Timer.h" class HelloWorld : public cocos2d::Layer { public: static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(HelloWorld); void logic(float dt); void dosomthing(float dt); private: Timerc* m_timer; }; #endif // __HELLOWORLD_SCENE_H__
#include "HelloWorldScene.h" USING_NS_CC; Scene* HelloWorld::createScene() { auto scene = Scene::create(); auto layer = HelloWorld::create(); scene->addChild(layer); return scene; } bool HelloWorld::init() { if ( !Layer::init() ) { return false; } m_timer = Timerc::create(); this->addChild(m_timer); m_timer->start(); this->schedule(schedule_selector(HelloWorld::logic),1.0f); this->schedule(schedule_selector(HelloWorld::dosomthing)); return true; } void HelloWorld::logic(float dt) { log("Hello World::logic %f",m_timer->getcurrenttime()); } void HelloWorld::dosomthing(float dt) { for(long i = 0; i < 99999999; i++);//耗时操作 }我们一秒调用一次logic,下面看看输出结果是怎样的:
2.有关NotificationCenter,观察者模式工具类
cocos2dx提供了一个不错的观察着模式工具类,NotificationCenter,我们来看看常用的函数和参数:
(1)addObserver(订阅消息)
Ref* target:要订阅消息的主体。
SEL_CallFuncO selector:消息回调函数。
const std::string& name:消息名称。
Ref* sender:要传递的数据。
(2)removeObserver(取消订阅消息)
Ref* target:取消订阅消息的主体。
const std::string& name:消息名称。
(3)postNotification(发布消息)
const std::string& name
or
const std::string& name,消息名称
Ref* sender.传递的数据
以上就是最基本的消息函数。
先实现一个类,用于订阅消息,他是一个层:
#ifndef _OTHERLAYER_H_ #define _OTHERLAYER_H_ #include "cocos2d.h" using namespace cocos2d; class OtherLayer:public Layer { public: CREATE_FUNC(OtherLayer); virtual bool init(); private: void testMsg(Ref* pData); }; #endif
#include"OtherLayer.h" bool OtherLayer::init() { if(!Layer::init())return false; //新建一个层,并订阅test消息 NotificationCenter::getInstance()->addObserver(this,callfuncO_selector(OtherLayer::testMsg),"test",NULL);//这个NULL,也可添加我们要的信息,比如(Ref*)"other layer data" return true; } //消息回调 void OtherLayer::testMsg(Ref* pData) { log("testMsg in OtherLayer"); }然后我们再实现一个发消息的类,如下:
#include "HelloWorldScene.h" #include "OtherLayer.h" USING_NS_CC; Scene* HelloWorld::createScene() { auto scene = Scene::create(); auto layer = HelloWorld::create(); scene->addChild(layer); //将层添加到场景里面 auto otherLayer = OtherLayer::create(); scene->addChild(otherLayer); return scene; } bool HelloWorld::init() { if ( !Layer::init() ) { return false; } //3秒后发消息 this->schedule(schedule_selector(HelloWorld::sendmsg),3.0f); return true; } void HelloWorld::sendmsg(float dt) { //发布test消息 NotificationCenter::getInstance()->postNotification("test",NULL); }上面就是简单的收发消息方法来了。 没什么好讲的,会用,了解就行额
3.实现一个简单的观察者
#ifndef _NOTIFYUTIL_H_ #define _NOTIFYUTIL_H_ #include"cocos2d.h" using namespace cocos2d; class NotifyUtil:public Ref { public: static NotifyUtil* getInstance(); CREATE_FUNC(NotifyUtil); virtual bool init(); //订阅消息 void addObserver(const std::string & sMsgName,std::function<void (Ref*)>func); //发送消息 void postNotification(const std::string &sMsgName,Ref* data); private: static NotifyUtil* m_NotifyUtil; //一个消息对已一系列注册者回调 std::map<std::string,std::vector<std::function<void(Ref*)>>> m_funcMap; }; #endif #include"NotifyUtil.h" NotifyUtil* NotifyUtil::m_NotifyUtil = NULL; NotifyUtil* NotifyUtil::getInstance() { if(m_NotifyUtil == NULL) { m_NotifyUtil = NotifyUtil::create(); m_NotifyUtil->retain(); } return m_NotifyUtil; } bool NotifyUtil::init() { return true; } void NotifyUtil::addObserver(const std::string & sMsgName,std::function<void(Ref*)> func) { if(m_funcMap.find(sMsgName) != m_funcMap.end()) { //已经存在该消息回调函数列表,有人订阅了同样的消息 std::vector<std::function<void(Ref*)>> &funcList = m_funcMap.at(sMsgName); funcList.push_back(func);//将新的订阅者添加到回调列表里面 } else { std::vector<std::function<void(Ref*)>> funcList;//新建一个列表 funcList.push_back(func); m_funcMap[sMsgName] = funcList;//将新建的列表放到map中 } } void NotifyUtil::postNotification(const std::string& sMsgName,Ref* data) { if(m_funcMap.find(sMsgName) != m_funcMap.end()) { std::vector<std::function<void(Ref*)>> funcList = m_funcMap.at(sMsgName); for(auto func:funcList) { func(data); } } }测试用例
bool HelloWorld::init() { if ( !Layer::init() ) { return false; } //三个订阅者 NotifyUtil::getInstance()->addObserver("hongzong",[](Ref* data) { log("hongzong receive msg %s",data); }); NotifyUtil::getInstance()->addObserver("hongzong",[](Ref* data) { log("this is di zong"); }); NotifyUtil::getInstance()->addObserver("hongzong",[](Ref* data) { log("this is bing zai"); }); NotifyUtil::getInstance()->postNotification("hongzong",(Ref*)"here"); return true; }