cocos2dx学习之路----第十二篇(关于Node节点的自我更新函数Update探讨及定时器的使用)

来源:互联网 发布:tbq淘宝权微博 编辑:程序博客网 时间:2024/05/02 00:35

这一篇来谈谈关于Node节点比较重要的函数接口,自我更新接口(update)以及定时器。

好,下面先来谈谈节点的自我更新。

每一个Node节点都有自带一个update函数。而当调用ScheduleUpdate()这一方法便会被开启,在每一帧被调用。

我们可能注意到,在AppDelegate中有个setAnimationInterval()的方法,有导演类调用。而这个方法就是设置渲染的帧率的。默认是以60帧每秒进行渲染。当然,并不是真正的每秒就渲染60次,这个只能是差不多达到这个速率,因为程序在运行过程中会耗时,特别是执行一些比较耗时的方法。

那么,既然是这样,如果开启来我们更新函数update,那么程序就会以这个时间(1/60秒 = 0.01666秒)去调用每次的update函数,而这个时间便作为update的参数传入。

通过开启节点的update方法可以实现节点自己的逻辑代码的更新。

好,接着我们再说说定时器,如果要在cocos中使用定时器,需要用到Scheduler这一个类来使用,称为调度器。而这一个类的也被整理到Node中,然后提供我们使用它的方法。通过它的一系类方法可以实现我们所谓的定时器。我列出它其中一个开启定时器的方法,理解了这个,也就可以理解其它方法了。如下:

