MenuItem Callbacks throwing exceptions

Hi, I am currently migrating my software from Cocos2d-X 2.2.6 to Cocos2d-X 3.10 and I am having trouble to make some MenuItem callbacks work.

I’ve tried two types of code:

Sprite *equalSprite, *equalDownSprite;
MenuItemSprite *equalButton;
CCPoint equalButtonPosition;

equalSprite = Sprite::createWithSpriteFrameName("botao_menu_igual.png");
equalDownSprite = Sprite::createWithSpriteFrameName("botao_menu_igual_down.png");

equalButton = MenuItemSprite::create(equalSprite, equalDownSprite, CC_CALLBACK_1(MainMenuLayer::buttonPressedCallback, this));

equalButton->setEnabled(gameContext->getEqualGameEnabled());
equalButton->setTag(EQUAL_BUTTON_TAG);
equalButtonPosition = Point(screenSize.width / 4, screenSize.height / 2);
equalButton->setPosition(mainMenu->convertToNodeSpace(equalButtonPosition));

mainMenu->addChild(equalButton);

And:

Sprite *equalSprite, *equalDownSprite;
MenuItemSprite *equalButton;
CCPoint equalButtonPosition;

equalSprite = Sprite::createWithSpriteFrameName("botao_menu_igual.png");
equalDownSprite = Sprite::createWithSpriteFrameName("botao_menu_igual_down.png");

equalButton = MenuItemSprite::create(equalSprite, equalDownSprite, (Ref *)this, menu_selector(MainMenuLayer::buttonPressedCallback));

equalButton->setEnabled(gameContext->getEqualGameEnabled());
equalButton->setTag(EQUAL_BUTTON_TAG);
equalButtonPosition = Point(screenSize.width / 4, screenSize.height / 2);
equalButton->setPosition(mainMenu->convertToNodeSpace(equalButtonPosition));

mainMenu->addChild(equalButton);

When I run my game, and click on the button created above, I get an exception on the file type_traits file, and in the: return (((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(_STD forward<_Types2>(_Args2)...)); line (see below).

struct _Invoker_pmf_pointer
    {    // INVOKE a pointer to member function on a [smart] pointer
    template<class _Decayed,
        class _Ty1,
        class... _Types2>
        static auto _Call(_Decayed _Pmf, _Ty1&& _Arg1, _Types2&&... _Args2)
        -> decltype(((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(
            _STD forward<_Types2>(_Args2)...))
        {    // INVOKE a pointer to member function on a [smart] pointer
        return (((*_STD forward<_Ty1>(_Arg1)).*_Pmf)(
            _STD forward<_Types2>(_Args2)...));
        }
    };

I am creating this callback wrong? Has anyone encountered this?

1 Like

While we’ve moved over to using lamdas for most of our callback code we still have some old 2.x Menu code as well. You seem to be setting up the callback or selector correctly.

My guess is MainMenuLayer derives Layer (which derives Ref) so you don’t need to cast (Ref*)this. Based on the error maybe your mainMenu is a smart ptr (unique/shared_ptr) instead of raw Menu*? Or maybe your method definition for the callback is wrong? It should be this:

void MainMenuLayer::buttonPressedCallback(Ref* sender) { ... }

You could try using a lambda here for testing or future actual use.

MenuItemSprite::create(equalSprite, equalDownSprite, [this] (Ref*sender) {
  // put your code inside buttonPressedCallback here
});
1 Like

Hi, I’ve changed my code, but the error is still happening.

    Sprite *equalSprite, *equalDownSprite;
    MenuItemSprite *equalButton;
    LabelBMFont *equalButtonLabel;
    MenuItemLabel *equalButtonMenuLabel;
    CCPoint equalButtonMenuLabelPosition;
    CCPoint equalButtonPosition;

    equalSprite = Sprite::createWithSpriteFrameName("botao_menu_igual.png");
    equalDownSprite = Sprite::createWithSpriteFrameName("botao_menu_igual_down.png");

    equalButton = MenuItemSprite::create(equalSprite, equalDownSprite, CC_CALLBACK_1(MainMenuLayer::buttonPressedCallback, this));

    equalButton->setEnabled(gameContext->getEqualGameEnabled());
    equalButton->setTag(EQUAL_BUTTON_TAG);
    equalButtonPosition = Point(screenSize.width / 4, screenSize.height / 2);
    equalButton->setPosition(mainMenu->convertToNodeSpace(equalButtonPosition));
    
    mainMenu->addChild(equalButton);

    equalButtonLabel = LabelBMFont::create(localization->getLocalizedString("EqualButtonLabel"), fontHelper->getStdFont().c_str());
    equalButtonMenuLabel = MenuItemLabel::create(equalButtonLabel, CC_CALLBACK_1(MainMenuLayer::buttonPressedCallback, this));

    equalButtonMenuLabel->setTag(EQUAL_BUTTON_TAG);
    equalButtonMenuLabelPosition.x = equalButtonPosition.x;
    equalButtonMenuLabelPosition.y = equalButtonPosition.y - equalButton->boundingBox().size.height / 2 - equalButtonMenuLabel->boundingBox().size.height;
    equalButtonMenuLabel->setPosition(mainMenu->convertToNodeSpace(equalButtonMenuLabelPosition));

    mainMenu->addChild(equalButtonMenuLabel);

The mainMenu object is a raw *Menu object and is defined like this in my header file:

class MainMenuLayer : public Layer
{

private:

    Size screenSize;

    Menu *mainMenu;

And is created like this:

bool MainMenuLayer::init()
{
    bool result;

    result = Layer::init();

    mainMenu = Menu::create();
    mainMenu->setPosition(0, 0);
    this->addChild(mainMenu);

Finally I also tried to use the Lambda expression that you suggested, but it I still got the error:

equalButton = MenuItemSprite::create(equalSprite, equalDownSprite, [this](Ref *sender)
    {
        this->buttonPressedCallback(sender);
    });

Hi,

I figured out what the error was. The problem was that I was registering a touch listener on a previous scene and I wasn’t removing it when the scene ended.

So when I added the remove touch listener code before changing scenes, everything worked well.

void SplashScreenMenuLayer::onTouchesEnded(Touch* touch, Event* event)
    {
        Director::getInstance()->getEventDispatcher()->removeEventListener(touchListener);
        Director::getInstance()->replaceScene(MainMenuLayer::scene());
    }