跑酷victorian (维多利亚人)代码分析

本文是解析跑酷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;
	}
};

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值