cocos2dx_texture_cache

  1. 如何移除不需要的纹理?

    cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();

    假设我们把这句话叫做XXX。

  1. 何时需要移除不需要的纹理?

    切换场景的时候(假设是A场景切换到B场景,那就是A场景的析构函数,或者B场景的构造函数)。

    这两个地方我都写了XXX,结果不生效。

    SceneA::~SceneA()
    {
        cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();
    }
    SceneB::SceneB()
    {
        cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();
    }
  2. 为啥不生效呢?

    不知道。

    我们可以用 cocos2d::Director::getInstance()->getTextureCache()->getCachedTextureInfo() 来打印纹理缓存信息。

    我打印过后发现,我想要移除的纹理的引用计数是等于1的,可没有移除成功。

  3. 怎么解决呢?

    我测试过后发现,如果在切换场景前,把A场景里把对应的节点移除掉,再去调用XXX。就可以了。

    bool SceneA::init()
    {
        if (!cocos2d::Scene::init())
        {
            return false;
        }
    
        cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();
    
        auto vorigin = cocos2d::Director::getInstance()->getVisibleOrigin();
        auto vsize = cocos2d::Director::getInstance()->getVisibleSize();
    
        auto sprite = cocos2d::Sprite::create("HelloWorld.png");
        sprite->setPosition(cocos2d::Vec2(vsize.width / 2 + vorigin.x, vsize.height / 2 + vorigin.y));
        this->addChild(sprite, 0, "spr");
    
        auto replace_scene_item = cocos2d::MenuItemImage::create("res/a_1.png", "res/a_1.png", CC_CALLBACK_1(SceneA::OnClickReplaceScene, this));
        replace_scene_item->setPosition(cocos2d::Vec2(vorigin.x + vsize.width - replace_scene_item->getContentSize().width / 2, vorigin.y + replace_scene_item->getContentSize().height / 2));
        auto menu_node = cocos2d::Menu::create(replace_scene_item, nullptr);
        menu_node->setPosition(cocos2d::Vec2::ZERO);
        this->addChild(menu_node, 1, "menu");
    
        auto s = cocos2d::Director::getInstance()->getTextureCache()->getCachedTextureInfo();
        cocos2d::log("Scene A:\n%s", s.c_str());
    
        return true;
    }
    
    void SceneA::OnClickReplaceScene(cocos2d::Ref * sender)
    {
        this->removeChildByName("spr", true);
        dynamic_cast<cocos2d::MenuItemImage*>(sender)->removeFromParentAndCleanup(true);//this->removeChildByName("menu", true);这样写不行,我也不知道为啥
        cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();
        auto scene = SceneB::create();
        cocos2d::Director::getInstance()->replaceScene(scene);
    }

完整代码

#ifndef __SCENE_A_H__
#define __SCENE_A_H__

#include "cocos2d.h"

class SceneA : public cocos2d::Scene
{
public:
    static SceneA * create();
private:
    virtual ~SceneA();
    bool init();
    void OnClickReplaceScene(cocos2d::Ref * sender);
};

#endif
#include "SceneA.h"
#include "SceneB.h"

SceneA::~SceneA()
{
    //cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();
}

SceneA * SceneA::create()
{
    auto p = new (std::nothrow) SceneA();
    if (p && p->init())
    {
        p->autorelease();
        return p;
    }
    delete p;
    p = nullptr;
    return nullptr;
}

bool SceneA::init()
{
    if (!cocos2d::Scene::init())
    {
        return false;
    }

    cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();

    auto vorigin = cocos2d::Director::getInstance()->getVisibleOrigin();
    auto vsize = cocos2d::Director::getInstance()->getVisibleSize();

    auto sprite = cocos2d::Sprite::create("HelloWorld.png");
    sprite->setPosition(cocos2d::Vec2(vsize.width / 2 + vorigin.x, vsize.height / 2 + vorigin.y));
    this->addChild(sprite, 0, "spr");

    auto replace_scene_item = cocos2d::MenuItemImage::create("res/a_1.png", "res/a_2.png", CC_CALLBACK_1(SceneA::OnClickReplaceScene, this));
    replace_scene_item->setPosition(cocos2d::Vec2(vorigin.x + vsize.width - replace_scene_item->getContentSize().width / 2, vorigin.y + replace_scene_item->getContentSize().height / 2));
    auto menu_node = cocos2d::Menu::create(replace_scene_item, nullptr);
    menu_node->setPosition(cocos2d::Vec2::ZERO);
    this->addChild(menu_node, 1, "menu");

    auto s = cocos2d::Director::getInstance()->getTextureCache()->getCachedTextureInfo();
    cocos2d::log("Scene A:\n%s", s.c_str());

    return true;
}

