cocos2dx通过SpriteFrame创建数字标签类

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;
}







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值