/******************************参数1:调度器调用的回调方法**参数2:调度器每隔'interval‘秒调用一次**参数3:调用(repeat+1)次**参数4:第一次开始调用时隔’delay‘秒******************************void Node::schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay);
对于第二个参数,如果把时间设置为0,那么,将会像update一样每一帧被调用,不过如果这样,建议使用ScheduleUpdate方法调用自身的update函数。对于第三个参数,如果要一直调用,可以通过宏定义CC_REPEAT_FOREVER来设置。

好,那么我们现在就来看看这次的测试中如何来应用,先来看看运行结果:


上面一个节点是通过调用ScheduleUpdate方法来进行自我的位置更新,下面一个则是使用定时器的方法来进行更新。我们还可以看到有Start、Remove以及PauseCurrentTarget、ResumeCurrentTarget的菜单条目。它们是用来对调度器的操作的。需要提及的一点是,在调度器被开启的时候,我们可以通过获取当前被调度的函数来识别该调度器是否被开启,即通过调用IsSchedule这一方法。而对于函数自身节点的update是检测不到的自身的update只能是开启或者移除。这点需要注意一下。对于最下面的Pause和Resume可以对节点的所有调度器进行停止恢复。这也是很有用的一个方法。

好了,话不多说。来看看源码吧:

SchedulerTest.h:

#ifndef __SCHEDULER_TEST__#define __SCHEDULER_TEST__#include"cocos2d.h"USING_NS_CC;class SchedulerTest :public Scene{public:static Scene *createScene();virtual bool init();CREATE_FUNC(SchedulerTest);void update(float dt);void Own_Update(float dt);//准备状态的函数void ReadyFunc(float dt);private:Size visibleSize;};#endif
SchedulerTest.cpp:

#include"SchedulerTest.h"Scene *SchedulerTest::createScene(){auto scene = SchedulerTest::create();return scene;}bool SchedulerTest::init(){if (!Scene::init()){return false;}visibleSize = Director::getInstance()->getVisibleSize();//当前测试标签描述auto test_label = Label::createWithSystemFont("About Node's Update Test", "", 30);test_label->setPosition(Vec2(visibleSize.width / 2, visibleSize.height - test_label->getContentSize().height));this->addChild(test_label);/*******************************************************************节点一****************************************************************/LayerColor *block1 = LayerColor::create(Color4B::RED, 70, 70);this->addChild(block1);block1->ignoreAnchorPointForPosition(false);block1->setAnchorPoint(Vec2::ANCHOR_MIDDLE);block1->setPosition(visibleSize.width / 4, visibleSize.height * 3 / 4 - 50);//设置名字以便获取block1->setName("block1");//附加在节点一上的名字标签auto label1 = Label::createWithSystemFont("block1", "", 22);block1->addChild(label1);label1->setPosition(block1->getContentSize() / 2);//节点一状态标签,对于状态,需要动态改变它,所以需要给它设置个名字auto state_label1 = Label::createWithSystemFont("Block1 State:", "", 25);state_label1->setPosition(Vec2(state_label1->getContentSize().width / 2,block1->getPositionY() + block1->getContentSize().height));this->addChild(state_label1);auto state1 = Label::createWithSystemFont("Stop", "", 25);state1->setPosition(Vec2(visibleSize.width/2 ,state_label1->getPositionY()));this->addChild(state1);//设置名字以便获取state1->setName("state1");/*******************************************************************节点二****************************************************************/LayerColor *block2 = LayerColor::create(Color4B::RED, 70, 70);this->addChild(block2);block2->ignoreAnchorPointForPosition(false);block2->setAnchorPoint(Vec2::ANCHOR_MIDDLE);block2->setPosition(Vec2(block1->getPositionX(), block1->getPositionY() - 160));//设置名字以便获取block2->setName("block2");//附加在节点二上的名字标签auto label2 = Label::createWithSystemFont("block2", "", 22);block2->addChild(label2);label2->setPosition(block2->getContentSize() / 2);//节点二状态标签auto state_label2 = Label::createWithSystemFont("Block2 State:", "", 25);state_label2->setPosition(Vec2(state_label2->getContentSize().width / 2,block2->getPositionY() + block2->getContentSize().height));this->addChild(state_label2);auto state2 = Label::createWithSystemFont("Stop", "", 25);state2->setPosition(Vec2(visibleSize.width/2,state_label2->getPositionY()));this->addChild(state2);state2->setName("state2");/*******************************************************************菜单条目****************************************************************//*******节点的Start菜单条目,用于节点开启调度器******/MenuItemLabel* Start_menuItem1 = MenuItemLabel::create(Label::createWithSystemFont("Start", "", 25), [&](Ref* sender){//修改Block1状态auto state = dynamic_cast<Label*>(this->getChildByName("state1"));state->setString("Running...");//开启当前节点的updatethis->scheduleUpdate();//设置当前点击目标不可用auto start_item = dynamic_cast<MenuItemLabel*>(sender);start_item->setEnabled(false);//获取Remove并设置为可用点击auto menu = dynamic_cast<Menu*>(this->getChildByName("menu"));auto remove_item = dynamic_cast<MenuItemLabel*>(menu->getChildByName("remove_item1"));remove_item->setEnabled(true);});Start_menuItem1->setPosition(Vec2(Start_menuItem1->getContentSize().width / 2 - visibleSize.width / 2, Start_menuItem1->getContentSize().height - 10));Start_menuItem1->setName("start_item1");auto Start_menuItem2 = MenuItemLabel::create(Label::createWithSystemFont("Start", "", 25),[&](Ref *sender){if (!isScheduled(CC_SCHEDULE_SELECTOR(SchedulerTest::Own_Update))){//设置当前点击目标不可用auto start_item = dynamic_cast<MenuItemLabel*>(sender);start_item->setEnabled(false);/*******************************************开启自定义节点的update:在3秒之后开启,每1秒调用一次,一直开启**参数相关:**param1  CC_SCHEDULE_SELECTOR(SchedulerTest::Own_Update):被调度器回调的函数**param2  1.0f:每隔一秒调用一次**param3  重复调用**param4  第一次开启调度器延迟时间,这里为4秒******************************************/this->schedule(CC_SCHEDULE_SELECTOR(SchedulerTest::Own_Update), 1.0f, CC_REPEAT_FOREVER, 4.0f);//开启另一个调度器,准备开启this->schedule(CC_SCHEDULE_SELECTOR(SchedulerTest::ReadyFunc), 1.0f, 3, 0);}});Start_menuItem2->setPosition(Vec2(Start_menuItem2->getContentSize().width / 2 - visibleSize.width / 2, -150));Start_menuItem2->setName("start_item2");/*******节点的Remove菜单条目,用于移除节点调度器******/MenuItemLabel *Remove_menuItem1 = MenuItemLabel::create(Label::createWithSystemFont("Remove", "", 25), [&](Ref *sender){//修改Block1状态auto state = dynamic_cast<Label*>(this->getChildByName("state1"));state->setString("Removed");//关闭updatethis->unscheduleUpdate();//设置当前目标不可用auto pause_item = dynamic_cast<MenuItemLabel*>(sender);pause_item->setEnabled(false);//获取Start并设置为可点击auto menu = dynamic_cast<Menu*>(this->getChildByName("menu"));auto start_item = dynamic_cast<MenuItemLabel*>(menu->getChildByName("start_item1"));start_item->setEnabled(true);});Remove_menuItem1->setPosition(Vec2(Start_menuItem1->getPositionX() + Start_menuItem1->getContentSize().width * 2,Start_menuItem1->getPositionY()));Remove_menuItem1->setEnabled(false);Remove_menuItem1->setName("remove_item1");auto Remove_menuItem2 = MenuItemLabel::create(Label::createWithSystemFont("Remove", "", 25), [&](Ref* sender){if (isScheduled(CC_SCHEDULE_SELECTOR(SchedulerTest::Own_Update))){//修改Block2状态auto state = dynamic_cast<Label*>(this->getChildByName("state2"));state->setString("Removed");this->unschedule(CC_SCHEDULE_SELECTOR(SchedulerTest::Own_Update));//设置当前目标不可用auto remove_item = dynamic_cast<MenuItemLabel*>(sender);remove_item->setEnabled(false);//获取Start并设置为可点击auto menu = dynamic_cast<Menu*>(this->getChildByName("menu"));auto start_item = dynamic_cast<MenuItemLabel*>(menu->getChildByName("start_item2"));start_item->setEnabled(true);}});Remove_menuItem2->setPosition(Vec2(Start_menuItem2->getPositionX() + Start_menuItem2->getContentSize().width * 2,Start_menuItem2->getPositionY()));Remove_menuItem2->setEnabled(false);Remove_menuItem2->setName("remove_item2");/*******节点的Pause菜单条目,用于暂停当前节点的所有调度器******/auto Pause_menuItem = MenuItemLabel::create(Label::createWithSystemFont("PauseCurrentTarget", "", 25), [&](Ref* sender){//暂停当前节点中的所有调度器this->getScheduler()->pauseTarget(this);//设置当前目标不可用auto remove_item = dynamic_cast<MenuItemLabel*>(sender);remove_item->setEnabled(false);//获取Resume并设置为可点击auto menu = dynamic_cast<Menu*>(this->getChildByName("menu"));auto resume_item = dynamic_cast<MenuItemLabel*>(menu->getChildByName("resume_item"));resume_item->setEnabled(true);//修改Block1状态auto state1 = dynamic_cast<Label*>(this->getChildByName("state1"));if (state1->getString() == "Running..."){state1->setString("Pause");}//修改Block2状态auto state2 = dynamic_cast<Label*>(this->getChildByName("state2"));if (isScheduled(CC_SCHEDULE_SELECTOR(SchedulerTest::Own_Update)) || isScheduled(CC_SCHEDULE_SELECTOR(SchedulerTest::ReadyFunc))){state2->setString("Pause");}});Pause_menuItem->setPosition(Vec2(0,Pause_menuItem->getContentSize().height * 3 - visibleSize.height/2));Pause_menuItem->setName("pause_item");/*******节点的Resume菜单条目,用于恢复当前节点的所有调度器******/auto Resume_menuItem = MenuItemLabel::create(Label::createWithSystemFont("ResumeCurrentTarget", "", 25), [&](Ref* sender){//恢复当前节点的所有调度器this->getScheduler()->resumeTarget(this);//设置当前目标不可用auto remove_item = dynamic_cast<MenuItemLabel*>(sender);remove_item->setEnabled(false);//获取Pause并设置为可点击auto menu = dynamic_cast<Menu*>(this->getChildByName("menu"));auto pause_item = dynamic_cast<MenuItemLabel*>(menu->getChildByName("pause_item"));pause_item->setEnabled(true);//修改Block1状态auto state1 = dynamic_cast<Label*>(this->getChildByName("state1"));if (state1->getString() == "Pause"){state1->setString("Running...");}//修改Block2状态auto state2 = dynamic_cast<Label*>(this->getChildByName("state2"));if (isScheduled(CC_SCHEDULE_SELECTOR(SchedulerTest::Own_Update))){state2->setString("Running...");}});Resume_menuItem->setPosition(Vec2(Pause_menuItem->getPositionX(),Pause_menuItem->getPositionY() - Resume_menuItem->getContentSize().height * 2));Resume_menuItem->setEnabled(false);Resume_menuItem->setName("resume_item");//菜单auto menu = Menu::create(Start_menuItem1, Start_menuItem2, Remove_menuItem1, Remove_menuItem2, Pause_menuItem, Resume_menuItem, NULL);menu->setName("menu");this->addChild(menu);return true;}//节点的自我更新函数void SchedulerTest::update(float dt){//CCLOG("THE NODE'S UPDATE : %f...",dt);//判断节点的方向static int dir1 = 1;//通过名字获取当前节点的子节点auto block1 = dynamic_cast<LayerColor*>(this->getChildByName("block1"));Vec2 pos = Vec2(block1->getPositionX() + 3 * dir1, block1->getPositionY());if (pos.x > visibleSize.width - block1->getContentSize().width/2 || pos.x < block1->getContentSize().width/2){dir1 = -dir1;}block1->setPosition(pos);}//自己的自我更新函数void SchedulerTest::Own_Update(float dt){//log("This is My Own Update : %f...",dt);static int dir2 = 1;//通过名字获取当前节点的子节点auto block2 = dynamic_cast<LayerColor*>(this->getChildByName("block2"));Vec2 pos = Vec2(block2->getPositionX() + 3 * dir2, block2->getPositionY());if (pos.x > visibleSize.width - block2->getContentSize().width / 2 || pos.x < block2->getContentSize().width / 2){dir2 = -dir2;}block2->setPosition(pos);}//准备状态的函数void SchedulerTest::ReadyFunc(float dt){static int i = 4;i--;//修改Block2状态auto state = dynamic_cast<Label*>(this->getChildByName("state2"));state->setString(String::createWithFormat("Ready to Start:%d second", i)->getCString());if (i == 0){i = 4;//修改Block2状态auto state = dynamic_cast<Label*>(this->getChildByName("state2"));state->setString("Running...");//获取Remove.auto menu = dynamic_cast<Menu*>(this->getChildByName("menu"));auto remove_item = dynamic_cast<MenuItemLabel*>(menu->getChildByName("remove_item2"));remove_item->setEnabled(true);}}

其实获取节点的方法有多种,节点都有属于自己的tag和Name的,并且节点是通过添加和被添加的形式渲染在场景中,所以,一旦节点被渲染了,就可以有不同的方式获取。即可以通过tag或者Name来取得,前提是它的tag或是Name必须要被设置。

上面的代码我也做了比较详细的注释了,就不多说了,有不懂的也可以提出来哈~

好了,关于节点的自我更新函数Update及定时器的使用就将到这里,下一篇就来说说关于动作类的相关的。有了它,又为场景中的对象增添了不少“光彩”哈~



0 0
原创粉丝点击