标签:
这一篇来谈谈关于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;
};
#endifSchedulerTest.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...");
//开启当前节点的update
this->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");
//关闭update
this->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);
}
}上面的代码我也做了比较详细的注释了,就不多说了,有不懂的也可以提出来哈~
好了,关于节点的自我更新函数Update及定时器的使用就将到这里,下一篇就来说说关于动作类的相关的。有了它,又为场景中的对象增添了不少“光彩”哈~
cocos2dx学习之路----第十二篇(关于Node节点的自我更新函数Update探讨及定时器的使用)
标签:
原文地址:http://blog.csdn.net/qq_30501909/article/details/52089847