cocos3.2自定义字体标签不支持SpriteFrame创建,也没有环形的,有时候因为要加入数字标签到比较尴尬的层中导致GL Calls暴涨,汗颜,看着都怕。这个类主要是解决这两个问题,能实现的效果:
1.支持直线和环形数字的切换2.支持从SpriteFrame中创建
//效果参考
//code/
说明:把代码中的#if (IsRecord==1)代码去掉就行,这些只是我用来测试用的
.h
#pragma once
#include "cocos2d.h"
using namespace cocos2d;
class LableNumExt : public Node
{
public:
~LableNumExt(void);
//创建数字radius!=0.0f的话就是创建这个半径的1/4个圆的环形数字,数字在这个环的中心位置
static LableNumExt* createWithSpriteFrame(SpriteFrame* spriteFrame,string strNum,float radius=0.0f);
string getString(){return _nowNumShow;}
void setString(string num);
void setRadius(float radius);
float getRadius(){return _radius;}
private:
LableNumExt(void);
string _strNum; //这个图片代表的数字是什么
string _nowNumShow; //当前显示的数字
int with; //一个数字的宽度
int height; //一个数字的高度
int startX; //图片开始的位置(左上角)
int startY;
int maxCount; //当前最大能显示的位数
float _radius;
bool _isChangeRadius; //是否改变了半径
SpriteFrame*_spriteFrame; //用来生成精灵的SpriteFrame
//显示哪个数字的
Sprite* creatSprite(char showChar); //创建一个精灵
void checkEnough();
//设置精灵新的显示区域显示str
void setTextTrueRect(Sprite* sp,char str);
};
///
.cpp
#include "LableNumExt.h"
#include "HGE.h"
LableNumExt::LableNumExt(void)
{
_strNum=" ";
_nowNumShow=" ";
maxCount=0;
_radius=0.0f;
_isChangeRadius=false;
_spriteFrame=nullptr;
}
LableNumExt::~LableNumExt(void)
{
}
LableNumExt* LableNumExt::createWithSpriteFrame(SpriteFrame* spriteFrame,string strNum,float radius/* =0.0f */)
{
LableNumExt* LB=new LableNumExt();
LB->_strNum=strNum;
LB->_radius=radius;
LB->_spriteFrame=spriteFrame;
//计算大小
LB->with=spriteFrame->getOriginalSize().width/strNum.size();
LB->height=spriteFrame->getOriginalSize().height;
LB->startX=spriteFrame->getRect().origin.x;
LB->startY=spriteFrame->getRect().origin.y;
for(int i=0;i<strNum.size();i++)
{
//创建你的默认是显示第一个数字的
LB->creatSprite(strNum[i]);
}
//设置初始值
LB->setString(strNum);
LB->setAnchorPoint(Vec2(0.5f,0.5f));
LB->autorelease(); //自动释放资源
return LB;
}
Sprite* LableNumExt::creatSprite(char showChar)
{
Texture2D* textureDog=_spriteFrame->getTexture();
//auto sp=Sprite::createWithTexture(textureDog,,_spriteFrame->isRotated());
auto sp=Sprite::createWithSpriteFrame(_spriteFrame);
//设置精灵的纹理
setTextTrueRect(sp,showChar);
sp->setAnchorPoint(Vec2(0.5f,0.5f)); //设置中点为锚点
sp->setTag(maxCount);
sp->setVisible(false);
this->addChild(sp);//加入父亲节点
this->maxCount++;
return sp;
}
void LableNumExt::setTextTrueRect(Sprite* sp,char str)
{
int index=_strNum.find(str);
if(index==-1)
{
#if (IsRecord==1)
WRITEERROR("setTextTrueRect中没有发现这个值");
#endif
index=0;
}
if(_spriteFrame->isRotated())
{
sp->setTextureRect(Rect(
startX,
index*with+startY,
height,
with
)
);
}
else
{
sp->setTextureRect(Rect(
index*with+startX,
startY,
with,
height
)
);
}
sp->setName(HGE::getInstance()->CharToString(str));//约定这个精灵显示的数字做为名字
sp->setVisible(true);
}
void LableNumExt::setString(string num)
{
HGE::getInstance()->trim(num);
if(num=="")
{
num="0";
}
if(_nowNumShow==num && !_isChangeRadius)
{
//相同的,直接返回,不用处理
return ;
}
//先隐藏旧的数字
for(int i=0;i<_nowNumShow.size();i++)
{
Node* nodeChild=this->getChildByTag(i);
nodeChild->setVisible(false);
}
//判断是否需要重新设置位置
bool isNeedToSetPS=false;
if(_isChangeRadius)
{
//如果半径改变了,一定需要重新设置位置
isNeedToSetPS=true;
}
else
{
//如果半径没有改变
if(_radius==0.0f)
{
//直线的
if(num.size()>_nowNumShow.size())
{
//如果要显示的位数比之前还要大的话,需要重新设置位数
isNeedToSetPS=true;
}
}
else
{
//环形的
if(num.size()!=_nowNumShow.size())
{
//如果位数和上次的不一样的话,需要重新设置位置
isNeedToSetPS=true;
}
}
}
//设置新的值
_nowNumShow=num;
//检查当前位数是否够显示
checkEnough();
//设置新的大小
if(_radius==0.0f)
{
this->setContentSize(Size(_nowNumShow.size()*with,height));
}
else
{
//环形的(大小就是比半径还大一点点的正方形)
this->setContentSize(Size(_radius+height*0.5f,_radius+height*0.5f));
}
//更新数字
float angle=0.0f;
float startAngle=0.0f;
if(_radius!=0.0f)
{
angle=asin(with/2.0f/(_radius-height/2.0f))/M_PI*180.0f * 2.0f;
startAngle=(90.0f-_nowNumShow.size()*angle)/2.0f+angle*0.5f;
}
for(int i=0;i<_nowNumShow.size();i++)
{
//如果是相同的数字,就不更新了
Sprite* nodeChild=(Sprite*)this->getChildByTag(i);
string name=nodeChild->getName();
if(name=="" || name[0]!=_nowNumShow[i])
{
setTextTrueRect(nodeChild,_nowNumShow[i]);
}
//是否要设置位置
if(isNeedToSetPS)
{
float rotation=0.0f;
Vec2 v2;
if(_radius==0.0f)
{
//直线的
rotation=0.0f;
v2=Vec2((i+0.5f)*with,height*0.5f);
}
else
{
//环形的
rotation=startAngle+angle*i;
v2=HGE::getInstance()->GetOtherVec2ByDistanceAndRotation(Vec2(0,0),_radius,rotation);
}
if(_spriteFrame->isRotated())
{
rotation-=90.0f;
if(rotation<0)
rotation+=360.0f;
}
nodeChild->setRotation(rotation);
nodeChild->setPosition(v2);
}
nodeChild->setVisible(true);
}
}
void LableNumExt::checkEnough()
{
int needCount=_nowNumShow.size();
if(needCount<=maxCount)
{
return;
}
//不够的话,就生成
needCount-=maxCount;
for(int i=0;i<needCount;i++)
{
int index=_strNum.find(_nowNumShow[maxCount]);
if(index==-1)
{
#if (IsRecord==1)
WRITEERROR("checkEnough中没有发现这个值");
#endif
index=0;
}
creatSprite(_strNum[index]);
}
}
void LableNumExt::setRadius(float radius)
{
if(_radius==radius)
{
//如果当前设置的角度没有改变的话
return;
}
//设置新的半径
_isChangeRadius=true;
this->_radius=radius;
//如果改变了半径,就要刷新数字的位置
this->setString(_nowNumShow);
_isChangeRadius=false;
}
//
hge.h
string HGE::CharToString(char ch)
{
std::stringstream newstr;
string tmp="";
newstr<<ch;
newstr>>tmp;
newstr.clear();
newstr.str("");
return tmp;
}
string& HGE::trim(string &s)
{
if (s.empty())
{
return s;
}
s.erase(0,s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ") + 1);
return s;
}
Vec2 HGE::GetOtherVec2ByDistanceAndRotation(Vec2 v2,float distance,float rotation)
{
Vec2 re;
float x=v2.x + sin(rotation/180.0f*M_PI) * distance;
float y=v2.y + cos(rotation/180.0f*M_PI) * distance;
re.x=x;
re.y=y;
return re;
}