最近在學習飛行射擊類遊戲的一些開發,學到的東西確實不少,比如,無限背景滾動,子彈的緩衝池,面向組件開發等等!
今天就來總結一下無限背景滾動的實現!
飛行類的遊戲都是基於背景的滾動,造成視覺上的假象,認爲飛機在飛行,而不是“真正的向前飛”。。。
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.效果
不能做成動畫,效果看不出來。。。