Passing a method with a parameter to a Scheduler

Hello,
I am aware that there are threads about this topic. I’ve read them but it didn’t really work for me.
So I wanted to post a very simple example to see if someone can make it work.

#include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    auto scene = HelloWorld::create();
    return scene;
}


bool HelloWorld::init()
{
    if ( !Scene::init() )
        return false;

	std::vector<int> myNumbs {1,2,3,4,5};

	for (auto numb: myNumbs)
	{
		schedule(CC_SCHEDULE_SELECTOR(HelloWorld::printInteger(numb)), 1.0f, kRepeatForever, 0);
		// The line above doesn't work because you can't pass a method with an argument to a scheduler
	}


    return true;
}


void HelloWorld::printInteger(int number)
{
	CCLOG("%i", number);
}

So basically I want to be able to run HelloWorld::printInteger(int number) forrever (or whatever number of times). The problem is that it is not possible to do CC_SCHEDULE_SELECTOR(HelloWorld::printInteger(numb)), 1.0f, kRepeatForever, 0).

Other threads replied to use a lambda that since we can give it arguments, but I don’t see how this solves the scheduling issue.

Can anyone have a look at the code above and see how you would could schedule HelloWorld::printInteger(int number).

thanks,
R

First thing, you should avoid using CC_SCHEDULE_XXXXX macros, because by using them, it’s not immediately obvious what it is you’re actually passing into the scheduler, and there is absolutely no need for them. They really should be marked as deprecated in the code. The scheduler has another overload that can accept a std::function, so you can just pass a lambda to it, which makes the code a lot clearer.

Using that CC_SCHEDULE_SELECTOR may be what is confusing you here. The first thing you always need to do is look up the declaration of that macro or method you’re using, and figure out what it accepts. If you do that, you would see something along the lines of this:

#define CC_SCHEDULE_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_SCHEDULE>(&_SELECTOR)

Now if you check what SEL_SCHEDULE, you’ll notice this:

typedef void (Ref::*SEL_SCHEDULE)(float);

It is clearly accepting a method with a signature of void(float), so, now that you know that, we can’t just send it whatever method signature we want, which is what you’re trying to do by giving it this:

void printInteger(int number)

You need to re-think how you want to implement that functionality. One possible solution is to use a member variable to track the index into the vector (the vector can also be a member of HelloWorld), and you increment it each time the scheduler is called. Inside the lambda you would access both the vector and the counter to do what you need with them.

Hey R101, you mean something like this?

#include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    auto scene = HelloWorld::create();
    return scene;
}


bool HelloWorld::init()
{
    if ( !Scene::init() )
        return false;

	
	std::vector<int> myNumbs {1,2,3,4,5};

	for (auto numb: myNumbs)
	{
		auto scheduler = Director::getInstance()->getScheduler();
		scheduler->schedule( [=] (float dt) {
			printInteger(counter);
			counter ++;
			if (counter > 5)
				counter = 1;
		}, this, 2, false, "funcKey");
	}
    return true;
}


void HelloWorld::printInteger(int number)
{
	CCLOG("%i ", number);
}

where counter is a member variable starting at 1.

Yes, something like that.

1 Like