跟我来用cocos2d-x做一个游戏 Sky Defense


游戏截图

Sky Defense 是cocos2d-x by Example Beginner's Guide,第4章的游戏示例。

先从GameLayer::init()说起,游戏的大部分初始化,都是在这里做的。

		//zeek.
		_screenSize = CCDirector::sharedDirector()->getWinSize();

		gameCreateScreen();	//添加背景及其他元素
		//
		createPools();
		createActions();//创建精灵的动作	

		//暂时还没有运行,所以设置为false(_running的值默认为false,也可以不用设置)
		this->_running = false;
		this->setTouchEnabled(true);	//触控设置为可用
		//_fallingObjects存放 falling Objects,在爆炸时候可以遍历数组
		_fallingObjects = CCArray::createWithCapacity(40);//将下落物,放在数组里方便统一管理。
		_fallingObjects->retain();//CCArray不是auotorelease()的
		//zeek..

		this->schedule(schedule_selector(GameLayer::update));//启用定时器,每帧调用一次GameLayer::update()
		SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background.mp3");//循环播放背景音乐

下面介绍 gameCreateScreen(),原文为createGameScreen()

void GameLayer::gameCreateScreen() {
	CCSprite *bg = CCSprite::create("bg.png");
	bg->setPosition(ccp(_screenSize.width * 0.5F, _screenSize.height * 0.5F));
	this->addChild(bg);
	CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("sprite_sheet.plist");
	_gameBatchNode = CCSpriteBatchNode::create("sprite_sheet.png");
	this->addChild(_gameBatchNode);

	CCSprite *sprite;
	//贴图城市背景
	for (int i = 0; i < 2; i++) {
		sprite = CCSprite::createWithSpriteFrameName("city_dark.png");
		sprite->setPosition(ccp(_screenSize.width * (0.25F + i * 0.5F), sprite->boundingBox().size.height * 0.5F));
		_gameBatchNode->addChild(sprite,kForeground);
		sprite = CCSprite::createWithSpriteFrameName("city_light.png");
		sprite->setPosition(ccp(_screenSize.width * (0.25F + i * 0.5F), sprite->boundingBox().size.height * 0.9F));
		_gameBatchNode->addChild(sprite,kBackground);
	}
	//种树
	for (int i = 0; i < 3; i++) {
		sprite = CCSprite::createWithSpriteFrameName("trees.png");
		sprite->setPosition(ccp(_screenSize.width * (0.2F + i * 0.3F),sprite->boundingBox().size.height * 0.5F) );
		_gameBatchNode->addChild(sprite,kForeground);
	}
	//添加云彩
	this->_clouds = CCArray::createWithCapacity(4);
	_clouds->retain();
	float cloud_y;
	for (int i = 0; i < 4; i++) {
		CCSprite	*cloud = CCSprite::createWithSpriteFrameName("cloud.png");
		//云彩需要不规则的排列,否则不生动
		cloud_y = i % 2 == 0 ? _screenSize.height * 0.4F : _screenSize.height * 0.5F ;
		cloud->setPosition(ccp(_screenSize.width * 0.1F + i * _screenSize.width * 0.25F, cloud_y));
		_gameBatchNode->addChild(cloud, kBackground);
		this->_clouds->addObject(cloud);	//添加到数组中去,方便管理
	}
	//得分
	_scoreDisplay = CCLabelBMFont::create("0","font.fnt",_screenSize.width * 0.3F);
	_scoreDisplay->setAnchorPoint(ccp(1.0F, 0.5F));
	_scoreDisplay->setPosition(_screenSize.width * 0.9F, _screenSize.height * 0.95F);
	this->addChild(_scoreDisplay);
	//生命力
	_energyDisplay = CCLabelBMFont::create("100","font.fnt", _screenSize.width * 0.1F,kCCTextAlignmentRight);
	_energyDisplay->setPosition(_screenSize.width * 0.05F, _screenSize.height * 0.95F);
	this->addChild(_energyDisplay);
	//health_Icon图标
	CCSprite *icon = CCSprite::createWithSpriteFrameName("health_icon.png");
	CCAssert(icon,"icon(NULL),get health_icon.png failed in GameLayer::gameCreateScreen()");
	icon->setPosition(ccp(_screenSize.width * 0.15F, _screenSize.height * 0.95F));
	_gameBatchNode->addChild(icon,kForeground);

	//bomb
	_bomb = CCSprite::createWithSpriteFrameName("bomb.png");
	_bomb->getTexture()->generateMipmap();
	_bomb->setVisible(false);
	CCSize	bombBoundingBoxSize = _bomb->boundingBox().size ;
		///add Halo inside to bomb
	CCSprite	*halo = CCSprite::createWithSpriteFrameName("halo.png");
	halo->setPosition(ccp(bombBoundingBoxSize.width * 0.4F, bombBoundingBoxSize.height  * 0.4F));
	_bomb->addChild(halo,kMiddleground,kSpriteHalo);
		///add  sparkle inside to bomb
	CCSprite *sparkle = CCSprite::createWithSpriteFrameName("sparkle.png");
	sparkle->setPosition(ccp(bombBoundingBoxSize.width * 0.72F,bombBoundingBoxSize.height * 0.72F));
	_bomb->addChild(sparkle, kMiddleground,kSpriteSparkle);
	//添加 bomb
	_gameBatchNode->addChild(_bomb,kForeground);

	//shockwave
	_shockWave = CCSprite::createWithSpriteFrameName("shockwave.png");
	_shockWave->getTexture()->generateMipmap();
	_shockWave->setVisible(false);
	_gameBatchNode->addChild(_shockWave);

	// introMessage, gameOverMessage
	_introMessage = CCSprite::createWithSpriteFrameName("logo.png");
	_introMessage->setPosition(ccp(_screenSize.width * 0.5F, _screenSize.height * 0.6F));
	_introMessage->setVisible(true);
	this->addChild(_introMessage, kForeground);

	_gameOverMessage = CCSprite::createWithSpriteFrameName("gameover.png");

	_gameOverMessage->setPosition(ccp(_screenSize.width * 0.5F, _screenSize.height * 0.65F));
	_gameOverMessage->setVisible(false);
	this->addChild(_gameOverMessage, kForeground);
}
在createGameScreen中添加了,可见的城市背景图片,种,云彩,生命值,得分,_introMessage,

