CCTMXTiledMap::layerNamed() crashes if any CCNode other than CCTMXLayer is added to the tiled map.

Hi All,

I’ve come across an issue in which CCTMXTiledMap::layerNamed() crashes if any CCNode other than a CCTMXLayer is added to a tiled map. The following is a proposed fix.

    CCTMXLayer * CCTMXTiledMap::layerNamed(const char *layerName)
    {
        std::string sLayerName = layerName;
        if (m_pChildren && m_pChildren->count()>0)
        {
            CCTMXLayer *layer;
            CCMutableArray::CCMutableArrayIterator it;
            for (it = m_pChildren->begin(); it != m_pChildren->end(); ++it)
            {
                /*
                 //Issue: Since any kind of CCNode* can be added into a CCTMXTiledMap, we can't safely rely on a C-Style cast.
                layer = (CCTMXLayer*)(*it);
                if (layer && layer->getLayerName() == sLayerName)
                {
                    return layer;
                }
                 */

                //Proposed Fix:
                layer = dynamic_cast (*it);
                if (layer && layer->getLayerName() == sLayerName)
                {
                    return layer;
                }
            }
        }

        // layer not found
        return NULL;
    }

It’s the bug #341 reported 2 months ago.
Thanks very much!

Glad to be of assistance. By the way cocos2d-x is an awesome engine! Kudos to you guys!

@Angelo Rohit
Not all platform support dynamic_cast().

@Angelo Rohit
I took a test just a moment ago. In the test, I add a sprite into a CCTMXTiledMap object as a child. The code like this:

CCSprite* pSprite = CCSprite::spriteWithFile("Images/close.png");
map->addChild(pSprite);
CCTMXLayer* pLayer = map->layerNamed("XXX");

But it works well, no crash occurred.

Also, I think it’s a bug of our engine. I only want to know how can I reproduce the bug.
Then I can test whether my solution is correct or not.

Thanks a lot!
By the way, my test environment is cocos2d-0.99.5-x-0.8.2.

The crash may not be occurring because the tile layer named “XXX” is actually present in the tile map.
Could you try getting the layer by specifying a name for a tile layer that is not present in the map?

@Angelo Rohit
In fact, the tile layer named “XXX” is not present in the tile map.
The location of my test code is constructor of TMXIsoVertexZ (TileMapTest.cpp, line 939).
The tile map only have two CCTMXLayer which named “Grass” and “Trees”.

Can you provide more information to reproduce the bug? (Such as a demo code.)

Hi Zhang,

I’ve built a basic Cocos2d-x iPhone project from the default template. The tiled map I’ve loaded is one of the examples that come with Tiled Map editor.
Please find attached the relevant files. Do let me know if you can reproduce the issue on your end.

Thanks for your demo code. I have reproduce the bug on my end.
And I have resolved the bug through my solution.

I’m very sorry for my careless! I haven’t noticed that the topic is in part cocos2d-iphone-cpp.
And my test is run on win32 platform. So I didn’t reproduced the bug.

Thank you once again! And you can see the issue progress by this link: #341.

Great to know that the issue has been identified. I’m curious to know what the proposed fix might be since we can’t rely on the portability of RTTI. :slight_smile:

The solution is simple.
First, I add a member parameter into the class CCTMXTiledMap (the parameter type is CCDictionary<std::string, CCTMXLayer*>).
Then record the CCTMXLayer objects when parsing the tmx files.
At last, modify the function layerNamed() like this:

std::string sLayerName = layerName;
CCTMXLayer * pRet = m_pTMXLayers->objectForKey(sLayerName);
return pRet; 

That’s all what I have done! :slight_smile:

Excellent!