Header image

Cocos2Dx – faster fonts

May 30th, 2013 | Posted by lars in Cocos2D | OpenGL | Source | Talk

For my current client, I’m working on a game that needs to display a lot of text in many cases. As a rendering engine we’re using Cocos2D. If you are familar with Cocos2D and you have worked with bitmap fonts (CCLabelBMFont) in your game you’ll notice that, they really can slow down everything, because every single text is rendered as a separate batch and you quickly end up with a lot of draw calls. After a quick research, I couldn’t find an extension or sample code which adresses this problem by batching all fonts into one single batch. So I quickly wrote my own font batch and hooray, the game runs a lot faster now. It’s more or less a “quick” hack and it could be extended by a few missing font features (text alignment, etc.), but for my case it does the job. Have fun with it:

LabelBMFontBatch.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#import "cocos2d.h"
 
using namespace cocos2d;
 
class LabelBMFontBatch : public cocos2d::CCSpriteBatchNode
{
 
private:
    const char *_fntFile;
    int _lastChildTag;
 
public:
 
    LabelBMFontBatch(const char *fntFile);
    ~LabelBMFontBatch();
 
    static LabelBMFontBatch *create(const char *fileImage, const char *fntFile, unsigned int capacity);
 
    /* returns a text id. used to identify the text in the batch. use the id with removeTextByID  */
    int addTextAt(const char *text, CCPoint position, float scale);
    void removeTextByID(int textID);
    void removeAllTexts();
};

LabelBMFontBatch.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include "LabelBMFontBatch.h"
 
LabelBMFontBatch::LabelBMFontBatch(const char *fntFile) : CCSpriteBatchNode() {
    _fntFile = fntFile;
    _lastChildTag = 0;
}
 
LabelBMFontBatch::~LabelBMFontBatch() {
    _fntFile = NULL;
    this->removeAllChildren();
}
 
LabelBMFontBatch *LabelBMFontBatch::create(const char *fileImage, const char *fntFile, unsigned int capacity) {
 
    LabelBMFontBatch *batchNode = new LabelBMFontBatch(fntFile);
    batchNode->initWithFile(fileImage, capacity);
    batchNode->autorelease();
 
    return batchNode;
}
 
int LabelBMFontBatch::addTextAt(const char *text, CCPoint position, float scale) {
 
    _lastChildTag += 100;
 
    CCLabelBMFont *bmpFont = CCLabelBMFont::create(text, _fntFile);
    CCSize textWidth = bmpFont->getContentSize();
 
    // center text ...
    position.x -= textWidth.width * 0.5f * scale;
 
    for(int i = 0; i < bmpFont->getChildrenCount(); i++)
    {
        CCObject *child = bmpFont->getChildren()->objectAtIndex(i);
        CCSprite *pNode = (CCSprite*)child;
        CCPoint pNodePosition = pNode->getPosition();
 
        pNode->retain();
 
        bmpFont->removeChild(pNode, false);
        this->addChild(pNode);
 
        pNode->setScale(scale);
        pNode->setPosition(ccp(position.x + pNodePosition.x * scale, position.y + pNodePosition.y * scale));
        pNode->setTag(_lastChildTag);
        pNode->release();
 
        --i;
    }
 
    return _lastChildTag;
}
 
void LabelBMFontBatch::removeTextByID(int textID)
{
    CCNode *child = this->getChildByTag(textID);
 
    while(child != NULL)
    {
        this->removeChild(child, true);
        child = this->getChildByTag(textID);
    }
}
 
void LabelBMFontBatch::removeAllTexts() {
    this->removeAllChildrenWithCleanup(true);
}

You can follow any responses to this entry through the RSS 2.0 You can leave a response, or trackback.

4 Responses



Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">