iosiphonexcodecocos2d-xcocos2d-x-3.x

Cocos2d-x Buttons - MenuItemSprite Vs Button


Cocos2d-x Version 3.17

// Create Button : Type - 1

{
    Sprite *spr1 = Sprite::createWithSpriteFrameName(FRAME_MM_PLAY);
    Sprite *spr2 = Sprite::createWithSpriteFrameName(FRAME_MM_PLAY);

    spr2->setColor( Color3B(200, 200, 200) );

    auto *playButton = MenuItemSprite::create(spr1, spr2, CC_CALLBACK_1(CBirdMainMenu::playBtnPress, this));
    playButton->setScale(1.0f);
    playButton->setEnabled(true);

    auto playMenu = Menu::create(playButton, nullptr);
}

// Create Button : Type - 2

Button *infoButton
    {
        infoButton = Button::create(FRAME_MM_INFO,FRAME_MM_INFO,FRAME_MM_INFO,Widget::TextureResType::PLIST);
        infoButton->setZoomScale(0.2f);
        infoButton->setPressedActionEnabled(true);
        infoButton->addTouchEventListener([&](Ref* sender, cocos2d::ui::Widget::TouchEventType type){
            switch (type)
            {
                case ui::Widget::TouchEventType::BEGAN:
                    break;
                case ui::Widget::TouchEventType::ENDED:
                    this->infoButtonPress();
                    break;
                default:
                    break;
            }
        });

        This->addChild(infoButton, 2);
    }

In Type-2 how to change color of button when clicked. I used single image for all states. I don't like to use separate image. Is it possible to change color of selected sprite in Type2 ? In Type1, for MenuItemSprite , we can easily set color for selected image……In Type-2, if I call setColor on Button, then it is crashing.

infoButton->setColor(Color3B(200, 200, 200)); //Crashed on this

Don't know how to change color of button when pressed.


Solution

  • you are creating the button and assigning to the InfoButton pointer.

    infoButton = Button::create(FRAME_MM_INFO,FRAME_MM_INFO,FRAME_MM_INFO,Widget::TextureResType::PLIST);
    

    the problem is though your infoButton is a local pointer.

    Button *infoButton;
      {
        ...
        ...
    

    from the screenshot you have provided, I can see that it's locally created in CBirdMenu::SetupMenu().

    you then add the info button as a child to an object pointed by a pointer called toolBar However the moment the CBirdMenu::SetupMenu() ends, your infoButton will no longer be recognised by the lambda expression.

    one way and perhaps easiest way is to fix your problem is using dynamic casting on the lambda parameter Ref* sender within the lambda expression.

    InfoButton->addTouchEventListener([&](Ref* sender, cocos2d::ui::Widget::TouchEventType type)
    {
        cocos2d::ui::Button * infButton = dynamic_cast<cocos2d::ui::Button*>(sender);
        if(infButton)//check if casting done properly
           infButton->setColor(Color3B(0, 200, 0)); //colour set to green.
    });
    

    or alternativly, instead of having a local pointer infoButton, store it as a class member of CBirdMenu. this way infoButton will never get lost while the cBirdMenu exists.

    here is a quick demo. the header file;

        #include "cocos2d.h"
        #include "ui\CocosGUI.h"
        class HelloWorld : public cocos2d::Layer
        {
        public:
            static cocos2d::Scene* createScene();
            virtual bool init();
            void menuCloseCallback(cocos2d::Ref* pSender);
            CREATE_FUNC(HelloWorld);
        private:
            cocos2d::ui::Button * InfoButton; //member of HelloWorld.
        };
    

    notice the private member cocos2d::ui::Button * InfoButton; And finally the source file where the button is instantiated and assigned to the infoButton pointer.

    // on "init" you need to initialize your instance
    bool HelloWorld::init()
    {
        //////////////////////////////
        // 1. super init first
        if ( !Layer::init() )
            return false;
    
        Size visibleSize = Director::getInstance()->getVisibleSize();
        Vec2 origin = Director::getInstance()->getVisibleOrigin();
    
        InfoButton = cocos2d::ui::Button::create("HelloWorld.png", "HelloWorld.png", "HelloWorld.png", ui::Widget::TextureResType::LOCAL);
        InfoButton->setColor(Color3B(255, 0, 0)); //colour is set to red as suppose to.
        InfoButton->setTitleFontSize(InfoButton->getTitleFontSize() * 0.7);
        InfoButton->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y));
        InfoButton->addTouchEventListener([&](Ref* sender, cocos2d::ui::Widget::TouchEventType type)
        {
            InfoButton->setColor(Color3B(0, 200, 0)); //colour set to green.
        });
        // add the button as a child to this layer
        this->addChild(InfoButton, 2);
        return true;
    }
    

    if you apply the same principle to your code, this should solve your current problem with the lambda. However I'm still not sure what yourtoolBar class does since this is not included in the code. if toolBar is a custom class, i recommend you to move your infoButton from CBirdMenu to toolBar instead if you going with the second approach to adress your issue.