Schedule a task recursively

cc.Class({
    extends: cc.Component,

    start () {
    	this.fireOneRound ();
    },
    
    fireOneRound () {
    	cc.log ("fire");
    	this.prepareNextFire ();
    },
    
    prepareNextFire () {
    	var delay = Math.random ();
    	this.scheduleOnce (this.fireOneRound, delay);
    },
});

For some reason, this will work in the simulator but will trigger only once if launched in the browser.
Is there a reason for that? What is the right way to achieve that?

At first I though the reason is different bindings, but then I saw log in browser (which I dont understand why): “cc.Scheduler#scheduleSelector: Selector already scheduled. Updating interval from: 0 to 0”.

Anyway, you can rewrite your code like this: this.scheduleOnce (this.fireOneRound.bind(this), 1);

I found the reason. In browser scheduleOnce resolves this.fireOneRound as the same selector, even if you run below code

let that = this;
this.scheduleOnce(that.fireOneRound, 1);

But when you run the code

let that = this;
this.scheduleOnce(function() {
that.fireOneRound();
}, 1);

or

this.scheduleOnce (this.fireOneRound.bind(this), 1);

then it will cheat as different selector. That’s strange. I think it’s a bug.

Ah, smart workaround, an anonymous function.
But then with these solutions, I can’t unschedule anymore, as it’s a different selector each time.
But then if I save the last scheduled selector to be able to unschedule it later, it works.
Here is the final code.

cc.Class({
    extends: cc.Component,
    
    properties: {
    	lastScheduledFire: null,
    },

    start () {
    	this.fireOneRound ();
    },
    
    unscheduleFire () {
    	this.unschedule (this.lastScheduledFire);
    },
    
    fireOneRound () {
    	cc.log ("fire");
    	this.prepareNextFire ();
    },
    
    prepareNextFire () {
    	var delay = Math.random ();
    	this.lastScheduledFire = function () { this.fireOneRound (); };
    	this.scheduleOnce (this.lastScheduledFire, delay);
    },

});

Note there is no need for the “let that = this” if you use an anonymous function.

I would consider it as a bug indeed, because:

  1. It doesn’t happen in the simulator
  2. No mention of such a limitation in the documentation

Also, the “Selector already scheduled” message you mentioned disappears if you unschedule (this.fireOneRound) before scheduling it again, but it will still never trigger.