计时器

有时候会想让某个函数不断的去执行,或许只是执行一次,获取你想让他每隔几秒执行一次,这些功能的实现可以使用定时器。

cocos2d-x中有三种定时器 schedulescheduleUpdatescheduleOnce

计时器种类

  1. scheduleUpdate
  1. this->scheduleUpdate(); //加入当前节点后,程序会每帧都会自动执行一次默认的update函数。

一定是update函数,若想调用其他自己命名的函数则使用schedule,每个cocos的类都会自带一个update函数

默认的update()函数为,要使用时,需要用户自行添加

  1. void HelloWorld::update(float a){
  2. //函数体
  3. }
  1. schedule
  1. schedule(schedule_selector(执行的函数),1.0f);

可以没隔几秒执行某个自定义的函数。时间不能小于帧速率,上述代码为每隔1秒执行一次函数,函数的参数有

schedule(SEL_SCHEDULE selector, float interval, unsigned int repeat, float delay)

selector为用户选择的事件函数

interval为事件触发时间间隔

repeat为触发一次之后还会触发的次数,默认永远循环(kRepeatForever)

delay为开始执行本次计时器的延时时间

  1. scheduleOnce
  1. scheduleOnce(schedule_selector(执行的函数),1.0f);

可以在等待几秒之后执行,并且只执行一次。

停止计时器

当满足一定状态时,我们并不想让计时器继续,则在计时器中使用此语句

  1. 停止执行自己定义函数的定时器:

this->unschedule(schedule_selector(HelloWorld::Move));

  1. 停止默认定时器:

this->unscheduleUpdate();

  1. 停止所有定时器:

this->unscheduleAllSelectors();



利用计时器实现倒计时

倒计时在游戏中十分常见,利用倒计时之前,一般我们需要首先获取时间,获取时间的一般方法有

获取时间

  1. 利用c++<time.h>

    struct tm *ptr;
    time_t lt;
    lt = time(NULL);
    ptr = localtime(&lt);
    char time[64] = "";
    sprintf(time, "%d:", ptr->tm_hour);
    /* ptr指针中,有
    tm_hour 时
    tm_min 分
    tm_sec 秒
    tm_mon 从0开始的月份序号
    tm_mday 月份
    tm_wday 星期
    tm_yday 今年的第几天
    tm_year 年份
    几个常用参数*/
    timeLabel->setString(time);
    
  2. 利用cocos的结构体,自己写一个函数用来获取时间

    long long HelloWorld::getCurrentTime() //自定义函数
    {
       struct timeval vt;
    gettimeofday(&vt, NULL);
    long long time = (long long)vt.tv_sec * 1000 + vt.tv_usec / 1000;
    return time; //注意,获取的是毫秒数
    }
    
  3. 或者,只是想简单获得时间的插值,那么可以单单设置一个自定义变量后使用计时器手动计时

    schedule(schedule_selector(HelloWorld::updateTime),1.0f);
    int sec=10;
    char time[64] = "";
    //为了有优化性能,请尽量不要在计时器中创建变量
    void HelloWorld::updateTime(float a) {
    sec--;
    sprintf(time, "%d", sec);
    timeLabel->setString(time);
    }
    

进行十秒的倒计时

现在,让我们设置一个秒数变量time_sec

void HelloWorld::updateTime(float a) {
    time_sec--;
    if (time_sec < 0)
        this->unscheduleAllSelectors(); //倒计时归零时停止计时器
    char time[64] = "";
    sprintf(time, "%d", time_sec);
    timeLabel->setString(time);
}

或者,我们使用getCurrentTime()的方法(注意计算前后插值,因为获取的毫秒数并不是从0开始计算)

我们设置一个时间的变化量time_before用来计算每次的时间差值

time_before = getCurrentTime();  //场景初始化时,保存当前毫秒数

void HelloWorld::updateTime(float a) {

    long long time_delta = (getCurrentTime() - time_before)/1000; //毫秒转秒

    log("当前time_before:%ld", time_before);
    log("当前time_delta:%ld", time_delta);

    if (time_delta >= time_sec)
        this->unscheduleAllSelectors(); //也可以在此处增加GameOver的函数,表示时间截止

    char time[64] = "";
    sprintf(time, "%ld", time_sec-time_delta );
    timeLabel->setString(time);

}

如果只是简简单单的计算十秒倒计时,不妨使用简单的计时器,在计时器时间间隔处设置为1秒,但是如果想要制作复杂的时间系统,或者游戏内时钟,可以使用时间差值进行计算,以及使用<time.h>



利用计时器制作进度条

上一章中提交的进度条LoadingBar的制作,但是,那是一个精致的进度条,使用schedule的更新,可以使进度条动起来

不妨我们设置一个功能,当登录时,必须按住登录按钮2秒才可登录,并对2秒内的进度条进行更新

设置相关参数

int time_msec = 4000;                 //毫秒数
float barPercent = 0;                //进度条百分比
bool buttonClicked = false;          //按钮是否按下判断
bool loginTimeJudge = false;         //判断时间到达是否最终能登录
LoadingBar *loadingBar;                //进度条本体
void updateLoadingBarTime(float a);     //计时函数

进度条更新部分

// loadingButton的监听事件
schedule(schedule_selector(HelloWorld::updateLoadingBarTime),0.05f); //加载更新进度条的计时器
loginButton->addTouchEventListener([=](Ref* pSender, ui::Widget::TouchEventType type) {

    if (type == ui::Widget::TouchEventType::BEGAN) {    //当按钮点击开始时
        log("登录按钮被按下");
        buttonClicked = true; //按钮按下

    }else if (type == ui::Widget::TouchEventType::ENDED) {
        log("登录按钮弹起");
        buttonClicked = false;//按钮弹起

        if (loginTimeJudge == true) { //只有在到达事件后才进行判断
            auto name = editName->getText();
            auto password = editPassword->getText();

            if (name == nullptr || password == nullptr)
                return;
            if(strcmp(name,"root")==0 && strcmp(password, "123456")==0) {
                log("密码正确");
                loginSuccessful();

            }else {
                log("密码或账号错误");

                time_msec = 4000;//重置时间
                loginTimeJudge = false;//重置判断
            }
        }
    }
});
//更新进度条的函数
void HelloWorld::updateLoadingBarTime(float a) { //该函数0.05秒刷新一次
    if (buttonClicked) { //按下状态时才允许减时间
        time_msec -= 100;
        if (time_msec <= 0)
            loginTimeJudge = true;
    }
    else if(time_msec<4000){
        time_msec += 100;
    }
    barPercent = ((4000.0 - time_msec) / 4000.0)*100; //每时每刻更新进度条占比
    loadingBar->setPercent(barPercent);
    return;
}

image.pngimage.pngimage.png
根据单击按钮时长自动更新的进度条