Getting scenes data from CCMenu callback

I have GameScene class with array of heroes

class GameScene : public cocos2d::CCLayer
{

public:     
    CCArray *heroes;
        ...
}

I have 4 buttons, with I created as menu items, and have added them at my scene.

    CCMenuItemImage *leftarrow = CCMenuItemImage::itemFromNormalImage(
                                        "arrowleft.png",
                                        "arrowleftpressed.png",
                                        this,
                                        menu_selector(GameScene::leftCallback) );
    leftarrow->setPosition(ccp(GetScreenWidth()/12 - GetScreenWidth() * GetMultiplier() * 0.88, GetScreenHeight()/8));  

    ...

    CCMenu* controlMenu = CCMenu::menuWithItems(prightwheel,
                                                leftarrow,
                                                rightarrow,
                                                uparrow,
                                                downarrow,
                                                NULL);
    controlMenu->setPosition(CCPointZero);
    this->addChild(controlMenu, 100);       

and now in GameScene::leftCallback I try to manage with my array of heroes, which is a part of GameScene.

void GameScene::leftCallback(CCObject* pSender)
{   
        int tsttst = heroes->count();
}

I’m getting exception in “leftCallback” procedure. Tell me please, how to get GameScene’s elements, and properly work with them? I know that I’ve missed something, please help me with this!

I also tries to get the item’s parent(menu), and then menu’s parent (scene) to get current scene’s data, but it don’t helps :frowning:

void GameScene::leftCallback(CCObject* pSender)
{    
  CCMenu* menu = (CCMenu*)(((CCNode*)(pSender))->getParent());
  GameScene* scene = (GameScene*)menu->getParent();
  int tsttst = scene->heroes->count();
}

Could you upload a demo based on HelloWorld to reproduce this issue?

Eugene Myagkiy wrote:

I also tries to get the item’s parent(menu), and then menu’s parent (scene) to get current scene’s data, but it don’t helps :frowning:
>
[…]

Sure, here is my problem, based on HelloWorld project. I’ve used “works_fine” variable to get array’s data right after array definition, also I can use this type of declaraion in any function, but not in function, that attached to menu item with “CCMenuItemImage::itemFromNormalImage” method. Look at the end of .ccp file, I’ve used “exception_here” variable, and got exception here.
P.S. I’m working with cocos2d-1.0.1-x-0.13.0-beta with Marmalade SDK and Visual Studio 2010. Hope this helps xD
HelloWorldScene.h
<pre>
#ifndef HELLOWORLD_SCENE_H
#define HELLOWORLD_SCENE_H
#include “cocos2d.h”
using namespace cocos2d;
class HelloWorld : public cocos2d::CCLayer
{
public:
////////////////////////////////////////////////////////////////////////////
CCArray
heroes;
void HelloWorld::AddSprite(CCArray* aArray, CCSprite* aSprite);
////////////////////////////////////////////////////////////////////////////

// Here’s a difference. Method ‘init’ in cocos2d-x returns bool, instead of returning ‘id’ in cocos2d-iphone
virtual bool init();

// there’s no ‘id’ in cpp, so we recommand to return the exactly class pointer
static cocos2d::CCScene* scene();

// a selector callback
virtual void menuCloseCallback(CCObject* pSender);

// implement the “static node()” method manually
LAYER_NODE_FUNC(HelloWorld);
};

#endif // HELLOWORLD_SCENE_H

HelloWorldScene.cpp
#include "HelloWorldScene.h"

USING_NS_CC;

CCScene* HelloWorld::scene()
{
    // 'scene' is an autorelease object
    CCScene *scene = CCScene::node();

    // 'layer' is an autorelease object
    HelloWorld *layer = HelloWorld::node();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

////////////////////////////////////////////////////////////////////////////
void HelloWorld::AddSprite(CCArray* aArray, CCSprite* aSprite)
{
    CCSprite* pSprite = new CCSprite;
    pSprite = aSprite;
    aArray->addObject(pSprite);
}
////////////////////////////////////////////////////////////////////////////

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !CCLayer::init() )
    {
        return false;
    }

    /////////////////////////////
    // 2. add a menu item with "X" image, which is clicked to quit the program
    //    you may modify it.

    // add a "close" icon to exit the progress. it's an autorelease object
    CCMenuItemImage *pCloseItem = CCMenuItemImage::itemFromNormalImage(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        this,
                                        menu_selector(HelloWorld::menuCloseCallback) );
    pCloseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20) );

    // create menu, it's an autorelease object
    CCMenu* pMenu = CCMenu::menuWithItems(pCloseItem, NULL);
    pMenu->setPosition( CCPointZero );
    this->addChild(pMenu, 1);

    /////////////////////////////
    // 3. add your codes below...


    // add a label shows "Hello World"
    // create and initialize a label
    CCLabelTTF* pLabel = CCLabelTTF::labelWithString("Hello World", "Arial", 24);
    // ask director the window size
    CCSize size = CCDirector::sharedDirector()->getWinSize();

    // position the label on the center of the screen
    pLabel->setPosition( ccp(size.width / 2, size.height - 50) );

    // add the label as a child to this layer
    this->addChild(pLabel, 1);

    // add "HelloWorld" splash screen"
    CCSprite* pSprite = CCSprite::spriteWithFile("HelloWorld.png");

    // position the sprite on the center of the screen
    pSprite->setPosition( ccp(size.width/2, size.height/2) );

    // add the sprite as a child to this layer
    this->addChild(pSprite, 0);

    ////////////////////////////////////////////////////////////////////////////
    heroes = CCArray::array();

    for(int i = 0; i < 5; i++)
        AddSprite(heroes, pSprite);

    int works_fine = heroes->count();

    ////////////////////////////////////////////////////////////////////////////

    return true;
}

void HelloWorld::menuCloseCallback(CCObject* pSender)
{

    ////////////////////////////////////////////////////////////////////////////
    CCMenu* menu = (CCMenu*)(((CCNode*)(pSender))->getParent());
    HelloWorld* scene = (HelloWorld*)menu->getParent();
    int exception_here = scene->heroes->count();
    ////////////////////////////////////////////////////////////////////////////

    CCDirector::sharedDirector()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}
// a selector callback
    /*virtual*/ void menuCloseCallback(CCObject* pSender);  // callback function don't need to be a virtual function

void HelloWorld::AddSprite(CCArray* aArray, CCSprite* aSprite)
{
    CCSprite* pSprite = new CCSprite;
    pSprite->init(); // you should invoke init method of CCSprite.
    pSprite = aSprite;
    aArray->addObject(pSprite);
}

Hi James, I’ve made changes, that you’ve suggested, but the error still remains, at the same place.

hi Eugene, did you find any solution for this?

Hi J B, no, I have no solution for this.