6-performFunctionInCocosThread

2019-02-20  本文已影响15人  porridgechen890

问题的提出

假设现在有这样一个需求:按住一个按钮后开始录音,录音开始后播放录音动画,松开按钮后停止录音,并移除录音动画。

分析

录音由安卓和iOS的代码实现,不在cocos这一层,并且属于新开的线程。但播放动画和停止动画由cocos的代码实现,属于cocos的UI线程。所以如果安卓(或iOS)代码启动录音成功需要告诉cocos的UI线程播放动画。如果安卓(或iOS)代码停止录音成功需要告诉cocos的UI线程停止动画。在cocos里新开辟一个线程可以用std::thread,在其他线程里回调cocos的函数可以用performFunctionInCocosThread。

Android里面有runOnUiThread,IOS下有performSelectorOnMainThread。
cocos2dx 3.0系列中新加入了一个专门处理线程安全的函数performFunctionInCocosThread(),它的声明如下:
/** Calls a function on the cocos2d thread. Useful when you need to call a cocos2d function from another thread.
This function is thread safe.
@param function The function to be run in cocos2d thread.
@since v3.0
@js NA
*/
void performFunctionInCocosThread(std::function<void()> function);

代码

这个Demo展示的是如何开辟新的线程和在支线程里如何影响UI线程。

//HelloWorld.h
class HelloWorld : public cocos2d::Scene
{
public:
    static cocos2d::Scene* createScene();
    virtual bool init();
    void menuCloseCallback(cocos2d::Ref* pSender);
    CREATE_FUNC(HelloWorld);
    void threadA();
};
//HelloWorld.cpp
bool HelloWorld::init()
{
    //其他未改动的代码省略了
    this->addChild(sprite, 0, "helloworld");//这里给这个图加了个名字
}

void threadB()
{
    Director::getInstance()->getScheduler()->performFunctionInCocosThread([]{
        auto sprite = Sprite::create("res/MagentaSquare.png");
        Director::getInstance()->getRunningScene()->addChild(sprite);
        Size size = Director::getInstance()->getWinSize();
        sprite->setPosition(Vec2(size.width/2-10, size.height/2));
    });
}

void HelloWorld::menuCloseCallback(Ref* pSender)
{
    std::thread t1(&HelloWorld::threadA, this);
    t1.detach();
    log("新开线程释放了");
    
    //这个t2只是为了说明新开的线程的函数可以不是成员函数,普通函数也可以
    std::thread t2(threadB);
    t2.detach();
}

void HelloWorld::threadA()
{
    Director::getInstance()->getScheduler()->performFunctionInCocosThread([this]{
        //新开线程回调主线程做两件事,创建并显示一个黄色方块,隐藏原来的HelloWorld图片。
        auto sprite = Sprite::create("res/YellowSquare.png");
        this->addChild(sprite);
        Size size = Director::getInstance()->getWinSize();
        sprite->setPosition(Vec2(size.width/2+10, size.height/2));
        auto spriteHelloWorld = this->getChildByName("helloworld");
        if (spriteHelloWorld)
        {
            spriteHelloWorld->setVisible(false);
        }
        log("新开线程的回调执行完了");
    });
    log("新开线程的函数执行完了");
}
没有点按钮时.png
点了按钮之后.png
image.png
上一篇下一篇

猜你喜欢

热点阅读