最近在学习飞行射击类游戏的一些开发,学到的东西确实不少,比如,无限背景滚动,子弹的缓冲池,面向组件开发等等!
今天就来总结一下无限背景滚动的实现!
飞行类的游戏都是基于背景的滚动,造成视觉上的假象,认为飞机在飞行,而不是“真正的向前飞”。。。
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.效果
不能做成动画,效果看不出来。。。