还有暂时不可见的gameMessage和bomb。其中bomb又包含了2个子结点Halo和Sparkle。还有一个炸弹爆炸后的shockwave。

我对其中的_energyDisplay做了小小的调整。去掉了后面的“%”。

看完了,gameCreateScreen(),我们接下来看看createActions()

void GameLayer::createActions() {
	//坠落动作
	CCFiniteTimeAction	*easeSwing = CCSequence::create(CCEaseInOut::create(CCRotateTo::create(1.2F,-10),2),
																											CCEaseInOut::create(CCRotateTo::create(1.2F,10),2),																							NULL);
	this->_swingHealth = CCRepeatForever::create((CCActionInterval *)easeSwing);
	this->_swingHealth->retain();
	//冲击波,淡出,完成时回调shockwaveDone(),还有retain()
	_shockwaveSequence = CCSequence::create(CCFadeOut::create(1.0F),CCCallFunc::create(this,callfunc_selector(GameLayer::shockwaveDone)),NULL);
	_shockwaveSequence->retain();
	//炸弹,膨胀
	_growBomb = CCScaleTo::create(6.0F,1.0F);
	_growBomb->retain();
	//旋转
	_rotateSprite = CCRepeatForever::create(CCRotateBy::create(0.5F,-90) );
	_rotateSprite->retain();
	
	//bomb爆炸的动画
	CCAnimation *animation;
	CCSpriteFrame	*frame;

	animation	= CCAnimation::create();
	CCString	*name;
        //利用10帧的动画(CCAnimation是资源)来创建CCAnimate(动作),通过动作序列来复合动作
	for (int i = 1; i < 10; i++) {
		name = CCString::createWithFormat("boom%i.png",i);
		frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(name->getCString());
		CCAssert(frame,"frame was NULL,in GameLayer::createActions()");
		animation->addSpriteFrame(frame);
	}
	animation->setDelayPerUnit(1 / 10.0F);//动画的快慢在这里调整
	animation->setRestoreOriginalFrame(true);//传入true
	//撞到地面的动画,别忘了CCSequence::create(... ,NULL);
	_groundHit = CCSequence::create(CCMoveBy::create( 0, ccp(0,_screenSize.height * 0.12F)),CCAnimate::create(animation),CCCallFuncN::create(this,callfuncN_selector(GameLayer::animationDone) ),NULL);
	_groundHit->retain();

	//爆炸动画
	animation = CCAnimation::create();
	int frameCount = 7;
	for (int i= 1; i < frameCount; i++) {
		name = CCString::createWithFormat("explosion_small%i.png", i);
		frame = CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(name->getCString());
		CCAssert(frame,"frame was NULL,in GameLayer::createActions()");
		animation->addSpriteFrame(frame);
	}
	animation->setDelayPerUnit(0.5F / frameCount);
	animation->setRestoreOriginalFrame(true);

	_explosion = CCSequence::create(CCAnimate::create(animation),CCCallFuncN::create(this,callfuncN_selector(GameLayer::animationDone)),NULL);
	_explosion->retain();
}