void SceneA::OnClickReplaceScene(cocos2d::Ref * sender)
{
    this->removeChildByName("spr", true);
    dynamic_cast<cocos2d::MenuItemImage*>(sender)->removeFromParentAndCleanup(true);//this->removeChildByName("menu", true);这样写不行,我也不知道为啥
    cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();
    auto scene = SceneB::create();
    cocos2d::Director::getInstance()->replaceScene(scene);
}
#ifndef __SCENE_B_H__
#define __SCENE_B_H__

#include "cocos2d.h"

class SceneB : public cocos2d::Scene
{
public:
    static SceneB * create();
private:
    SceneB();
    virtual bool init();
    void menuCloseCallback(cocos2d::Ref* pSender);
};

#endif
#include "SceneB.h"
#include "SceneA.h"

SceneB::SceneB()
{
    //cocos2d::Director::getInstance()->getTextureCache()->removeUnusedTextures();
}

SceneB * SceneB::create()
{
    auto p = new (std::nothrow) SceneB();
    if (p && p->init())
    {
        p->autorelease();
        return p;
    }
    delete p;
    p = nullptr;
    return nullptr;
}

bool SceneB::init()
{
    if ( !cocos2d::Scene::init() )
    {
        return false;
    }

    auto visibleSize = cocos2d::Director::getInstance()->getVisibleSize();
    auto origin = cocos2d::Director::getInstance()->getVisibleOrigin();

    auto closeItem = cocos2d::MenuItemImage::create("CloseNormal.png", "CloseSelected.png", CC_CALLBACK_1(SceneB::menuCloseCallback, this));
    closeItem->setPosition(cocos2d::Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width / 2, origin.y + closeItem->getContentSize().height / 2));

    auto menu = cocos2d::Menu::create(closeItem, NULL);
    menu->setPosition(cocos2d::Vec2::ZERO);
    this->addChild(menu, 1);

    return true;
}

void SceneB::menuCloseCallback(cocos2d::Ref* pSender)
{
    auto s = cocos2d::Director::getInstance()->getTextureCache()->getCachedTextureInfo();
    cocos2d::log("Scene B:\n%s", s.c_str());
}

输出结果

Scene A:
"G:/ZZZ/ccTestTexturecache/proj.win32/Debug.win32/Resources/HelloWorld.png" rc=2 id=1 195 x 270 @ 32 bpp => 205 KB
"G:/ZZZ/ccTestTexturecache/proj.win32/Debug.win32/Resources/res/a_1.png" rc=2 id=2 60 x 60 @ 32 bpp => 14 KB
"G:/ZZZ/ccTestTexturecache/proj.win32/Debug.win32/Resources/res/a_2.png" rc=2 id=3 60 x 60 @ 32 bpp => 14 KB
TextureCache dumpDebugInfo: 3 textures, for 233 KB (0.23 MB)

cocos2d: QuadCommand: resizing index size from [-1] to [2560]
cocos2d: TextureCache: removing unused texture: G:/ZZZ/ccTestTexturecache/proj.win32/Debug.win32/Resources/HelloWorld.png
cocos2d: TextureCache: removing unused texture: G:/ZZZ/ccTestTexturecache/proj.win32/Debug.win32/Resources/res/a_1.png
cocos2d: TextureCache: removing unused texture: G:/ZZZ/ccTestTexturecache/proj.win32/Debug.win32/Resources/res/a_2.png
Scene B:
"/cc_fps_images" rc=4 id=4 999 x 54 @ 16 bpp => 105 KB
"G:/ZZZ/ccTestTexturecache/proj.win32/Debug.win32/Resources/CloseNormal.png" rc=2 id=1 40 x 40 @ 32 bpp => 6 KB
"G:/ZZZ/ccTestTexturecache/proj.win32/Debug.win32/Resources/CloseSelected.png" rc=2 id=2 40 x 40 @ 32 bpp => 6 KB
TextureCache dumpDebugInfo: 3 textures, for 117 KB (0.12 MB)