cpp-tests CocosDenshionTest

~~~~我的生活,我的点点滴滴!!


玩游戏的时候,背景音乐和音效能够使一款游戏增添不少色彩。


背景音乐:时间相对比较长,同一时间内只能播放一首背景音乐。


音效:时间相对比较短,同一时间内可以播放多个音效。


不管是音乐还是音效,cocos2d-x中都采用SimpleAudioEngine类实现跨平台的声音引擎。


今天我们分析的例子就是cpp-tests中关于声音的引擎使用例子部分。



1. 游戏背景音乐



1.1 背景音乐在不同平台下所支持的声音


关于背景音乐,cocos2d-x 在不同平台下所支持的格式大致如下:


主要平台
支持类型
Android
android.media.MediaPlayer类支持的格式,包括MP3、WAV和3GP
iOS
cocos2d-iPhone中cocosDenshion支持的类型,推荐MP3和CAF
Win32
MID和WAV


1.2 背景音乐SimpleAudioEngine类常用的函数


函数名
返回类型
描述
preloadBackgroundMusic

预加载背景音乐
playBackgroundMusic

播放背景音乐
stopBackgroundMusic

停止背景音乐
pauseBackgroundMusic

暂停背景音乐
resumeBackgroundMusic

重新开始背景音乐
rewindBackgroundMusic

回放背景音乐
willPlayBackgroundMusic
布尔型
是否会播放背景音乐
isBackgroundMusicPlaying
布尔型
是否正播放背景音乐
getBackgroundMusicVolume
布尔型
获得背景音乐音量
setBackgroundMusicVolume

设置背景音乐音量



2. 游戏音效


2.1 音效在不同平台下所支持的音效格式:

平台名称
支持类型
Android
对应OGG格式支持最好,同时支持WAV格式
iOS
cocos2d-iPhone中cocosDenshion支持的类型,推荐CAF
Win32
MID和WAV



2.2 音效SimepleAudioEngine类常用的函数

函数名
返回类型
描述
getEffectsVolume
浮点型
获得音效音量
setEffectsVolume

设置音效音量
playEffect
整型
播放音效,参数为文件路径和是否循环
pauseEffect

暂停音效,参数为播放时获得的ID号
pauseAllEffects

暂停所有音效
resumeEffect

开始音效,参数为播放时获得的ID号
resumeAllEffects

开始所有音效
stopEffect

停止音效,参数为播放时获得的ID号
stopAllEffects

停止所有音效
preloadEffect

预加载音效
unloadEffect

将预加载的音效从缓存中删除


注意:预加载音乐和音效能够提高程序的执行效率,但是这样也会增加内存的占用。所以,在实际使用时,要根据项目特点来平衡效率
和内存压力的问题。

例子图:

cpp-tests CocosDenshionTest_第1张图片


3. 源码分析


下面是简单的代码分析,代码里面都写上了相应的注释,我懒得在扯一些重复的解释话了,大家直接看代码里面的注释:

//注意要带上此头文件,他是主要的声音引擎类,不同平台有不同的接口,但是类名还是一样的
#include "SimpleAudioEngine.h"
#include "extensions/GUI/CCControlExtension/CCControlSlider.h"

//=================================================================
//对于不同平台支持不同的音乐与音效格式,这点很重要,上面的表格已经有说到
//也许不全,但是肯定是主要的,下面的官方例子也有讲解
//=================================================================
// android effect only support ogg
#if (CC_TARGET_PLATFORM == CC_PLATFOR_ANDROID)
    #define EFFECT_FILE        "effect2.ogg"
#elif( CC_TARGET_PLATFORM == CC_PLATFOR_MARMALADE)
    #define EFFECT_FILE        "effect1.raw"
#else
    #define EFFECT_FILE        "effect1.wav"
#endif // CC_PLATFOR_ANDROID

#if (CC_TARGET_PLATFORM == CC_PLATFOR_WIN32)
    #define MUSIC_FILE        "music.mid"
