Cocos2d-x学习(九):cocos2d-x 无限背景滚动

最近在学习飞行射击类游戏的一些开发,学到的东西确实不少,比如,无限背景滚动,子弹的缓冲池,面向组件开发等等!

今天就来总结一下无限背景滚动的实现!

飞行类的游戏都是基于背景的滚动,造成视觉上的假象,认为飞机在飞行,而不是“真正的向前飞”。。。


1.原理

滚动的原理:设定一个速度,在每次调用update(ccTime dt) 时,就根据速度和dt得到移动的偏移量,因为更新频率很快,所以偏移量很小,所以在视觉上认为是连贯的!就形成了滚动效果。

无限滚动的原理:有两个背景,每次调用update(ccTime dt) 时,判断当前这两个背景,如果在屏幕之外了,说明它不在起到显示作用,于是将它放到后面去,其实就像是两条腿走路,一前一后,循环,就向前运动起来了,也就是说只需要两个背景,一张贴在一张后面!(我采用的算法比较懒,就是会对两个背景分别判断位置,而不是记录哪个背景在前,哪个背景在后)!


2.代码实现

这里用了两个景层,一个近景,一个远景,这样看起来效果更逼真!(资源来源于cocos2d-x-html版的飞行demo

远景用了一个图片精灵,近景用了一个tmx地图

定义了一个背景标签,用来标记是近景还是远景,如果只有一层就可以忽略

// 背景标签
enum TAG_BG
{
    TAG_BG_NEAR_LAYER = 0,
    TAG_BG_FAR_LAYER = 1
};
近景和远景精灵,以及其运行速度和景层的高度,(速度用来滚动,高度用来判断更新景层的位置)

private:
    // 背景(远景层)
    CCSprite *m_pSkySprite;
    CCSprite *m_pSkySpriteRe;
    float m_fSkyVelocity;
    float m_fSkyHeight;
    
    // 地图(近景层)
    CCTMXTiledMap *m_pTileMap;
    CCTMXTiledMap *m_pTileMapRe;
    float m_fTileMapVelocity;
    float m_fTileMapHeight;
初始化,每个景层由两个相同地图精灵组成,依次排开,向下运动

void GameBGLayer::initBackground()
{
    // Sky
    m_pSkySprite = CCSprite::spriteWithFile("bg01.jpg");
    m_pSkySpriteRe = CCSprite::spriteWithFile("bg01.jpg");
    m_pSkySprite->setAnchorPoint(CCPointZero);
    m_pSkySpriteRe->setAnchorPoint(CCPointZero);
    this->addChild(m_pSkySprite, -10, TAG_BG_NEAR_LAYER);
    this->addChild(m_pSkySpriteRe, -10, TAG_BG_NEAR_LAYER);
    
    // Map
    m_pTileMap = CCTMXTiledMap::tiledMapWithTMXFile("level01.tmx");
    m_pTileMapRe = CCTMXTiledMap::tiledMapWithTMXFile("level01.tmx");
    m_pTileMap->setAnchorPoint(CCPointZero);
    m_pTileMapRe->setAnchorPoint(CCPointZero);    
    this->addChild(m_pTileMap, -9, TAG_BG_FAR_LAYER);
    this->addChild(m_pTileMapRe, -9, TAG_BG_FAR_LAYER);
    
    // 设置高度
    m_fSkyHeight = m_pSkySprite->getContentSize().height;
    m_fTileMapHeight = m_pTileMap->getMapSize().height * m_pTileMap->getTileSize().height;
    
    // 设置副本背景位置
    m_pSkySpriteRe->setPosition(ccp(0, m_fSkyHeight));
    m_pTileMapRe->setPosition(ccp(0, m_fTileMapHeight));
    
    // 设置移动速度
    m_fSkyVelocity = -16;
    m_fTileMapVelocity = -60;
//    m_fSkyVelocity = -160;
//    m_fTileMapVelocity = -600;
}
更新方法,为了统一管理,我将所有背景相关的都放在了这一层,每次遍历并更新位置和判断是否向后移动

void GameBGLayer::update(ccTime dt)
{
    CCArray *bgSprites = this->getChildren();
    CCObject *obj = NULL;
    
    CCARRAY_FOREACH(bgSprites, obj)
    {
        movingBackground(obj, dt);
    }
}
移动背景(包括滚动和向后移动)

void GameBGLayer::movingBackground(CCObject *pObj, ccTime dt)
{
    CCNode *bgNode = (CCNode*) pObj;
    int tag = bgNode->getTag();
    
    if (tag == TAG_BG_NEAR_LAYER) {
        // 远景层
        bgNode->setPositionY(bgNode->getPositionY() + m_fSkyVelocity * dt);
        if (bgNode->getPositionY() < -m_fSkyHeight) {
            bgNode->setPositionY(bgNode->getPositionY() + m_fSkyHeight * 2 - 2);
        }
    }
    else if (tag == TAG_BG_FAR_LAYER) {
        // 近景层
        bgNode->setPositionY(bgNode->getPositionY() + m_fTileMapVelocity * dt);
        if (bgNode->getPositionY() < -m_fTileMapHeight) {
            bgNode->setPositionY(bgNode->getPositionY() + m_fTileMapHeight * 2 - 2);
        }
    }
}

-2的目的是为了避免背景之间有可能因为加载产生的黑线


3.效果



不能做成动画,效果看不出来。。。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章