Schedule problem with replaceScene

Hi,
I have read some people with this problem in the forum, but I could not solve the problem.
In the init() function, I’ve this two important lines:
buttomPlay->addTouchEventListener(CC_CALLBACK_1(HelloWorld::onTouchPlay, this));
schedule(SEL_SCHEDULE(&HelloWorld::updateMy), 1/60);

When I run my app, the method “updateMy” works fine. Is called every 1/60 seconds.
Then, I touch the screen and the logic call the method “onTouchPlay”. In the onTouchPlay function, I replace the init Scene like this:

Scene *s = Scene::create();
Director::getInstance()->replaceScene(s);

My problem is, when the scene is replaced, the scheduler stop working.
I tried with push and pop scene, and creating a virtual void onEnter and replace the scene there, but nothing works.
I tried too, remove all child from the current scene and use the same scene, and it’s works, but this not is the solution, I need replace scene.

Anyone can help me?
Thanks.

@tranthor
When you replay Scene From Scene-A to Scene-B, Scene-A will be paused and all actions and schedules will be paused.

Thanks

1 Like

Ok perfect, but how can I fix this problem? I need run the scheduler method all the time.

You can add sprite on top instead of replacing scene.

Sry but I don’t understand u. Can u give me an example?

Can you explain more how you are going to use another scene and why you need update() from previous scene?

I’m using box2d and the method scheduled “updateMy” is the method that updates the sprites positions, world step’s, etc. So, I need run the method all the time, else my game would not work fine.

Why you don’t add touchListener and update() in the new scene you transition to ?

because when I tried to add the Schedule after replace scene, this does not work. Then, I need to add this in the init() function. How can I solve this problem? Thanks

Create scene like this:

YourScene .hpp

class YourScene: public cocos2d::LayerColor {
    
public:
    
    static cocos2d::Scene* createScene();
    
    virtual bool init();
    
    CREATE_FUNC(YourScene);      

    bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event);

};

YourScene.cpp

using namespace cocos2d;

Scene* YourScene::createScene() {
    
    auto scene = Scene::create();
    auto layer = YourScene::create();
    scene->addChild(layer);
    
    return scene;
}

bool YourScene::init() {
    
    if (!LayerColor::initWithColor(Color4B::GREEN)) {return false;}

    auto listener = EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);
    listener->onTouchBegan = CC_CALLBACK_2(MainMenuScene::onTouchBegan, this);
    Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);                

    return true;
}

Transition to it:

    auto scene = YourScene::createScene();
    Director::getInstance()->replaceScene(TransitionFade::create(1.0, scene, Color3B::BLACK));

etc.

and where is the Schedule() method?

just place it in init()

Okay, but I have a new problem now.
In the onTouchBegan method, I’ve this code:

Auto scene = YourScene :: createScene ();
Director :: getInstance () -> replaceScene (TransitionFade :: create (1.0, scene, Color3B :: BLACK));
B2Vec2 grav = b2Vec2 (0.0f, -10.0f); // gravity
_world = new b2World (grav);
.
.
.

I define the body, bodyDef, Shape, Fixture, etc. And finally I apply a force in the ball:

B2Vec2 force = b2Vec2 (20, 20);
BBall-> ApplyForce (force, ballDef.position, true);

The “updateMy” method is scheduled and it’s calling all the time, the problem is that “_world” variable, is always NULL in the method “updateMy”, except when I touch the screen (only one time is != NULL). The ball does not travel the trajectory for this reason …
I defined _world variable in the class (private part).
What is my problem? I need that when I set the world variable, it live all the time …

I think that scene->addChild(layer); is not the correct solution.
Besides, I want use a button for onTouchBegan:

auto play = cocos2d::ui::Button::create("play.png");
play->setPosition(Vec2(origin.x + visibleSize.width/2, origin.y + visibleSize.height/2));
play->addTouchEventListener(CC_CALLBACK_1(HelloWorld::onTouchBegan, this)); 

I don’t want to use EventListenerTouchOneByOne …
I think this problem is related to unschedule function that call the framework when I use replaceScene().
I need solve the problem, please, anyone… I think is a basic problem but I can not solve it weeks ago

If you need them to run all the time, put them in a singleton.
Scheduling will be like:

cocos2d::Director::getInstance()->getScheduler()->schedule(CC_CALLBACK_1(&MySingleton::updateMy), this, 1.0f / 60, false, "key");

Thanks for the answer. I’m trying to use a Singleton. I created this class:

class MySingleton
{
private:
    b2World *_world = NULL;
    MySingleton() {}

public:
    static MySingleton* getInstance()
    {
        static MySingleton *instance = new MySingleton();
        return instance;
    }
    
    void updateMy(float dt);
    b2World* getWorld() { return this->_world;  };
};

In the HelloWorld::init() I put this line:

Director::getInstance()->getScheduler()->schedule(SEL_SCHEDULE(&MySingleton::updateMy), this, 1/60, false);

And finally, in the onTouchBegan I changed this lines:

Scene *scene = Scene::create();
Director::getInstance()->replaceScene(scene);
b2World* _world = MySingleton::getInstance()->getWorld();

…and I’m using the _world variable for set body, bodydef, fixture, shape, etc.

I have an error when run the app. What is the problem? Can you give me a complete example?
I would like to put the scheduler() in a new MySingleton method, like “runGame()” and in the init() method call this like MySingleton::getInstance()->runGame(). Is that possible? When I put the schedule() in a new MySingleton method, the compiler says “Use of undeclared identifier schedule”
Thanks-

Use the schedule overload with lambda instead.

class MySingleton {
public:
    static MySingleton* getInstance();
    
    void schedule();
    void unschedule();

private:
    void update(float delta);

    b2World* _world;
}

MySingleton* MySingleton::getInstance() {
    static MySingleton sharedInstance;
    return &sharedInstance;
}

void MySingleton::schedule() {
    cocos2d::Director::getInstance()->getScheduler()->schedule(CC_CALLBACK_1(&MySingleton::update, this), this, 1.0f / 60, false, "key")
}

void MySingleton::unschedule() {
    cocos2d::Director::getInstance()->getScheduler()->unschedule(this, "key");
}

void MySingleton::update(float delta) {
    // Do your logic.
}
1 Like

it works. Thanks man!!

Thanks to @enrevol’s code and help elsewhere I got this working with the following:

class GlobalNode {
    public:
        static GlobalNode* getInstance() {
            static GlobalNode sharedInstance;
            return &sharedInstance;
        }
        void schedule() {
            cocos2d::Director::getInstance()->getScheduler()->schedule(
                    CC_CALLBACK_1(GlobalNode::update, this), this, 1.0f / 60, false, "key");
        };

        void unschedule() {
            cocos2d::Director::getInstance()->getScheduler()->unschedule("key", this);
        };

    private:
        void update(float dt)
        {
            CCLOG("this is being called every frame, no matter the replaced scene");
        }

};

... elsewhere :

        GlobalNode::getInstance()->schedule();