注意CCCallFuncN::create(this,callfuncN_selector(GameLayer::animationDone) 这个this作为参数传入GameLayer::animationDone(this),N代表CCNode

animationDone()将执行动作的精灵通过setVisible(false)隐藏起来(通过参数传进来的this->,在暗中作梗)。

下面的GameLayer::ccTouchesBegan随着你的手指在屏幕轻点(tap)一下,整个游戏就被赋予了生命,动起来了。

void GameLayer::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *event) {
	//游戏如果不是running状态,要么是未开始,要么是已经结束
	if (!_running) {
		if (_introMessage->isVisible() ) {
			_introMessage->setVisible(false);
		}else if (_gameOverMessage->isVisible() ) {
			_gameOverMessage->setVisible(false);
		}
		this->resetGame();
		return ;
	}
	//running
	CCTouch	*touch = (CCTouch *)pTouches->anyObject();
	//如果炸弹在膨胀
	if (touch) 
	{
		if (_bomb->isVisible() ) {
			//不管炸弹是否可以爆炸(1.爆炸,2.无效(不具备爆炸条件,则销毁)), 停止所有动作包括(child's actions)
			_bomb->stopAllActions();
			CCSprite*	child;
			child = (CCSprite *)_bomb->getChildByTag(kSpriteSparkle);
			child->stopAllActions();
			child = (CCSprite *)_bomb->getChildByTag(kSpriteHalo);
			child->stopAllActions();

			//如果炸弹已经准备好,则创建shockWave
			if (_bomb->getScale() > 0.3F) {
				_shockWave->setScale(0.1F);
				_shockWave->setPosition(_bomb->getPosition());
				_shockWave->setVisible(true);
				_shockWave->runAction(CCScaleTo::create(0.5F,_bomb->getScale() * 2.0F));
				_shockWave->runAction((CCFiniteTimeAction *)_shockwaveSequence->copy()->autorelease() );
				//播放音效
				SimpleAudioEngine::sharedEngine()->playEffect("bombRelease.wav");
			}
			else {
				SimpleAudioEngine::sharedEngine()->playEffect("bombFail.wav");
			}
			_bomb->setVisible(false);
			_shockwaveHits = 0;
		}
		//当前screen中没有bomb创建一个
		else {
			//缩小,位置,可见,停止原有的动作,透明度50%。添加;shockWave和Halo
			CCPoint	tap = touch->getLocation();
			_bomb->stopAllActions();	//zeek,child's actions是不是也要停止?,此时无雷,何谈child?
			_bomb->setPosition(tap);
			_bomb->setScale(0.1F);
			_bomb->setOpacity(50);
			_bomb->setVisible(true);
			_bomb->runAction((CCAction*) _growBomb->copy()->autorelease() );

			CCSprite	*child;
			child  = (CCSprite *)_bomb->getChildByTag(kSpriteHalo);
			CCAssert(child != NULL,"child(NULL)!,getChildByTag(kSpriteHalo) failed,in GameLayer::ccTouchesBegan()");
			child->runAction((CCAction *)_rotateSprite->copy()->autorelease());
			child  = (CCSprite *)_bomb->getChildByTag(kSpriteSparkle);
			CCAssert(child != NULL,"child(NULL)!,getChildByTag(kSpriteSparkle) failed,in GameLayer::ccTouchesBegan()");
			child->runAction((CCAction *)_rotateSprite->copy()->autorelease());
		}
	}
}

再下面,就是游戏的源头了

