Cocos2d-x塔防游戏_贼来了11——完善游戏

原创: @涵紫任珊

Cocos2d-x塔防游戏_贼来了1——基础知识储备
Cocos2d-x塔防游戏_贼来了2——地图的创建加载
Cocos2d-x塔防游戏_贼来了3——进攻的敌人
Cocos2d-x塔防游戏_贼来了4——创建炮塔
Cocos2d-x塔防游戏_贼来了5——触摸响应
Cocos2d-x塔防游戏_贼来了6——触摸响应2
Cocos2d-x塔防游戏_贼来了7——数据管理与碰撞检测
Cocos2d-x塔防游戏_贼来了8——批量添加敌人
Cocos2d-x塔防游戏_贼来了9——关卡数据
Cocos2d-x塔防游戏_贼来了10——选择关卡
Cocos2d-x塔防游戏_贼来了11——完善游戏

现在回头看看,关于塔防系列的教程,前面我们已经拖拖拉拉的写了也有10篇之多了,是不是都不想听我啰嗦了。

虽然这个贼来了游戏还有很多功能(比如炮塔的升级、移除、数值系统)都还没有实现,但我们还是要止步于此了,感兴趣的同学可以自己继续研究拓展。毕竟这仅仅只是一篇教程,我们也只是为了教大家使用Cocos2d-x更方便的制作游戏,而不是在做一个商业项目,所以感兴趣的同学可以自己继续拓展。

在本章里,我们将完善游戏代码,添加更多的游戏场景、音乐音效、粒子效果以及预加载功能,下面就一起来看看吧。

音乐音效

Cocos2d-x声音的接口主要有三个API:

  1. SimpleAudioEngine:提供一个最简单的声音控制API。如果你仅仅是要播放一些简单的背景音乐,那我们推荐你选用该API。
  2. CDAudioManager:一个封装了AVAudioPlayer对象,且非常基础、简单的API。它可以播放MP3,IMA4或者AAC格式的声音。
  3. CDSoundEngine:基于OpenAL的声音引擎。它可以控制多达32种通道的声音,且功能强大,能完全取代CDAudioManager和SimpleAudioEngine。

因为本游戏只需要简单的播放一些声音,所以这里我们选择了最简单、最普遍的SimpleAudioEngine。 SimpleAudioEngine非常简单,通过下面的几个API就可以满足本游戏声音的播放。

SimpleAudioEngine::getInstance()->preloadBackgroundMusic(FileUtils::getInstance()->fullPathForFilename("XX").c_str() );
SimpleAudioEngine::getInstance()->preloadEffect(FileUtils::getInstance()->fullPathForFilename("XX" ).c_str());
 
SimpleAudioEngine::getInstance()->playBackgroundMusic(FileUtils::getInstance()->fullPathForFilename("XX").c_str(), true);
SimpleAudioEngine::getInstance()->playEffect(FileUtils::getInstance()->fullPathForFilename("XX").c_str(), false);

游戏中声音有两种,一种是背景音乐,另一种是音效,所以播放它们需要用不同的API。

还有一点要提的是,在使用SimpleAudioEngine之前需要包含它的头文件。如下所示:

#include "SimpleAudioEngine.h" 
using namespace CocosDenshion;

预加载功能

游戏资源预加载可以提升用户体验,比如当一个游戏场景的内容过于庞大时,预加载可以缓解游戏资源加载时的卡顿现象。

预加载的实现我们需要做的是,在第一个场景load完的时候,把下一个场景所用的资源提前加载到缓冲,这样切换到下个场景时就可以直接读取缓存资源了,玩家也就不用等很久了。

一般情况下,我们需要预加载的资源有图片和声音两种,在Cocos2d-x的cpp-tests例子里本身就有一个预加载图片的例子(TextureCacheTest)。它的原理是用一个变量来记录已加载的资源数目,当加载好一个资源时,这个变量值就加1,当这个变量值等于总资源数时,意味着我们已经加载了所有的文件,这时就可以跳转到下一个场景了。预加载声音的原理和它差不多,都需要先加入缓存,下面我们还是直接看看代码是怎样实现的吧。

