cocos2d-x高仿捕鱼达人实例分析(五)

来源:互联网 发布:sql contains 用法 编辑:程序博客网 时间:2024/05/18 02:19
 
资源:http://download.csdn.net/detail/hezeping888/5734051

在游戏中数值显示是一个常用部件,本节将实现对积分的累加,在积分榜上滚动显示。

将积分榜进行分解:将数字分解为一个的位,个位 ,十位等,  每个位的对象都只需要管理自己这个位上的数字滚动显示,然后有一个对每个位进行管理的调度对象,将这些位相互之间的数学关系维护起来。

数字位对象:RollNum
管理数字位对象:RollNumGroup

先讲解上述两个对象的实现,让后再将它们怎样融入到主游戏界面GameLayer的。

下面是RollNum及RollNumGroup的头文件
#ifndef __FishingJoyStep1__RollNum__
#define __FishingJoyStep1__RollNum__

#include "cocos2d.h"

class GameLayer;

/**
 数字的每个位,主要控制这个位上得数字的滚动
 */
class RollNum : public cocos2d::CCSprite
{
public:
    RollNum();
    virtual ~RollNum();
    CREATE_FUNC(RollNum);
    
    //设置要滚动到得数字,以及滚动的方向
    void setNumber(int var, bool bUp);
    int getNumber();
private:
    bool init();
    CC_SYNTHESIZE(bool, m_bUp, UpDirection);
    int m_nNumber; //当前显示的数字
    int m_nCurTexH;//当前显示数字纹理的位置
    int m_nEndTexH;//数字纹理的高度
    bool m_bRolling;//标记当前这个数字是否在滚动
    cocos2d::CCTexture2D *m_pTexture;//数字纹理
    //不断更新数字纹理显示的位置,达到滚动数字的效果
    void updateNumber(cocos2d::CCTime dt);
};

/**
 管理数字的每个位,包括控制每个位的位置,及解析数字的每个位,调度RollNum进行显示
 */
class RollNumGroup : public cocos2d::CCObject
{
public:
    RollNumGroup();
    virtual ~RollNumGroup();
    //nDigit 指定积分榜是几位数
    static RollNumGroup *createWithGameLayer(GameLayer *pGameLayer, int nDigit);
    //设置显示的数字,内部会将数字分解成单个数,然后逐个调用对应的setNumber方法
    void setValue(int nValue);
    //初始化各个数字的位置,参数指定最右边的那个数字的位子
    void setPosition(cocos2d::CCPoint pt);
private:
    CC_SYNTHESIZE(cocos2d::CCSpriteBatchNode *, m_pBatchNode, BatchNode);
    CC_SYNTHESIZE(GameLayer *, m_pGameLayer, GameLayer);
    //存储数字的每个位
    CC_SYNTHESIZE_RETAIN(cocos2d::CCArray *, m_pRollNumArray, RollNumArray);
    cocos2d::CCPoint m_ptPosition;
    int m_nDigit;//展示数字的位数
    int m_nValue;//被展示的数字
    bool initWithGameLayer(GameLayer *pGameLayer, int nDigit);
};
#endif /* defined(__FishingJoyStep1__RollNum__) */


//////////////////////////////////////////////////////////////////////
////RollNum.cpp的实现代码如下
//////////////////////////////////////////////////////////////////////

#include "RollNum.h"
#include "cocos2d.h"
#include "GameLayer.h"

using namespace cocos2d;

#define NUMBERHEIGHT    16
#define NUMBERWIDTH     12
#define TEXTUREHEIGHT   196

RollNum::RollNum():m_nNumber(0), m_bUp(true), m_nCurTexH(0), m_nEndTexH(0), m_bRolling(false), m_pTexture(NULL){}

RollNum::~RollNum()
{
    this->unscheduleAllSelectors();
}

bool RollNum::init()
{
    m_pTexture = CCTextureCache::sharedTextureCache()->textureForKey("number.png");
    //初始默认截取数字0的位置进行显示
    CCSpriteFrame *pFrame = CCSpriteFrame::createWithTexture(m_pTexture, CCRectMake(0, 0, NUMBERWIDTH, NUMBERHEIGHT));
    this->initWithSpriteFrame(pFrame);
    this->setScale(1.0f);
    return true;
}

//不断更新数字纹理显示的位置,达到滚动数字的效果
void RollNum::updateNumber(cocos2d::CCTime dt)
{
    if(m_bRolling && m_nCurTexH == m_nEndTexH)
    {
        //标记为数字滚动中,且滚动数字纹理到指定位置m_nEndTexH,注销updateNumber,停止滚动
        this->unschedule(schedule_selector(RollNum::updateNumber));
        m_bRolling = false;
        return;
    }

    //每次向上或向下滚动4px,在数字纹理中,每两两数字的上下间隔为4px,数字本身高度为16px
    if(m_bUp)
    {
        m_nCurTexH += 4;
        if(m_nCurTexH >= TEXTUREHEIGHT)
            //数字往增大方向滚动到纹理末尾,就从头开始,形成循环
            m_nCurTexH = 0;
    }
    else
    {
        m_nCurTexH -= 4;
        if(m_nCurTexH < 0)
            //数字往减小方向滚动到纹理末尾,就从尾部开始,形成循环
            m_nCurTexH = TEXTUREHEIGHT;
    }
    int h = m_nCurTexH;
    if(m_nCurTexH >= 180)
        //如果进入最后一个数字的高度范围,则从最后一个数字的位置开始
        h = 180;
    //截取指定范围的数字纹理
    CCSpriteFrame *pFrame = CCSpriteFrame::createWithTexture(m_pTexture, CCRectMake(0, h, NUMBERWIDTH, NUMBERHEIGHT));
    //更新自己负责的位的展现的数字纹理
    this->setDisplayFrame(pFrame);   
    m_bRolling = true;
}