void GameLayer::update (float dt) {
    if (!_running) return;
    
    int count;
    int i;
    CCSprite * sprite;
    
    //update timers
    
    _meteorTimer += dt;
    if (_meteorTimer > _meteorInterval) {
        _meteorTimer = 0;
        this->resetMeteor();
    }
    
    _healthTimer += dt;
    if (_healthTimer > _healthInterval) {
        _healthTimer = 0;
        this->resetHealth();
    }
    
    _difficultyTimer += dt;
    if (_difficultyTimer > _difficultyInterval) {
        _difficultyTimer = 0;
        this->increaseDifficulty();
    }
    
    if (_bomb->isVisible()) {
        if (_bomb->getScale() > 0.3f) {
            if (_bomb->getOpacity() != 255)
                _bomb->setOpacity(255);
        }
    }
    
    //检测与冲击波有关的碰撞
	if (_shockWave->isVisible() ) {
		CCPoint shockWavePosition = _shockWave->getPosition();
		CCSprite *sprite;
		CCPoint currentSpritePosition;
		float diffx, diffy;
		char szScore[10] = { 0 };
		for (int count = _fallingObjects->count() - 1; count >= 0; count--) {
			sprite =(CCSprite *) _fallingObjects->objectAtIndex(count);
			 currentSpritePosition = sprite->getPosition();
			 diffx = shockWavePosition.x - currentSpritePosition.x;
			 diffy = shockWavePosition.y - currentSpritePosition.y;
			 if (pow(diffx,2)+pow(diffy,2) <= pow(_shockWave->boundingBox().size.width * 0.5F, 2)) {
				 //sprite 冲击波的范围内
				 sprite->stopAllActions();
				 sprite->runAction((CCAction *)_explosion->copy()->autorelease());	//zeek!
				 SimpleAudioEngine::sharedEngine()->playEffect("boom.wav");	//播放音效
				 //如果是流星 ,加分
				 if (sprite->getTag() == kSpriteMeteor) {
					 _shockwaveHits ++;
					 _score += _shockwaveHits * 13 + _shockwaveHits * 2;
					 sprintf(szScore,"%i",_score);
					 _scoreDisplay->setString(szScore);
				 }
				 _fallingObjects->removeObjectAtIndex(count);	//被炸了(消失了),当然要从数组中移除			 
			 }//if(pow(diffx
		}//for
	}//if(_shockwave->isVisible())

    //move clouds
    count = _clouds->count();
    for (i = 0; i < count; i++) {
        sprite = (CCSprite *) _clouds->objectAtIndex(i);
        sprite->setPositionX(sprite->getPositionX() + dt * 20);
        if (sprite->getPositionX() > _screenSize.width + sprite->boundingBox().size.width * 0.5f)
            sprite->setPositionX(-sprite->boundingBox().size.width * 0.5f);
    }
}
下面的这段代码是原作者,大家比较一下有什么不同。

    //check collision with shockwave
    if (_shockWave->isVisible()) {
        count = _fallingObjects->count();

        float diffx;
        float diffy;

        for (i = count-1; i >= 0; i--) {
            sprite = (CCSprite *) _fallingObjects->objectAtIndex(i);
            diffx = _shockWave->getPositionX() - sprite->getPositionX();
            diffy = _shockWave->getPositionY() - sprite->getPositionY();
            if (pow(diffx, 2) + pow(diffy, 2) <= pow(_shockWave->boundingBox().size.width * 0.5f, 2)) {
                sprite->stopAllActions();
                sprite->runAction((CCAction *) _explosion->copy()->autorelease());
                SimpleAudioEngine::sharedEngine()->playEffect("boom.wav");
                if (sprite->getTag() == kSpriteMeteor) {
                    _shockwaveHits++;
                    _score += _shockwaveHits * 13 + _shockwaveHits * 2;
                }
                //play sound
                _fallingObjects->removeObjectAtIndex(i);
            }
        }

        char szValue[100] = {0};
        sprintf(szValue, "%i", _score);
        _scoreDisplay->setString(szValue);
    }

后面重要的函数还有resetGame()

void GameLayer::resetGame() {
	//得分,生命
	_score = 0;
	_energy = 100;

	//时间和速度
	_meteorInterval = 2.5F;
	_meteorTimer = _meteorInterval * 0.99F;
	_meteorSpeed = 10;//10s 落地

	_healthInterval = 20;
	_healthTimer = 0;
	_healthSpeed = 15;

	_difficultyInterval = 60;
	_difficultyTimer = 0;

	_running = true;

	CCString	*value;
	value= CCString::createWithFormat("%i",_energy);
	_energyDisplay->setString(value->getCString());
	value = CCString::createWithFormat("%i",_score);
	_scoreDisplay->setString(value->getCString());
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值