#elif (CC_TARGET_PLATFORM == CC_PLATFOR_BLACKBERRY || CC_TARGET_PLATFORM == CC_PLATFOR_LINUX )
    #define MUSIC_FILE        "background.ogg"
#else
    #define MUSIC_FILE        "background.mp3"
#endif // CC_PLATFOR_WIN32

USING_NS_CC;
using namespace CocosDenshion;

#define LINE_SPACE          40

class Button : public Node//, public TargetedTouchDelegate
{
public:
    
	//此处省略N行代码
	......

    ~Button()
    {
//        Director::getInstance()->getTouchDispatcher()->removeDelegate(this);
    }

	//后面lambda表达式给std::function<void()> &onTriggered赋值,这是一个回调功能函数
	//但是我没有发现什么触发的这个回调,所谓回调就是提前写好在哪里调用,仔细看效果
	//是在鼠标点击结束后才会相应的动作产生,这样我们就去看onTouchEnded()这个函数,
	//他在里面有个调用_onTriggered()这个动作,他就是我们绑定的回调函数。
	//至于onTouchEnded()为什么能触发,那是cocos2dx的消息
	//机制推动的,这个大家要深究可以去看源码了,我这里只是解释为什么这样设置了回调
	//函数后就能触发我们想要的效果,而不是cocos2dx在促使回调进行
    void onTriggered(const std::function<void()> &onTriggered)
    {
        _onTriggered = onTriggered;
    }

private:
    Button()
        : _child(NULL)
    {      
        // 注册触摸事件
        auto listener = EventListenerTouchOneByOne::create();
        listener->setSwallowTouches(true);
        
		//不懂的可以去看链接http://blog.csdn.net/ac_huang/article/details/37839413
        listener->onTouchBegan = CC_CALLBACK_2(Button::onTouchBegan, this);
        listener->onTouchEnded = CC_CALLBACK_2(Button::onTouchEnded, this);
        listener->onTouchCancelled = CC_CALLBACK_2(Button::onTouchCancelled, this);
        
        _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
        
    }

	//此处省略N行代码
	......

	//返回触摸区域
    bool touchHits(Touch  *touch)
    {
        const Rect area(0, 0, _child->getContentSize().width, _child->getContentSize().height);
        return area.containsPoint(_child->convertToNodeSpace(touch->getLocation()));
    }

    bool onTouchBegan(Touch  *touch, Event  *event)
    {
        CC_UNUSED_PARAM(event);
        const bool hits = touchHits(touch);
        if (hits)
            //产生缩小,看上去点击的感觉
            scaleButtonTo(0.9f);
        return hits;
    }

    void onTouchEnded(Touch  *touch, Event  *event)
    {
        CC_UNUSED_PARAM(event);
        const bool hits = touchHits(touch);
        if (hits && _onTriggered)
            //在这里进度回调的
            _onTriggered();
        scaleButtonTo(1);
    }

    void onTouchCancelled(Touch  *touch, Event  *event)
    {
        CC_UNUSED_PARAM(event);
        scaleButtonTo(1);
    }

    void scaleButtonTo(float scale)
    {
        auto action = ScaleTo::create(0.1f, scale);
		
        action->setTag(900);
		//个人觉得stopActionByTag()函数能把所有相同的tag的Action动作都停止掉
		//后来看完代码,确实也是如此
        stopActionByTag(900);
        runAction(action);
    }

    Node *_child;
    std::function<void()> _onTriggered;
};

class AudioSlider : public Node
{
public:
    
	//此处省略N行代码
	......

private:
    AudioSlider(Direction direction)
        : _direction(direction)
        , _slider(NULL)
        , _lblMinValue(NULL)
        , _lblMaxValue(NULL)
    {
    }

    bool init()
    {
		//建议去看ControlSlider的源码,了解此类的一些基本接口,此类用来设置滑动条
        _slider = extension::ControlSlider::create("extensions/sliderTrack.png","extensions/sliderProgress.png" ,"extensions/sliderThumb.png");
		//设置缩放为原来的一半
        _slider->setScale(0.5);
        if (_direction == Vertical)
            _slider->setRotation(-90.0);
        addChild(_slider);
        return true;
    }

