1. 程式人生 > >Cocos2d-x 3.4 之 消滅星星 > 第三篇(終) <

Cocos2d-x 3.4 之 消滅星星 > 第三篇(終) <

周期 ack ini 顏色 博客 ec2 width pri mp3格式

***************************************轉載請註明出處:http://blog.csdn.net/lttree********************************************



滿滿的淚啊。

從5月22日寫的第一篇,於6月6日結束。

中間各種課程、上機、大作業穿插。焦頭爛額的。

最後最終做出來幾乎相同的樣子了。。

PS:寫博客這幾天。宿舍一直停電狀態。。

。真是醉了。。




本篇實現的功能:

> 粒子特效

> 音樂音效

> 漂浮文字

> combo特效 及 每關結束後星星的消除(小於等於10個的一個個消除。剩余的一齊消除)

> 最高分存儲、場景的簡單存儲

> 消除星星的Hint




一、粒子特效

粒子特效,主要是星星消除後的爆炸效果。

技術分享 技術分享

這裏主要用了兩個函數:

? 產生爆炸粒子特效

? 獲取點擊星星的顏色

void starSpecialEffect(Star* sta,Point position,Node* node,int staNum)
{
	// 創建爆炸粒子效果,粒子數量為 staNum 個
	ParticleExplosion* effect = ParticleExplosion::createWithTotalParticles(staNum);
	// 設置此粒子特效的紋理圖片
    effect->setTexture(Director::getInstance()->getTextureCache()->addImage("star.png"));
	// 設置開始時候的粒子顏色
	effect->setStartColor(getColor4F(sta->getImgIndex()));
	effect->setStartColorVar(Color4F(0,0,0,1));
    effect->setEndColor(getColor4F(sta->getImgIndex()));
    effect->setEndColorVar(Color4F(0,0,0,1));
	// 設置開始時的粒子大小
    effect->setStartSize(20.0f);
    effect->setGravity(Point(0,-300));
	// 設置粒子生命周期
    effect->setLife(2.0f);
	// 設置粒子速度
    effect->setSpeed(200);
    effect->setSpeedVar(10);
	// 設置粒子位置
    effect->setPosition(position);
    node->addChild(effect,2);
}
 
Color4F getColor4F(int imgIndex)
{
	switch(imgIndex){
	case 0:
		//red
		return Color4F::RED;
    case 1:
		//blue
		return Color4F::BLUE;
    case 2:
		//green
		return Color4F::GREEN;
    case 3:
		//purple
		return Color4F(128.0f,0,128.0f,1.0f);
    case 4:
		//yellow
		return Color4F::YELLOW;
    }
    return Color4F(1,1,1,0);
}

詳細粒子特效的應用,等有時間做一個單獨的博文發出來。。




二、音樂音效

這裏用了UserDefault進行存儲,音樂音效的開關,

音樂和音效同一開關。沒有分開。

主要就是 Android對於 ogg 格式的音樂支持是最好的。

可是在Windows平臺不好測試。由於Windows自帶的WMP(Windows Media Player)不支持這個格式的音樂播放。即使沒有路,我們自己創造路來走,有大牛就開發了一款解碼軟件—— K-Lite Codec Pack,

我的WMP是能夠播放ogg了,cocos2d-x 還是須要修改一下,臨時沒改好,

於是。。。閹割了。。

我是在Windows用 mp3格式 測試,然後在Android用ogg格式的,效果挺好

之前的三消遊戲中。非常多人就說音樂播放不出來。沒有效果,

可是我自己試的是沒問題的。偶爾還真有一兩個音效不好用。我認為還是格式問題,

各個音效部分,我就不多說了。在對應位置插入即可,

背景音樂。須要 重載虛函數

virtual void onEnterTransitionDidFinish();
virtual void cleanup();

onEnterTransitionDidFinish是在場景載入完畢後進行,

不同於onEnter。onEnter是場景開始載入就進行,

cleanup 函數。是在場景被消除時的動作,

我們的背景音樂就是要在這兩個函數中增加:

void WelcomeScene::onEnterTransitionDidFinish()
{
	Layer::onEnterTransitionDidFinish();  
	if ( userDefault->getBoolForKey("MusicKey") ) {                      
        SimpleAudioEngine::getInstance()->playBackgroundMusic("Music/music.ogg", true);  
    } 
}
void WelcomeScene::cleanup()
{
	Layer::cleanup();
	SimpleAudioEngine::getInstance()->stopBackgroundMusic();
}

對於音樂音效說的也就這麽多了




三、漂浮文字

漂浮文字效果,單獨開了一個類,

基本的創建函數:

FloatWord* FloatWord::create( const std::string& word,const int fontSize,Vec2 begin )
{
	FloatWord* fw = new FloatWord();
	if( !fw->init(word,fontSize,begin) )	{
		return NULL;
	}
	
	fw->autorelease();
	return fw;
}

幾個基本的工具函數:

void FloatWord::floatInOut(const float speed,const float delayTime,std::function<void()> callback){
	
	MoveTo* moveIn = MoveTo::create(speed,Vec2(GAME_SCREEN_WIDTH/2,fw_begin.y));
	MoveTo* moveOut = MoveTo::create(speed,Vec2(-fw_label->getContentSize().width,fw_begin.y));

	CallFunc* call = CallFunc::create(callback);

	Sequence* action = Sequence::create(moveIn,DelayTime::create(delayTime),moveOut,call,NULL);
	fw_label->runAction(action);
}

void FloatWord::floatIn(const float speed){
	
	MoveTo* moveIn = MoveTo::create(speed,Vec2(GAME_SCREEN_WIDTH/2,fw_begin.y));

	Sequence* action = Sequence::create(moveIn,NULL);
	fw_label->runAction(action);
}

