本文是解析跑酷victorian(维多利亚人)的代码,使用的coco2dx引擎。
设计上:
代理控制程序的开关、设置帧率、创建和运行场景,游戏层初始化时进入游戏主循环。游戏界面渲染在游戏层上。地形是个空白图精灵,控制所有的街区块精灵。
游戏含游戏状态机(在游戏主循环),控制游戏状态。角色有角色状态机,控制角色状态。
运行图:
目录:
1、游戏代理
2、游戏层
2.1、游戏层和初始化
2.2、游戏界面
2.3、游戏控制
2.4、游戏层主循环
3、角色
3.1、角色循环
4、地形4.1、地形精灵初始化
4.2、地形精灵操作
4.3、地形控制街区块
5、街区块
5.1、街区块定义和初始化
5.2、设置街区块参数,包括屋顶和陷阱
5.3、街区块突出景象(烟囱)
5.4、街区块随机模式
6、自定义精灵
内容:
1、游戏代理
代理运行场景对象
bool AppDelegate::applicationDidFinishLaunching() { // initialize director CCDirector *pDirector = CCDirector::sharedDirector(); pDirector->setOpenGLView(CCEGLView::sharedOpenGLView()); // turn on display FPS pDirector->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this pDirector->setAnimationInterval(1.0 / 60); // create a scene. it's an autorelease object CCScene *pScene = GameLayer::scene(); // run pDirector->runWithScene(pScene); return true; }
应用进入后台时停止动画
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too void AppDelegate::applicationDidEnterBackground() { CCDirector::sharedDirector()->stopAnimation(); }
// this function will be called when the app is active again void AppDelegate::applicationWillEnterForeground() { CCDirector::sharedDirector()->startAnimation(); }
2、游戏层
2.1、游戏层和初始化
创建场景对象和层,并把层添加到场景对象
CCScene* GameLayer::scene() { CCScene * scene = NULL; do { // 'scene' is an autorelease object scene = CCScene::create(); CC_BREAK_IF(! scene); // 'layer' is an autorelease object GameLayer *layer = GameLayer::create(); CC_BREAK_IF(! layer); // add layer as a child to scene scene->addChild(layer); } while (0); // return the scene return scene; }
游戏层初始化
bool GameLayer::init() { bool bRet = false; do { ////////////////////////////////////////////////////////////////////////// // super init first ////////////////////////////////////////////////////////////////////////// CC_BREAK_IF(! CCLayer::init()); //获取屏幕大小 _screenSize = CCDirector::sharedDirector()->getWinSize(); //创建游戏界面 createGameScreen(); //重新开始游戏 resetGame(); //listen for touches this->setTouchEnabled(true); //create main loop this->schedule(schedule_selector(GameLayer::update)); bRet = true; } while (0); return bRet; }
2.2、游戏界面
创建游戏界面,加载资源到内存,设置背景和装饰精灵和角色精灵
void GameLayer::createGameScreen () { //设置游戏背景 CCSprite * bg = CCSprite::create("bg.png"); bg->setPosition(ccp(_screenSize.width * 0.5f, _screenSize.height * 0.5f)); this->addChild(bg, kBackground); //CCSpriteFrameCache(精灵帧缓存)主要用来存放CCSpriteFrame,它没有提供特别的属性,而是提供一系列用于管理CCSpriteFrame的方法 CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("sprite_sheet.plist","sprite_sheet.png"); _gameBatchNode = CCSpriteBatchNode::create("sprite_sheet.png", 200); this->addChild(_gameBatchNode, kMiddleground); CCSprite * repeat; _background = CCSprite::createWithSpriteFrameName("background.png"); _background->setAnchorPoint(ccp(0,0)); _gameBatchNode->addChild(_background, kBackground); repeat = CCSprite::createWithSpriteFrameName("background.png"); repeat->setAnchorPoint(ccp(0,0)); repeat->setPosition(ccp(repeat->getContentSize().width - 1, 0)); _background->addChild(repeat, kBackground); repeat = CCSprite::createWithSpriteFrameName("background.png"); repeat->setAnchorPoint(ccp(0,0)); repeat->setPosition(ccp(2 * (repeat->getContentSize().width - 1), 0)); _background->addChild(repeat, kBackground); //设置路灯 _foreground = CCSprite::createWithSpriteFrameName("lamp.png"); _foreground->setAnchorPoint(ccp(0,0)); _gameBatchNode->addChild(_foreground, kForeground); repeat = CCSprite::createWithSpriteFrameName("lamp.png"); repeat->setAnchorPoint(ccp(0,0)); repeat->setPosition(ccp(repeat->getContentSize().width * 4, 0)); _foreground->addChild(repeat, kBackground); repeat = CCSprite::createWithSpriteFrameName("lamp.png"); repeat->setAnchorPoint(ccp(0,0)); repeat->setPosition(ccp(repeat->getContentSize().width * 8, 0)); _foreground->addChild(repeat, kBackground); //加入精灵云 CCSprite * cloud; _clouds = CCArray::createWithCapacity(4); _clouds->retain(); float cloud_y; for (int i = 0; i < 4; i++) { //云位置:一低一高一低一高显示 cloud_y = i % 2 == 0 ? _screenSize.height * 0.7f : _screenSize.height * 0.8f; cloud = CCSprite::createWithSpriteFrameName("cloud.png"); cloud->setPosition(ccp (_screenSize.width * 0.15f + i * _screenSize.width * 0.25f, cloud_y)); _gameBatchNode->addChild(cloud, kBackground); _clouds->addObject(cloud); } //创建地形类 _terrain = Terrain::create(); _gameBatchNode->addChild(_terrain, kMiddleground); //创建主角类 _player = Player::create(); _gameBatchNode->addChild(_player, kBackground); //加入logo _intro = CCSprite::createWithSpriteFrameName("logo.png"); _intro->setPosition(ccp(_screenSize.width * 0.5f, _screenSize.height * 0.7f)); _gameBatchNode->addChild(_intro, kForeground); //加入重试 _tryAgain = CCSprite::createWithSpriteFrameName("label_tryagain.png"); _tryAgain->setPosition(ccp(_screenSize.width * 0.5f, _screenSize.height * 0.7f)); _tryAgain->setVisible(false); this->addChild(_tryAgain, kForeground); //加入积分板 _scoreDisplay = CCLabelBMFont::create("000000", "font.fnt", _screenSize.width * 0.3f, kCCTextAlignmentCenter); _scoreDisplay->setAnchorPoint(ccp(1,0)); _scoreDisplay->setPosition(ccp(_screenSize.width * 0.95f, _screenSize.height * 0.88f)); this->addChild(_scoreDisplay, kBackground); //加入帽子 _hat = CCSprite::createWithSpriteFrameName("hat.png"); _hat->setVisible(false); _gameBatchNode->addChild(_hat, kMiddleground); //加入一个竞技团队(车队动画和车队移动动画) _jam = CCSprite::createWithSpriteFrameName("jam_1.png"); //创建车队动画 CCAnimation* animation; animation = CCAnimation::create(); CCSpriteFrame * frame; int i; for(i = 1; i <= 3; i++) { char szName[100] = {0}; sprintf(szName, "jam_%i.png", i); frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(szName); animation->addSpriteFrame(frame); } animation->setDelayPerUnit(0.2f / 3.0f); animation->setRestoreOriginalFrame(false); animation->setLoops(-1); _jamAnimate = CCAnimate::create(animation); _jamAnimate->retain(); _gameBatchNode->addChild(_jam, kBackground); _jam->setPosition(ccp(_screenSize.width * 0.19f, _screenSize.height * 0.47f)); _jamMove = CCMoveTo::create(6.0f, ccp(-_screenSize.width * 0.3f, _jam->getPositionY())); _jamMove->retain(); //add menu CCSprite * menuItemOn; CCSprite * menuItemOff; //菜单有两个状态,平时展示的样子和点击的样子 menuItemOn = CCSprite::createWithSpriteFrameName("btn_new_on.png"); menuItemOff = CCSprite::createWithSpriteFrameName("btn_new_off.png"); //New Game 菜单 CCMenuItemSprite * starGametItem = CCMenuItemSprite::create( menuItemOff, menuItemOn, this, //这个最重要,点击菜单调用系统哪个方法 menu_selector(GameLayer::startGame)); menuItemOn = CCSprite::createWithSpriteFrameName("btn_howto_on.png"); menuItemOff = CCSprite::createWithSpriteFrameName("btn_howto_off.png"); //How to Play 菜单 CCMenuItemSprite * howToItem = CCMenuItemSprite::create( menuItemOff, menuItemOn, this, menu_selector(GameLayer::showTutorial)); _mainMenu = CCMenu::create(howToItem, starGametItem, NULL);//创建菜单 _mainMenu->alignItemsHorizontallyWithPadding(120);//设置两个菜单的水平间距(水平方向以padding间隙排序) //_mainMenu->alignItemsVerticallyWithPadding(50); _mainMenu->setPosition(ccp(_screenSize.width * 0.5f, _screenSize.height * 0.54)); this->addChild(_mainMenu, kForeground); _tutorialLabel = CCLabelTTF::create("", "Times New Roman", 25); _tutorialLabel->setPosition(ccp (_screenSize.width * 0.5f, _screenSize.height * 0.6f) ); this->addChild(_tutorialLabel, kForeground); _tutorialLabel->setVisible(false); }
2.3、游戏控制
展示教程状态
void GameLayer::showTutorial (CCObject* pSender) { _tutorialLabel->setString("Tap the screen to make the player jump."); _state = kGameTutorialJump; _jam->runAction(_jamMove); _intro->setVisible(false); _mainMenu->setVisible(false); //SimpleAudioEngine::sharedEngine()->playEffect("start.wav"); _tutorialLabel->setVisible(true); }
开始游戏状态
void GameLayer::startGame (CCObject* pSender) {
_tutorialLabel->setVisible(false);
_intro->setVisible(false);
_mainMenu->setVisible(false);
_jam->runAction(_jamMove);
// SimpleAudioEngine::sharedEngine()->playEffect("start.wav");
_terrain->setStartTerrain ( true );
_state = kGamePlay;
}
重新开始游戏
void GameLayer::resetGame () { //初始化配置 _score = 0; _speedIncreaseInterval = 15; _speedIncreaseTimer = 0; //显示积分 char szValue[100] = {0}; sprintf(szValue, "%i", (int) _score); _scoreDisplay->setString (szValue); _scoreDisplay->setAnchorPoint(ccp(1,0)); _scoreDisplay->setPosition(ccp(_screenSize.width * 0.95f, _screenSize.height * 0.88f)); _state = kGameIntro; _intro->setVisible(true); _mainMenu->setVisible(true); _jam->setPosition(ccp(_screenSize.width * 0.19f, _screenSize.height * 0.47f)); _jam->setVisible(true); _jam->runAction(_jamAnimate); _running = true; }
2.4、游戏层主循环
游戏层主循环,游戏状态机
void GameLayer::update(float dt) { //CCLog("_running:%d",_running); if (!_running) return; //获取主角位置 if (_player->getPositionY() < -_player->getHeight() || _player->getPositionX() < -_player->getWidth() * 0.5f) {//死亡判断 if (_state == kGamePlay) { _running = false; //create GAME OVER state _state = kGameOver;//状态为结束状态 _tryAgain->setVisible(true);//出现重试图标 _scoreDisplay->setAnchorPoint(ccp(0.5f, 0.5f));//分数位置修改 _scoreDisplay->setPosition(ccp(_screenSize.width * 0.5f, _screenSize.height * 0.88f)); _hat->setPosition(ccp(_screenSize.width * 0.2f, -_screenSize.height * 0.1f)); _hat->setVisible(true);//出现帽子 //旋转精灵,以度为单位 CCAction * rotate = CCRotateBy::create(2.0f, 660); CCAction * jump = CCJumpBy::create(2.0f, ccp(0,10), _screenSize.height * 0.8f, 1); //主角死亡,帽子旋转着跳起 _hat->runAction(rotate); _hat->runAction(jump); //SimpleAudioEngine::sharedEngine()->stopBackgroundMusic(); //SimpleAudioEngine::sharedEngine()->playEffect("crashing.wav"); } } //更新主角状态,角色状态机 _player->update(dt); _terrain->move(_player->getVector().x); //检查碰撞冲突 if (_player->getState() != kPlayerDying) _terrain->checkCollision(_player); //放置主角 _player->place(); if (_player->getNextPosition().y > _screenSize.height * 0.6f) { _gameBatchNode->setPositionY( (_screenSize.height * 0.6f - _player->getNextPosition().y) * 0.8f); } else { _gameBatchNode->setPositionY ( 0 ); } //更新视差 update paralax if (_player->getVector().x > 0) { //一直往左移 _background->setPositionX(_background->getPosition().x - _player->getVector().x * 0.25f); float diffx; //移完一个宽度时,重新把位置设置为接近0的位置 if (_background->getPositionX() < -_background->getContentSize().width) { diffx = fabs(_background->getPositionX()) - _background->getContentSize().width; _background->setPositionX(-diffx); } _foreground->setPositionX(_foreground->getPosition().x - _player->getVector().x * 4); if (_foreground->getPositionX() < -_foreground->getContentSize().width * 4) { diffx = fabs(_foreground->getPositionX()) - _foreground->getContentSize().width * 4; _foreground->setPositionX(-diffx); } int count = _clouds->count(); CCSprite * cloud; for (int i = 0; i < count; i++) { cloud = (CCSprite *) _clouds->objectAtIndex(i); cloud->setPositionX(cloud->getPositionX() - _player->getVector().x * 0.15f); if (cloud->getPositionX() + cloud->boundingBox().size.width * 0.5f < 0 ) cloud->setPositionX(_screenSize.width + cloud->boundingBox().size.width * 0.5f); } } if (_jam->isVisible()) { if (_jam->getPositionX() < -_screenSize.width * 0.2f) { _jam->stopAllActions(); _jam->setVisible(false); } } if (_terrain->getStartTerrain() && _player->getVector().x > 0) { _score += dt * 50; char szValue[100] = {0}; sprintf(szValue, "%i", (int) _score); _scoreDisplay->setString (szValue); _speedIncreaseTimer += dt; if (_speedIncreaseTimer > _speedIncreaseInterval) { _speedIncreaseTimer = 0; _player->setMaxSpeed (_player->getMaxSpeed() + 4); } } if (_state > kGameTutorial) {//教程模式状态 if (_state == kGameTutorialJump) { if (_player->getState() == kPlayerFalling && _player->getVector().y < 0) { _player->stopAllActions(); _jam->setVisible(false); _jam->stopAllActions(); _running = false; _tutorialLabel->setString("While in the air, tap the screen to float."); _state = kGameTutorialFloat; } } else if (_state == kGameTutorialFloat) { if (_player->getPositionY() < _screenSize.height * 0.95f) { _player->stopAllActions(); _running = false; _tutorialLabel->setString("While floating, tap the screen again to drop."); _state = kGameTutorialDrop; } }else { _tutorialLabel->setString("That's it. Tap the screen to play."); _state = kGameTutorial; } } }
3、角色
3.1、角色循环
角色循环,处理状态机(0.017s)
void Player::update (float dt) { //加速度到最大,然后匀速 if (_speed + ACCELERATION <= _maxSpeed) { _speed += ACCELERATION; } else { _speed = _maxSpeed; } _vector.x = _speed; //CCLog("play state:%d",_state); switch (_state) { case kPlayerMoving: _vector.y -= GRAVITY; if (_hasFloated) _hasFloated = false; break; case kPlayerFalling: if (_floating ) { _vector.y -= FLOATNG_GRAVITY;//(减去重力加速度0.4f,乘以空气阻力0.98f) _vector.x *= FLOATING_FRICTION; } else { _vector.y -= GRAVITY;//减去重力加速度(1.3f),乘以空气阻力(0.99f) _vector.x *= AIR_FRICTION; _floatingTimer = 0; } break; case kPlayerDying: _vector.y -= GRAVITY;//y减去重力加速度(1.3f),x减去速度4 _vector.x = -_speed; this->setPositionX(this->getPositionX() + _vector.x); break; } if (_jumping) {//按了跳起,就处于下落状态 _state = kPlayerFalling; _vector.y += PLAYER_JUMP * 0.25f;//跳高速度跟跳跃高度(15)的1/4 if (_vector.y > PLAYER_JUMP ) _jumping = false; } if (_vector.y < -TERMINAL_VELOCITY) //y速度需要大于-70 _vector.y = -TERMINAL_VELOCITY; _nextPosition.y = this->getPositionY() + _vector.y;//设置下一点的y值 if (_vector.x * _vector.x < 0.01) _vector.x = 0; if (_vector.y * _vector.y < 0.01) _vector.y = 0; if (_floating) {//漂浮定时器 _floatingTimer += dt; if (_floatingTimer > _floatingTimerMax) { _floatingTimer = 0; this->setFloating(false); } } } //主角位置的真正实现 inline virtual void place () { this->setPositionY( _nextPosition.y ); if (_vector.x > 0 && this->getPositionX() < _screenSize.width * 0.2f) { this->setPositionX(this->getPositionX() + _vector.x); if (this->getPositionX() > _screenSize.width * 0.2f) { this->setPositionX(_screenSize.width * 0.2f); } } };
4、地形
地形精灵初始化,地形精灵本身是个空白图的精灵
4.1、地形精灵初始化
void Terrain::initTerrain () { _increaseGapInterval = 5000; _increaseGapTimer = 0; //陷阱宽初始为2 _gapSize = 2; //街区块池,设计一个街区块pool用数组存起来 _blockPool = CCArray::createWithCapacity(20); _blockPool->retain(); //init object pools Block * block; for (int i = 0; i < 20; i++) { //初始化街区块 block = Block::create(); this->addChild(block); _blockPool->addObject(block); } _blocks = CCArray::createWithCapacity(20); _blocks->retain(); _minTerrainWidth = _screenSize.width * 1.5f; random_shuffle(_blockPattern.begin(), _blockPattern.end()); random_shuffle(_blockWidths.begin(), _blockWidths.end()); random_shuffle(_blockHeights.begin(), _blockHeights.end()); this->addBlocks(0); }
4.2、地形精灵操作
移动地形精灵
void Terrain::move (float xMove) { if (xMove < 0) return; if (_startTerrain) { if (xMove > 0 && _gapSize < 5) _increaseGapTimer += xMove;//增加空隙定时器 if (_increaseGapTimer > _increaseGapInterval) { _increaseGapTimer = 0; _gapSize += 1; } } this->setPositionX(this->getPositionX() - xMove); Block * block; block = (Block *) _blocks->objectAtIndex(0); if (this->getPositionX() + block->getWidth() < 0) { _blocks->removeObjectAtIndex(0); _blocks->addObject(block); this->setPositionX(this->getPositionX() + block->getWidth()); float width_cnt = this->getWidth() - block->getWidth() - ((Block *) _blocks->objectAtIndex(0))->getWidth(); this->initBlock(block); this->addBlocks(width_cnt); } }
//地形精灵重置
void Terrain::reset() { this->setPosition(ccp(0,0)); _startTerrain = false; int count = _blocks->count(); Block * block; int i = 0; int currentWidth = 0; for (i = 0; i < count; i++) { block = (Block *) _blocks->objectAtIndex(i); this->initBlock(block); currentWidth += block->getWidth(); } while (currentWidth < _minTerrainWidth) { block = (Block *) _blockPool->objectAtIndex(_blockPoolIndex); _blockPoolIndex++; if (_blockPoolIndex == _blockPool->count()) { _blockPoolIndex = 0; } _blocks->addObject(block); this->initBlock(block); currentWidth += block->getWidth(); } this->distributeBlocks(); _increaseGapTimer = 0; _gapSize = 2; }
检查碰撞
void Terrain::checkCollision (Player * player) { //检查主角状态,死亡则跳出 if (player->getState() == kPlayerDying) return; //街区总块数 int count = _blocks->count(); Block * block; //是否在空中 bool inAir = true; int i; for (i = 0; i < count; i++) { block = (Block *) _blocks->objectAtIndex(i); if (block->getType() == kBlockGap) continue; //if within x, check y (bottom collision) //当主角和房子在X轴上时 if (player->right() >= this->getPositionX() + block->left() && player->left() <= this->getPositionX() + block->right()) { if (player->bottom() >= block->top() && player->next_bottom() <= block->top() && player->top() > block->top()) { player->setNextPosition(ccp(player->getNextPosition().x, block->top() + player->getHeight())); player->setVector ( ccp(player->getVector().x, 0) ); // Sets the rotation (angle) of the node in degrees player->setRotation(0.0); inAir = false; break; } } } for (i = 0; i < count; i++) { block = (Block *) _blocks->objectAtIndex(i); if (block->getType() == kBlockGap) continue; //now if within y, check x (side collision) //右侧房子突然高起 if ((player->bottom() < block->top() && player->top() > block->bottom()) || (player->next_bottom() < block->top() && player->next_top() > block->bottom())) { if (player->right() >= this->getPositionX() + block->getPositionX() && player->left() < this->getPositionX() + block->getPositionX()) { player->setPositionX( this->getPositionX() + block->getPositionX() - player->getWidth() * 0.5f ); player->setNextPosition(ccp(this->getPositionX() + block->getPositionX() - player->getWidth() * 0.5f, player->getNextPosition().y)); player->setVector ( ccp(player->getVector().x * -0.5f, player->getVector().y) ); //主角装墙上了 if (player->bottom() + player->getHeight() * 0.2f < block->top()) { player->setState(kPlayerDying); return; } break; } } } if (inAir) { //设置下降状态 player->setState(kPlayerFalling); } else { //设置一直移植状态 player->setState(kPlayerMoving); player->setFloating (false); } }
4.3、地形控制街区块
地形初始化街区块,地形移动和重置时会触发
void Terrain::initBlock(Block * block) { int blockWidth; int blockHeight; //根据现在的街区类型索引找 int type = _blockTypes[_currentTypeIndex]; _currentTypeIndex++; if (_currentTypeIndex == _blockTypes.size()) { _currentTypeIndex = 0; } //地形设计开始 if (_startTerrain) { //是否设置陷阱 if (_showGap) { int gap = rand() % _gapSize; if (gap < 2) gap = 2; //设置陷阱块 block->setupBlock (gap, 0, kBlockGap); _showGap = false; } else { blockWidth = _blockWidths[_currentWidthIndex]; _currentWidthIndex++; if (_currentWidthIndex == _blockWidths.size()) { random_shuffle(_blockWidths.begin(), _blockWidths.end()); _currentWidthIndex = 0; } if (_blockHeights[_currentHeightIndex] != 0) { //change height of next block blockHeight = _blockHeights[_currentHeightIndex]; //if difference too high, decrease it if (blockHeight - _lastBlockHeight > 2 && _gapSize == 2) { blockHeight = 1; } } else { blockHeight = _lastBlockHeight; } _currentHeightIndex++; if (_currentHeightIndex == _blockHeights.size()) { _currentHeightIndex = 0; random_shuffle(_blockHeights.begin(), _blockHeights.end()); } block->setupBlock (blockWidth, blockHeight, type); _lastBlockWidth = blockWidth; _lastBlockHeight = blockHeight; //select next block series pattern _currentPatternCnt++; if (_currentPatternCnt > _blockPattern[_currentPatternIndex]) { _showGap = true; //start new pattern _currentPatternIndex++; if (_currentPatternIndex == _blockPattern.size()) { random_shuffle(_blockPattern.begin(), _blockPattern.end()); _currentPatternIndex = 0; } _currentPatternCnt = 1; } } } else {//地形没有改变 terrain is not being changed yet _lastBlockHeight = 2; _lastBlockWidth = rand() % 2 + 2; block->setupBlock (_lastBlockWidth, _lastBlockHeight, type); } }
void Terrain::addBlocks(int currentWidth) { Block * block; while (currentWidth < _minTerrainWidth) { block = (Block *) _blockPool->objectAtIndex(_blockPoolIndex);//从内存池获取街区块 _blockPoolIndex++; if (_blockPoolIndex == _blockPool->count()) { _blockPoolIndex = 0; } this->initBlock(block);//初始化街区块 currentWidth += block->getWidth(); _blocks->addObject(block); } this->distributeBlocks(); }
地形上分布街区块
void Terrain::distributeBlocks() { int count = _blocks->count(); Block * block; Block * prev_block; int i; for (i = 0; i < count; i++) { block = (Block *) _blocks->objectAtIndex(i); if (i != 0) { prev_block = (Block *) _blocks->objectAtIndex(i - 1); block->setPositionX( prev_block->getPositionX() + prev_block->getWidth()); } else { block->setPositionX ( 0 ); } } }
5、街区块
街区块存在于一个从左到右的块数组(_blocks)。每个块是个精灵。
5.1、街区块定义和初始化
街区块定义
//街区类 class Block : public GameSprite { //屏幕宽高 CCSize _screenSize; int _tileWidth; int _tileHeight; int _puffIndex; CCSpriteFrame * _tile1; CCSpriteFrame * _tile2; CCSpriteFrame * _tile3; CCSpriteFrame * _tile4; CCSpriteFrame * _roof1;//屋顶1 CCSpriteFrame * _roof2;//屋顶2 CCArray * _wallTiles; CCArray * _roofTiles; CCAction * _puffSpawn; CCAction * _puffMove; CCAction * _puffFade; CCAction * _puffScale; CCAction * _puffAnimation; void initBlock(void); void createPuff(void); public: CC_SYNTHESIZE(int, _type, Type); //声明一个成员变量_puffing以及getfunName函数,没有set函数。getfunName函数的实现要自己做 CC_SYNTHESIZE_READONLY(bool, _puffing, Puffing); //声明成员变量数组:烟囱 CC_SYNTHESIZE(CCArray *, _chimneys, Chimneys); Block(); ~Block(); static Block * create(); void setupBlock (int width, int height, int type); void setPuffing (bool value); void hidePuffs(); inline virtual int left() { return this->getPositionX(); } inline virtual int right() { return this->getPositionX() + _width; } inline virtual int top() { return this->getHeight(); } inline virtual int bottom() { return 0; } };
街区块初始化
//初始化街区配置信息 void Block::initBlock(){ _tile1 = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName ("building_1.png"); _tile2 = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName ("building_2.png"); _tile3 = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName ("building_3.png"); _tile4 = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName ("building_4.png"); _roof1 = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName ("roof_1.png"); _roof2 = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName ("roof_2.png"); int i; _wallTiles = CCArray::createWithCapacity(20); _wallTiles->retain(); _roofTiles = CCArray::createWithCapacity(5); _roofTiles->retain(); CCSprite * tile; for (i = 0; i < 5; i++) { tile = CCSprite::createWithSpriteFrameName("roof_1.png"); tile->setAnchorPoint(ccp(0, 1)); tile->setPosition(ccp(i * _tileWidth, 0)); tile->setVisible(false); this->addChild(tile, kMiddleground, kRoofTile); _roofTiles->addObject(tile); for (int j = 0; j < 4; j++) { tile = CCSprite::createWithSpriteFrameName("building_1.png"); tile->setAnchorPoint(ccp(0, 1)); tile->setPosition(ccp(i * _tileWidth, -1 * (_tileHeight * 0.47f + j * _tileHeight))); tile->setVisible(false); this->addChild(tile, kBackground, kWallTile); _wallTiles->addObject(tile); } } _chimneys = CCArray::createWithCapacity(5); _chimneys->retain(); CCSprite * chimney; CCSprite * puff; for (i = 0; i < 5; i++) { chimney = CCSprite::createWithSpriteFrameName("chimney.png"); chimney->setVisible(false); this->addChild(chimney, kForeground, kChimney); _chimneys->addObject(chimney); for (int j = 0; j < TOTAL_PUFFS; j++) { puff = CCSprite::createWithSpriteFrameName("puff_1.png"); puff->setAnchorPoint(ccp(0,-0.5)); puff->setVisible(false); chimney->addChild(puff, -1, j); } } CCAnimation* animation; animation = CCAnimation::create(); CCSpriteFrame * frame; for(i = 1; i <= 4; i++) { char szName[100] = {0}; sprintf(szName, "puff_%i.png", i); frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(szName); animation->addSpriteFrame(frame); } animation->setDelayPerUnit(0.75f / 4.0f); animation->setRestoreOriginalFrame(false); animation->setLoops(-1); _puffAnimation = CCAnimate::create(animation); _puffAnimation->retain(); _puffSpawn = CCRepeat::create(CCSequence::create(CCDelayTime::create(0.5f), CCCallFunc::create( this, callfunc_selector(Block::createPuff) ), NULL), TOTAL_PUFFS); _puffSpawn->retain(); _puffMove = CCMoveBy::create(1.0f, ccp(-100,80)); _puffMove->retain(); _puffFade = CCFadeOut::create(2.0f); _puffFade->retain(); _puffScale = CCScaleBy::create(1.5f, 1.5); _puffScale->retain(); _puffIndex = 0; }
5.2、设置街区块参数,包括屋顶和陷阱
//设置街区:入参:宽、高、类型 void Block::setupBlock (int width, int height, int type) { this->setPuffing(false); _type = type; _width = width * _tileWidth; _height = height * _tileHeight + _tileHeight * 0.49f; this->setPositionY(_height); //这是屋顶 CCSpriteFrame * wallFrame; //随机生成屋顶 CCSpriteFrame * roofFrame = rand() % 10 > 6 ? _roof1 : _roof2; int num_chimneys; float chimneyX[] = {0,0,0,0,0}; switch (type) { //这是一个坑(看不见) case kBlockGap: this->setVisible(false); return; //街区1 case kBlock1: wallFrame = _tile1; chimneyX[0] = 0.2f; chimneyX[1] = 0.8f; num_chimneys = 2; break; case kBlock2: wallFrame = _tile2; chimneyX[0] = 0.2f; chimneyX[1] = 0.8f; chimneyX[2] = 0.5f; num_chimneys = 3; break; case kBlock3: wallFrame = _tile3; chimneyX[0] = 0.2f; chimneyX[1] = 0.8f; chimneyX[2] = 0.5f; num_chimneys = 3; break; case kBlock4: wallFrame = _tile4; chimneyX[0] = 0.2f; chimneyX[1] = 0.5f; num_chimneys = 2; break; } int i; GameSprite * chimney; int count; count = _chimneys->count(); for (i = 0; i < count; i++) { chimney = (GameSprite *) _chimneys->objectAtIndex(i); if (i < num_chimneys) { chimney->setPosition( ccp (chimneyX[i] * _width, 0) ); chimney->setVisible(true); } else { chimney->setVisible(false); } } this->setVisible(true); CCSprite * tile; count = _roofTiles->count(); for (i = 0; i < count; i++) { tile = (CCSprite *) _roofTiles->objectAtIndex(i); if (tile->getPositionX() < _width) { tile->setVisible(true); //显示相应的屋顶 tile->setDisplayFrame(roofFrame); } else { tile->setVisible(false); } } // count = _wallTiles->count(); for (i = 0; i < count; i++) { tile = (CCSprite *) _wallTiles->objectAtIndex(i); if (tile->getPositionX() < _width && tile->getPositionY() > -_height) { tile->setVisible(true); tile->setDisplayFrame(wallFrame); } else { tile->setVisible(false); } } }
5.3、街区块突出景象(烟囱)
定时出现街区块突出的烟囱。在街区块初始化(Block::initBlock())时设置定时器。
void Block::createPuff () { int count = _chimneys->count(); CCSprite * chimney; CCSprite * puff; for (int i = 0; i < count; i++) { chimney = (CCSprite * ) _chimneys->objectAtIndex(i); if (chimney->isVisible()) { puff = (CCSprite *) chimney->getChildByTag(_puffIndex); puff->setVisible(true); puff->stopAllActions(); puff->setScale(1.0); puff->setOpacity(255); puff->setPosition(ccp(0,0)); puff->runAction((CCAction *) _puffAnimation->copy()->autorelease()); puff->runAction((CCAction *) _puffMove->copy()->autorelease()); //puff->runAction((CCAction *) _puffFade->copy()->autorelease()); puff->runAction((CCAction *) _puffScale->copy()->autorelease()); } } _puffIndex++; if (_puffIndex == TOTAL_PUFFS) _puffIndex = 0; }
5.4、街区块随机模式
街区随机设计,地形精灵初始化时会打乱顺序
//随机的模式、宽、高、及类型 int patterns[] = {1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,3,3,3}; int widths[] = {2,2,2,2,2,3,3,3,3,3,3,4,4,4,4,4,4}; int heights[] = {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,3,3,3,3,3,3,4}; int types[] = {1,2,3,4,1,3,2,4,3,2,1,4,2,3,1,4,2,3,1,2,3,2,3,4,1,2,4,3,1,3,1,4,2,4,2,1,2,3}; //街区模式 vector<int> _blockPattern (patterns, patterns + sizeof(patterns) / sizeof(int)); //街区宽度 vector<int> _blockWidths (widths, widths + sizeof(widths) / sizeof(int)); //街区高度 vector<int> _blockHeights (heights, heights + sizeof(heights) / sizeof(int)); //街区类型 vector<int> _blockTypes (types, types + sizeof(types) / sizeof(int));
6、自定义精灵
class GameSprite : public CCSprite { protected: CCSize _screenSize; public: //定义变量,并且直接定义默认的get/set方法 CC_SYNTHESIZE(CCPoint, _nextPosition, NextPosition); CC_SYNTHESIZE(float, _width, Width); CC_SYNTHESIZE(float, _height, Height); CC_SYNTHESIZE(CCPoint, _vector, Vector); GameSprite(void); ~GameSprite(void); //内联虚函数,只是一个接口 inline virtual void place () { this->setPosition(_nextPosition); }; inline virtual float radius () { return _width * 0.5f; } inline void setSize() { _width = this->boundingBox().size.width; _height = this->boundingBox().size.height; } };