    Direction _direction;
    extension::ControlSlider *_slider;
    LabelTTF *_lblMinValue;
    LabelTTF *_lblMaxValue;
};

CocosDenshionTest::CocosDenshionTest()
: _soundId(0),
_musicVolume(1),
_effectsVolume(1),
_sliderPitch(NULL),
_sliderPan(NULL),
_sliderGain(NULL),
_sliderEffectsVolume(NULL),
_sliderMusicVolume(NULL)
{
    addButtons();
    addSliders();
    schedule(schedule_selector(CocosDenshionTest::updateVolumes));

    // 提前加载背景音乐与音效,如果内存吃紧的话,就不要提前加载了,如果在win32上开发,进去看源码,会发现此函数为空
    // 其他平台下不是这样的,因为引擎主要针对移动平台,在win32上只是一个开发与调试,所以有可能会有不理想的效果,这都
    // 无关紧要的。
    SimpleAudioEngine::getInstance()->preloadBackgroundMusic( MUSIC_FILE );
    SimpleAudioEngine::getInstance()->preloadEffect( EFFECT_FILE );

    // 设置默认音量
    SimpleAudioEngine::getInstance()->setEffectsVolume(0.5);
    SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(0.5);

}

CocosDenshionTest::~CocosDenshionTest()
{
}

void CocosDenshionTest::onExit()
{
    Layer::onExit();

	//一定要记得释放掉声音引擎
    SimpleAudioEngine::end();
}

void CocosDenshionTest::addButtons()
{
    auto lblMusic = LabelTTF::create("Control Music", "Arial", 24);
    addChildAt(lblMusic, 0.25f, 0.9f);

    Button *btnPlay = Button::createWithText("play");
    //lambda表达式注册回调函数
    btnPlay->onTriggered([]() {
        SimpleAudioEngine::getInstance()->playBackgroundMusic(MUSIC_FILE, true);
    });
    addChildAt(btnPlay, 0.1f, 0.75f);

	//此处省略N多行代码
    ......

    Button *btnPlayEffect = Button::createWithText("play");
	//由于要用到类成员变量,所以lambda表达式里面带上了"[this]"
	//详细请看链接http://blog.csdn.net/ac_huang/article/details/27574889
    btnPlayEffect->onTriggered([this]() {
        const float pitch = _sliderPitch->getValue();
        const float pan = _sliderPan->getValue();
        const float gain = _sliderGain->getValue();
        _soundId = SimpleAudioEngine::getInstance()->playEffect(EFFECT_FILE, false, pitch, pan, gain);
    });
    addChildAt(btnPlayEffect, 0.6f, 0.8f);

	//此处省略N行代码
    ......
}

//根据百分比来添加控件的位置
void CocosDenshionTest::addChildAt(Node *node, float percentageX, float percentageY)
{
    const Size size = VisibleRect::getVisibleRect().size;
    node->setPosition(Point(percentageX * size.width, percentageY * size.height));
    addChild(node);
}

//SimpleAudioEngine是我们用来控制音乐、音效的类,他是单个例子
void CocosDenshionTest::updateVolumes(float)
{
    //通过判断当前他们是否有改变来区别更新哪一个
    const float musicVolume = _sliderMusicVolume->getValue();
    if (fabs(musicVolume - _musicVolume) > 0.001) {
        _musicVolume = musicVolume;
        //用来改变背景音乐的声音大小
        SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(_musicVolume);
    }

    const float effectsVolume = _sliderEffectsVolume->getValue();
    if (fabs(effectsVolume - _effectsVolume) > 0.001) {
        _effectsVolume = effectsVolume;
        //用来改变背景音效的声音大小
        SimpleAudioEngine::getInstance()->setEffectsVolume(_effectsVolume);
    }
}

个人觉得重要的知识点来和自己有疑问的点都在上面有注释,大家就直接看代码和注释,这样理解起来更快,有哪些错误的地方,欢迎大家
指出,共同学习,共同进步。

你可能感兴趣的:(cpp-tests CocosDenshionTest)