Cocos2dx学习第九章(schedule简介)

 本章简单介绍一下有关schedule和一个工具类:NotificationCenter。

1.有关schedule

关于他,我们主要简单知道怎么用就可以了,具体不进行深入探讨。
(1)scheduleupdate()和update(float dt)
这两者结合使用,把当前节点加入到队列中,这个节点就会在游戏运行的每一帧中调用一次update函数。参数float dt表示上次调用update到当前这次调用update所间隔的时间。
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:常用于定义菜单回调函数。
指定固定时间的定时调用声明方法:
thsi->schedule(schedule_selector(HelloWorld::myupdate), 2.0f);//两秒调用一次
只调用一次的方式如下:
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,下面看看输出结果是怎样的:

可见,第27次调用的时候,已经是27.4秒了,延迟了。如果我们想要更准确的在指定时间调用某函数,可以在update里面做判断,大于等于某值时去调用,这样相对来说,会比较精确。

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;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值