void RollNum::setNumber(int var, bool bUp)
{    
    m_nNumber = var;
    m_bUp = bUp;
    //计算当前位的数字纹理滚动到位置
    m_nEndTexH = m_nNumber * (NUMBERHEIGHT + 4);
    //周期更新数字纹理的位置,形成滚动效果
    this->schedule(schedule_selector(RollNum::updateNumber), 0.01f);
   
}

int RollNum::getNumber()
{
    return m_nNumber;
}

////////////////////////////////////////////////////////////////////////////////////////////////
////RollNumGroup.cpp 实现如下
////////////////////////////////////////////////////////////////////////////////////////////////
RollNumGroup *RollNumGroup::createWithGameLayer(GameLayer *pGameLayer, int nDigit)
{
    RollNumGroup *pRollNumGroup = new RollNumGroup();
    if(pRollNumGroup && pRollNumGroup->initWithGameLayer(pGameLayer, nDigit))
    {
        //将自己设置为内存自动管理的对象
        pRollNumGroup->autorelease();
        return pRollNumGroup;
    }
    else
    {
        CC_SAFE_DELETE(pRollNumGroup);
        return NULL;
    }
}

RollNumGroup::RollNumGroup():m_pRollNumArray(NULL), m_nValue(0){}

RollNumGroup::~RollNumGroup()
{
    CC_SAFE_RELEASE(m_pRollNumArray);
}

bool RollNumGroup::initWithGameLayer(GameLayer *pGameLayer, int nDigit)
{
    m_pGameLayer = pGameLayer;
    //装载数字纹理
    CCTexture2D *pTex = CCTextureCache::sharedTextureCache()->addImage("number.png");
    m_pBatchNode = CCSpriteBatchNode::createWithTexture(pTex);
    //将积分榜添加到主游戏界面上
    m_pGameLayer->addChild(m_pBatchNode, 100);
    this->setRollNumArray(CCArray::createWithCapacity(nDigit));
    for(int i = 0; i < nDigit; i++)
    {
        //创建积分榜中的每一个数字位
        RollNum *pRollNum = RollNum::create();
        m_pRollNumArray->addObject(pRollNum);
        //将数字位显示到主游戏界面上
        m_pBatchNode->addChild(pRollNum);
    }
    return true;
}

void RollNumGroup::setPosition(cocos2d::CCPoint pt)
{
    m_ptPosition = pt;//积分榜的个位的位置坐标
    for(int i = 0; i < m_pRollNumArray->count(); ++i)
    {
        RollNum *pRollNum = (RollNum *)m_pRollNumArray->objectAtIndex(i);
        pRollNum->setPosition(pt);
        //每个位的 坐标从右往左移动,间隔20.7px
        pt.x -= 20.7f;
    }
}

void RollNumGroup::setValue(int nValue)
{
    //设置的数字与显示的一直时,直接返回
    if(m_nValue == nValue)
        return;
    //设置积分榜中得数字滚动的方向
    bool bUp = m_nValue < nValue;
    m_nValue = nValue;
    //解析每个位上的数,循环调度对应位上的数的滚动显示
    for(int i = 0; i < m_pRollNumArray->count(); ++i)
    {
        RollNum *pRollNum = (RollNum *)m_pRollNumArray->objectAtIndex(i);
        int num = nValue % 10;//取得与显示的积分榜中的末位上的数
        //将m_pRollNumArray 中的第一个RollNum定义为个位,第二位为十位,依次类推
        if(pRollNum->getNumber() != num)
            //调度相应位上数字滚动
            pRollNum->setNumber(num, bUp);
        //去掉预显示的积分数的末位,进入下一位数字显示调度
        nValue = nValue / 10;
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////
下面来看看主游戏界面是怎么使用它们的。
在GameLayer.h 中添加 RollNum.h的头文件
添加定义:
public:
    CC_SYNTHESIZE_RETAIN(RollNumGroup *, m_pRollNumGroup, RollNumGroup);//定义积分榜

在GameLayer.cpp中进行初始,调用,和释放
在 GameLayer::~GameLayer()方法中添加释放代码:
    CC_SAFE_RELEASE(m_pRollNumGroup);

在void GameLayer::initBackground()添加初始化代码:
    this->setRollNumGroup(RollNumGroup::createWithGameLayer(this, 6));
    m_pRollNumGroup->setPosition(ccp(353, 21));

在 void GameLayer::updateGame(cocos2d::CCTime dt)中,将上一节两句代码注释放开:
                m_nScore += 125;//此处简单处理,让每一种鱼的积分都是125分
                //更新积分榜
                m_pRollNumGroup->setValue(m_nScore);

OK,到现在积分榜就可以正常使用了。赶紧运行起来感受一下自己的捕鱼达人吧。