cocos2d-x 4.0 learning path (fourteen) action monitoring (CallFunc)

Today we come to learn another action-CallFunc, it is a special action, it is invisible, unlike the actions we used before are very specific, such as moving, jumping, rotating, etc. The function of CallFunc is to call back a function.
With CallFunc we can implement action monitoring. For example, we want to let a sprite move to its destination and notify us that it has arrived (a Label is displayed). It is easy to achieve with CallFunc.

bool HelloWorld::init() {
    auto moveBy = MoveBy::create(1.0f, Vec2(500, 0));
    auto arrived = [&]() {
        auto visibleSize = Director::getInstance()->getVisibleSize();
        auto label = Label::createWithTTF("*** I arrived! ***", "fonts/arial.ttf", 24);
        label->setPosition(visibleSize.width / 2, visibleSize.height / 2 + 100);
        this->addChild(label);
    };
    auto callFunc = CallFunc::create(arrived);
    sprite1->runAction(Sequence::create(moveBy, callFunc, nullptr));
    return true;
}

We see that when the sprite finishes moving, the arrived () function will be called and the Label will be created and displayed. effect:
Insert picture description here

auto arrived = [](){};This callback function is actually a Lambda function. This is C ++ and has nothing to do with cocos2dx. This type of function callback has only been supported since cocos2dx3.0.
Similar to Lambda in java, it is an anonymous function. Its structure is: [] () {}
[]: It means to start a Lambda function
(): The parameters of the function can be filled in
{}: The content of the function is inside

We write a simple example:

auto func = [](){
	log("test");
};
auto callFunc = CallFunc::create(func);
this->runAction(callFunc);

This way you can see test in the output. Someone may ask, can this-> runAction? Wasn't it all sprite-> runAction before?
In fact, as long as it is a class that inherits from Node, you can use runAction. Sprite directly inherits Node, and this (that is, our HelloWorld class) inherits from Scene, and Scene inherits from Node. So you can use this-> runAction directly to let it execute the action.

In the top example, someone will observe an ampersand in the square brackets. What is this symbol for? You can remove it and try it out, is it a compilation error? A concept involved here is the capture mode of the variable.
To put it in human terms, what should you do when you want to use variables outside the Lambda function in the Lambda function? Do not think that this Lambda function is written in the function you are currently running (for example, we are currently running in init), you can easily access the local variables in this function or access the global variables of the class, that is impossible. why? Because the Lambda function is essentially a function, when the computer creates it, it opens up a section of memory space for it, and it does not matter where you write it. In other words, this (global variable) and sprite (local variable) in HelloWorld are completely invisible to the Lambda function.

So, we still want to use this, sprite them, what should we do? You need to add the specified symbol in [] to specify the capture mode of the variable. The common capture modes are as follows
[]:: No interception of any variable
[&]: Intercept all variables in the external scope and use them as references in the Lambda function. As long as the variables in the external scope are not released, they can be used in the Lambda function. Therefore, local variables cannot be used because local variables will be released.
[=]: Intercept all variables in the external scope and make a copy for use in the Lambda function. Even if the value of the external variable changes, when the Lambda function is executed, it is still the value of the copy.
[=, &myvar]: Same as [=], but use references to myvar variables (that is, [&] method).
[myvar]: Same function as [=], but only for one variable of myvar, other variables are ignored.

It is estimated that everyone is dizzy. Still explain in code.
In the following Lambda function, we create a label, and then use this to add it to HelloWorldScene, then this this is an external variable, we want to use it, set the capture mode [&], this is used.

bool HelloWorld::init() {
    auto arrived = [&]() {
        auto visibleSize = Director::getInstance()->getVisibleSize();
        auto label = Label::createWithTTF("*** I arrived! ***", "fonts/arial.ttf", 24);
        label->setPosition(visibleSize.width / 2, visibleSize.height / 2 + 100);
        this->addChild(label);
    };
    this->runAction(arrived);
    return true;
}

Let's change this code again and put the definition of Label outside the Lambda function:

bool HelloWorld::init() {
	auto visibleSize = Director::getInstance()->getVisibleSize();
    auto label = Label::createWithTTF("*** I arrived! ***", "fonts/arial.ttf", 24);
    label->setPosition(visibleSize.width / 2, visibleSize.height / 2 + 100);
    auto arrived = [&]() {
        this->addChild(label);
    };
    this->runAction(arrived);
    return true;
}

In this way, for the Lambda function arrived, this and Label are external variables. Is it still possible to use [&]? It won't compile. Because this is a global variable of HelloWorld, label is a local variable of the init () function. When the init () function is executed, this will not be released, and the label will be released (no longer exists, what else do you visit). This place is a bit subtle, in fact, the Label object itself has not been released, only the local variable label has been released. In other words, the pointer label is released, but the object it points to is not released. (I really don't understand and don't need to tangle with this one) At
this time, we have to use [=]. In other words, copy a label pointer to the lambda function and it's OK. Since the Lambda function is an anonymous function, we can of course omit the function name and write it directly in runAction.

bool HelloWorld::init() {
	auto visibleSize = Director::getInstance()->getVisibleSize();
    auto label = Label::createWithTTF("*** I arrived! ***", "fonts/arial.ttf", 24);
    label->setPosition(visibleSize.width / 2, visibleSize.height / 2 + 100);
    this->runAction([=]() {
        this->addChild(label);
    });
    return true;
}

As long as you understand [&] and [=], the other patterns are easy to understand.

So much about Lambda functions, it should be enough for general needs. If you want to keep improving, you can find more information and research C ++ knowledge.

Published 104 original articles · Like8 · Visit 210,000+

Guess you like

Origin blog.csdn.net/sunnyboychina/article/details/105338241