由于显示得分其实是数字精灵的组合,因此需要先设计一个存储数字精灵数列的类:
#ifndef __EngryBird__NumberSeries__
#define __EngryBird__NumberSeries__
#include "cocos2d.h"
/**
* This class is for ScoreNumber, and it will store a list of sprite frames.
* With it, you can load number sprite with name format and get sprite frame
* with index.
*/
class NumberSeries : public cocos2d::Ref {
public:
/**
* The default constructor
*/
NumberSeries();
/**
* The default destructor
*/
~NumberSeries();
/**
* The init method, will init the super init method first
*
* @return true if succeeded, otherwise false
*/
virtual bool init();
CREATE_FUNC(NumberSeries);
/**
* Load sprite frame with a format name
*
* @param format The name format, eg. "number1_%d"
* @param base The begin index
*/
void loadNumber(const char *foramt, int base = 0);
/**
* Get sprite frame with an index
*
* @param index The index in the _numberVector
*
* @return a sprite frame object
*/
cocos2d::SpriteFrame* at(int index);
private:
/**
* Store number sprite frames
*/
cocos2d::Vector<cocos2d::SpriteFrame *> _numberVector;
};
#endif /* defined(__EngryBird__NumberSeries__) */
这个类只有一个成员变量,_numberVector,存储的是一组数字精灵帧,这样就可以通过数字作为下标,直接获取对应的精灵帧。
在初始化时:
bool NumberSeries::init() {
_numberVector = cocos2d::Vector<SpriteFrame *>(kMaxNumberCount);
return true;
}
因此数字就是0~9这几个,所以是固定的,写成一个宏常量
下面这个方法是获取得分组合精灵,如得分为42,则把对应的精灵帧4和2加入到组合中,
void NumberSeries::loadNumber(const char *foramt, int base) {
for (int i = base; i < kMaxNumberCount + base; ++i) {
char name[20];
sprintf(name, foramt, i);
auto frame = AtlasLoader::getInstance()->getSpriteFrame(name);
_numberVector.pushBack(frame);
}
}
base表示从什么数字开始,这样写是因为有的精灵的名称不是从0开始的,如bird_045~bird_088,那么base就是45了
获取数字精灵帧的时候,传数字过来,就是获取对应的数字精灵帧了,
SpriteFrame* NumberSeries::at(int index) {
if (index >= 0 && index < _numberVector.size()) {
return _numberVector.at(index);
}
return NULL;
}
考虑代码的健壮性,增加了范围的判断
下面是数字特效类了,设计为全局共享类,
首先,显示的方式为居中,居左,居右,因此先设计一个枚举来表示。
/**
* The alignment
*/
typedef enum {
kGravityDirectionCenter = 1,
kGravityDirectionLeft,
kGravityDirectionRight
} GravityDirection;
看看加载得分精灵方法:
bool ScoreNumber::loadNumber(const char *name, const char *format, int base) {
auto series = NumberSeries::create();
series->loadNumber(format, base);
_numberContainer.insert(name, series);
return true;
}
这里_numberContainer是一个Map类型的容器,用于存储得分,因为游戏不断重复的话,同样的得分,就可以直接获取,而不用重复了。
下面这个方法是把数字得分转换成精灵数字,并调整方向:
Node* ScoreNumber::convert(const char *name, int number, GravityDirection direction) {
// 首先根据key,取得数字组合
auto series = _numberContainer.at(name);
auto zero = Sprite::createWithSpriteFrame(series->at(0));
// 如果得分为0,直接显示
if (number == 0) {
zero->setAnchorPoint(Vec2(0.5, 0));
return zero;
}
// seperate the number and load number sprite into the node
// 使用node节点来容纳数字精灵
auto node = Node::create();
float totalWidth = 0.0f;
while (number) {
// 循环获取每一位数字,然后获取对应的精灵,添加到node中并计算
// node的总宽
int tmp = number % 10;
auto sprite = Sprite::createWithSpriteFrame(series->at(tmp));
totalWidth += sprite->getContentSize().width;
node->addChild(sprite);
number /= 10;
}
// set the content size of node
node->setContentSize(Size(totalWidth, zero->getContentSize().height));
// caculate the width of each number
float perWidth = totalWidth / node->getChildrenCount();
ssize_t index = 0;
float anchorX = 0;
bool isMinus = true;
if (direction == kGravityDirectionCenter) {
anchorX = 0.5f;
index = node->getChildrenCount() / 2;
} else if (direction == kGravityDirectionRight) {
anchorX = 1.0f;
index = node->getChildrenCount();
} else if (direction == kGravityDirectionLeft) {
anchorX = 0.0f;
isMinus = false;
index = 0;
}
// 获取显示的方式来调整精灵的位置
for (auto child : node->getChildren()) {
child->setAnchorPoint(Vec2(anchorX, 0));
float posX = perWidth * (isMinus ? index-- : index++);
child->setPositionX(posX);
}
return node;
}
下一步,先说明一下用到的宏