void LoadingResScene::loadResources()
{
    SimpleAudioEngine::getInstance()->preloadBackgroundMusic(FileUtils::getInstance()->fullPathForFilename("sound/music.mp3").c_str() );
    numberOfLoadedRes++;
    SimpleAudioEngine::getInstance()->preloadEffect(FileUtils::getInstance()->fullPathForFilename("sound/dead.wav" ).c_str());
    numberOfLoadedRes++;
    SimpleAudioEngine::getInstance()->preloadEffect(FileUtils::getInstance()->fullPathForFilename("sound/button.wav").c_str() );
    numberOfLoadedRes++;
    SimpleAudioEngine::getInstance()->preloadEffect(FileUtils::getInstance()->fullPathForFilename("sound/comeout.wav").c_str() );
    numberOfLoadedRes++;
    SimpleAudioEngine::getInstance()->preloadEffect(FileUtils::getInstance()->fullPathForFilename("sound/shoot.wav").c_str() );
    numberOfLoadedRes++;
    SimpleAudioEngine::getInstance()->preloadEffect(FileUtils::getInstance()->fullPathForFilename("sound/tip.wav").c_str() );
    numberOfLoadedRes++;
    SimpleAudioEngine::getInstance()->preloadEffect(FileUtils::getInstance()->fullPathForFilename("sound/dead.mp3").c_str() );
    numberOfLoadedRes++;
    SpriteFrameCache::getInstance()->addSpriteFramesWithFile("Play.plist");
    numberOfLoadedRes++;
 
    Director::getInstance()->getTextureCache()->addImageAsync("playbg.png", CC_CALLBACK_1(LoadingResScene::loadingCallBack, this));
    Director::getInstance()->getTextureCache()->addImageAsync("playbg1.png", CC_CALLBACK_1(LoadingResScene::loadingCallBack, this));
    ........................
}

preloadBackgroundMusic和preloadEffect方法是用来缓存音乐音效的。numberOfLoadedRes就是前面提到过的那个记录已加载资源数目的变量,每加载一个资源,numberOfLoadedRes值就加1。loadingCallBack是加载图片后的回调函数,在它的函数体中同样递增numberOfLoadedRes的值。

在贼来了游戏中,我们在加载资源的同时用了一根进度条来显示加载进度。进度条的创建前面章节已经讲过,所以就此跳过,接下来,我们来更新load进度条,代码如下:

void LoadingResScene::logic(float dt)
{
    float percent = (float)numberOfLoadedRes / (float)totalOfLoadedRes * 100;
 
    progressBar->setPercentage(percent);
    if (numberOfLoadedRes == totalOfLoadedRes)
    {
        transitionScene();
        SimpleAudioEngine::getInstance()->playBackgroundMusic(FileUtils::getInstance()->fullPathForFilename("sound/music.mp3").c_str(), true);
        SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(0.1f);
    }
}

logic方法将时时更新进度条进度,它会在加载完所有的资源后跳转到下一个场景。logic方法用如下的定时器启动:

schedule(schedule_selector(LoadingResScene::logic));

LoadingResScene场景效果图:

p1

其他界面

除了前面部分文章中提到的各个关卡场景外,我们还为游戏添加了一些其他界面,如菜单界面,成功界面,失败界面,读取关卡信息界面(在每关游戏开始之前)。下面是整个游戏的流程图,其中就包含了各个界面。

p2

菜单界面(UIScene):

p3

在菜单界面中,有一个绕按钮旋转的粒子效果,关于它的实现原理感兴趣的童鞋可以跳转到使用Cocos2d-x实现微信“天天爱消除”炫耀button特效中查看。

关卡信息界面(LevelInfoScene):

p4

关卡信息界面是玩家选择了关卡后进入的一个界面,设想中的关卡信息界面将读取当前关卡的关卡信息,但这里我们只读取了关卡当前的得分情况。

成功界面(SuccessfulScene):

p5

失败界面(FailedScene):

p6

失败界面中加入粒子特效和按钮的弹入效果,粒子效果有粒子编辑器制作产生,而弹入效果请查看源码。

总结

到目前为止,尽管本游戏的功能还不完善,代码上也不是很完美,但我们的塔防系列游戏还是就此结束了。感谢大家一直以来的支持,希望本系列教程对大家学习Cocos2d-x有所帮助。同时欢迎大家扩展游戏功能或斧正文章代码。

在此还要提醒大家的是,由于之前提交过几次未修正的游戏源码,所有请大家一定要在 https://github.com/iTyran/thiefTD 这里下载最终版的代码,再次谢谢支持!

标签: none

?>