void FloatWord::floatOut(const float speed,const float delayTime){
	
	MoveTo* moveOut = MoveTo::create(speed,Vec2(-fw_label->getContentSize().width,fw_begin.y));

	Sequence* action = Sequence::create(DelayTime::create(delayTime),moveOut,NULL);
	fw_label->runAction(action);
}

就是將動作 Sequence起來了,按順序播放即可了

技術分享 技術分享




四、combo特效 及 每關結束後星星的消除

首先是 combo 特效,做一個函數,然後每次消除的時候,推斷消除的個數是否滿足combo特效觸發條件就可以。

void comboEffect(int num,Node* node){
	
	if( num < 5 )
		return;

	Sprite* comboSprite;
	if( num >= 10 ){
		comboSprite = Sprite::create("combo_3.png");
	}else if( num >= 7 ){
		comboSprite = Sprite::create("combo_2.png");
	}else{
		comboSprite = Sprite::create("combo_1.png");
	}

	comboSprite->setPosition(Vec2(GAME_SCREEN_WIDTH/2,GAME_SCREEN_HEIGHT/2));
	node->addChild(comboSprite,4);

	Blink* blink = Blink::create(1.0f,5);
	CallFunc* remove = CallFunc::create([=](){comboSprite->removeFromParentAndCleanup(true);});
	Sequence* action = Sequence::create(blink,remove,nullptr);
	comboSprite->runAction(action);
}

最後星星的消除。這裏我的處理比較麻煩:

1.推斷此關卡結束(沒有能夠消除的星星),然後將 全局的 關卡結束 變量 設置為 true,獲得剩余星星的數量,假設剩余星星數量大於10 則 設置為10(由於一個一個消除的效果,最多10個)

2.在 update函數中(每一幀都會調用的函數),會推斷關卡是否結束,若結束。會調用 消除函數,10個以內,每消除一個都會返回,不會繼續消除。並且記錄消除時間,消除一次後一定時間間隔再進行下一次消除

3.消除完10個(或者小於10個)以後,不會再返回,會一次性將剩余星星消除完成,將 關卡結束 變量設置為false。

這裏的: 關卡結束一系列操作:

if( isFinish() )	{
    isLevelFinish = true;
    int temp = totalStarNum();

    if( temp <= 10 )	{
        needDelOneByOne = temp;
    }
}
else
{
    needDelOneByOne = 10;
}

update函數:

void GameScene::update( float dt )
{
	// 分數變化
	Label *labelScore = (Label *)this -> getChildByTag(6);
	labelScore -> setString( StringUtils::format("Score: %d ",_score));

	// 假設當前關卡結束  星星一個個消除的實現
	if( isLevelFinish )	{

		deleteTime += dt;
		if( deleteTime > DELSTAR_ONEBYONE_TIME )	{
			popFinishStar(needDelOneByOne);
			needDelOneByOne--;
			deleteTime = 0;
		}
	}
}

消除結束星星函數:

void GameScene::popFinishStar( int n )
{
	int r,c;
	Star* sta;

	for( r = ROWS-1 ; r >= 0 ; r-- )	{
		for( c = 0 ; c < COLS ; c++ )	{
			sta = map[r][c];
			if( sta )	{
					starSpecialEffect(sta,sta->getPosition(),this,5);
					map[r][c]=NULL;
					sta->removeFromParentAndCleanup(true);
					return;
				}
				else
				{
					starSpecialEffect(sta,sta->getPosition(),this,totalStarNum()*4);
					map[r][c]=NULL;
					sta->removeFromParentAndCleanup(true);
				}
			}
		}
	}


	isLevelFinish = false;
	scheduleOnce(schedule_selector(GameScene::levelOver),2.0f);
}

技術分享 技術分享 技術分享





五、最高分的存儲。場景的簡單存儲

最高分的存儲,還是用了userdefault,

就是在遊戲結束的時候。推斷一下是否破紀錄:

if( userDefault->getIntegerForKey("HightScore") < _score )
		userDefault->setIntegerForKey("HightScore",_score);

場景的存儲。用了 push 和 pop,

在主界面定義一個變量,來推斷能否夠繼續,

剛進入主界面時,場景棧是沒有場景存儲的,此時點擊 繼續遊戲 就會退出遊戲,

所以要在場景棧沒有場景時,不同意點擊 繼續遊戲 button。

這個變量,在從遊戲界面跳轉到主界面(通過返回函數跳轉)時。會設置為true。就是能夠點擊。




六、消除星星Hint

當消除幾個星星,我們都要有提示。加了幾分。

遊戲結束,假設剩余星星數量小於10個,都要有額外分數的添加。

星星消除函數是這種:

一個等差數列,第一個星星 5分,第二個15分,第三個25分(首項為5,公差為10的等差數列)

所以,假設消除n個星星,就是用到等差數列的求和公式了:

n*5+n*(n-1)*10/2

剩余星星數量。所獲得的額外分數則建立了一個數組,放在GameDefine頭文件,

// 剩余星星所獎勵的分數
static const int rewardScore[11] = {
	2000,
	1980,
	1920,
	1820,
	1680,
	1500,
	1280,
	1020,
	720,
	380,
	0
};


技術分享 技術分享





到這裏,消滅星星系列完美結束啦~~~

撒花。。。

接下來把歷史遺留下的問題——別踩白塊 剩下部分搞定,

然後要做第一款自己想的遊戲了,

敬請期待呀~~~





本文源代碼: > 這裏 <

終於APK: > here <


***************************************轉載請註明出處:http://blog.csdn.net/lttree********************************************

Cocos2d-x 3.4 之 消滅星星 &gt; 第三篇(終) &lt;