第十章Audio引擎

Cocos2d-x学习笔记


Cocos2d-x中的音频文件

Cocos2d-x跨平台音频支持

Cocos2d-x对于背景音乐播放各个平台格式支持如下:

  • Android平台支持android.media.MediaPlayer所支持的格式相容,android.media.MediaPlayer是Android多媒体播放类。
  • iOS平台支持推荐使用MP3和CAFF格式。
  • Windows平台支持MIDI、WAV和MP3格式。

Cocos2d-x对于音效播放各个平台格式支持如下:

  • Android平台支持Ogg和WAV文件,但最好是Ogg文件。
  • iOS平台支持使用CAFF格式。
  • Windows平台支持MIDI和WAV文件。

使用Audio引擎

Cocos2d-x提供了一个Audio引擎,Audio引擎可以独立于Cocos2d-x单独使用,Audio引擎本质上封装了OpenAL音频处理库。
具体使用的API是SimpleAudioEngine。SimpleAudioEngine有几个常用的函数:

  • void preloadBackgroundMusic(const char * pszFilePath, boolbLoop = false):预处理背景音乐文件,将压缩格式的文件进行解压处理,如MP3解压为WAV。
  • void playBackgroundMusic()::播放背景音乐,参数bLoop是控制是否循环播放,默认情况下是false。
  • void stopBackgroundMusic():停止播放背景音乐。
  • void pauseBackgroundMusic():暂停播放背景音乐。
  • void resumeBackgroundMusic():继续播放背景音乐。
  • bool isBackgroundMusicPlaying():判断背景音乐是否在播放。
  • unsigned int playEffect(const char * pszFilePath):播放音效。
  • void pauseEffect(unsigned intnSoundId):暂停播放音效,参数nSoundId是playEffect函数返回的ID。
  • void pauseAllEffects():暂停所有播放的音效。
  • void resumeAllEffects():继续播放所有音效。
  • void stopEffect(unsigned int nSoundId):停止播放音效,参数nSoundId是playEffect函数返回的ID。
  • void stopAllEffects():停止所有播放的音效。
  • void preloadEffects(const char * pszFilePath):预处理音效音频文件,将压缩格式的文件进行解压处理,如MP3解压为WAV。

音频文件的预处理

预处理只需要在整个游戏运行过程中处理一次就可以了,如果不进行预处理,则会发现在第一次播放这个音频文件时感觉卡顿。
预处理有两个相关函数:preloadBackgroundMusicpreloadEffect

//初始化背景音乐
SimpleAudioEngine::getInstance()->preloadBackgroundMusic("sound/Jazz.mpe");
//初始化音效
SimplaAudioEngine::getInstance()->preloadEffect("sound/Blip.wav");

这些预处理过程代码放置到AppDelegate文件applicationDidFinishLaunching()函数中比较好:

bool AppDelegate::applicationDidFinishLaunching() {
    ···
    //run
    director->runWithScene(scene);

    //初始化背景音乐
    SimpleAudioEngine::getInstance()->preloadBackgroundMusic("sound/Jazz.mpe");
    //初始化音效
    SimplaAudioEngine::getInstance()->preloadEffect("sound/Blip.wav");

    return true;
}

播放背景音乐

背景音乐的播放与停止实例代码如下:

SimpleAudioEngine::getInstance()->playBackgroundMusic("sound/Jazz.mp3", true);
SimpleAudioEngine::getInstance()->stopBackgroundMusic("sound/Jazz.mp3");

背景音乐的播放代码放置到什么地方比较合适呢?例如,在Setting场景中,主要代码如下:

bool Setting::init()
{
    return true;
}

void Setting::onEnter()
{
    Layer::onEnter();
    log("Setting onEnter");
}

void Setting::onEnterTransitiononDidFinish()
{
    Layer::onEnterTransitionDidFinish();
    log("Setting onEnterTransitionDidFinish");
    //播放代码
}

void Setting::onExit()
{
    Layer::onExit();
    log("Setting onExit");
}

void Setting::onExitTransitionDidStart()
{
    Layer::onExitTransitiononDidStart();
    log("Setting onExitTransitionDidStart");
}

void Setting::cleanup()
{
    Layer::cleanup();
    log("Setting cleanup");
}

停止播放背景音乐

停止播放背景音乐代码放置什么地方比较合适呢?例如在HelloWorld场景中,主要代码如下:

bool HelloWorld::init()
{
    return true;
}

void HelloWorld::onEnter()
{
    Layer::onEnter();
    log("HelloWorld onEnter");
}

void HelloWorld::onEnterTransitiononDidFinish()
{
    Layer::onEnterTransitionDidFinish();
    log("HelloWorld onEnterTransitionDidFinish");
}

void HelloWorld::onExit()
{
    Layer::onExit();
    log("HelloWorld onExit");
}

void HelloWorld::onExitTransitionDidStart()
{
    Layer::onExitTransitiononDidStart();
    log("HelloWorld onExitTransitionDidStart");
}

void HelloWorld::cleanup()
{
    Layer::cleanup();
    log("HelloWorld cleanup");
    // 停止播放的代码
}

背景音乐播放暂停与继续

背景音乐播放暂停与继续很少使用:
SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
它们的调用一般情况下是在游戏退到后台是调用的暂停函数pauseBackgroundMusic(),然后回到前台是调用继续函数resumeBackgroundMusic()。这些代码应该放在游戏生命周期函数中:

void AppDelegate::applicationDidEnterBackground() {
    Director::getInstance()->stopAnimation();
    SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}
void Appdelegete::applicationWillEnterBackground() {
    Director::getInstance()->startAnimation();
    SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}

实例:设置背景音乐与音效

HelloWorld.h文件

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "SimpleAudioEngine.h"
#include "SettingScene.h"


class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();  
    virtual void onEnter();
    virtual void onEnterTransitionDidFinish();
    virtual void onExit();
    virtual void onExitTransitionDidStart();
    virtual void cleanup();

    void menuItemHelpCallback(cocos2d::Ref* pSender);
    void menuItemStartCallback(cocos2d::Ref* pSender);
    void menuItemSettingCallback(cocos2d::Ref* pSender);

    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);
};

#endif // __HELLOWORLD_SCENE_H__

HelloWorld.cpp文件

#include "HelloWorldScene.h"

USING_NS_CC;
using namespace CocosDenshion;

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //
    // 1. super init first
    if ( !Layer::init() )
    {
    return false;
    }

    log("HelloWorld init");

    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    Sprite *bg = Sprite::create("background.png");

    // position the label on the center of the screen
    bg->setPosition(Vec2(origin.x + visibleSize.width/2,
    origin.y + visibleSize.height /2));
    this->addChild(bg);

    //开始精灵
    Sprite *startSpriteNormal = Sprite::create("start-up.png");
    Sprite *startSpriteSelected = Sprite::create("start-down.png");

    MenuItemSprite *startMenuItem = MenuItemSprite::create(startSpriteNormal, 
    startSpriteSelected,
    CC_CALLBACK_1(HelloWorld::menuItemStartCallback, this));
    startMenuItem->setPosition(Director::getInstance()->convertToGL(Vec2(700, 170)));

    // 设置图片菜单
    MenuItemImage *settingMenuItem = MenuItemImage::create(
    "setting-up.png",
    "setting-down.png",
    CC_CALLBACK_1(HelloWorld::menuItemSettingCallback, this)); 
    settingMenuItem->setPosition(Director::getInstance()->convertToGL(Vec2(480, 400)));

    // 帮助图片菜单
    MenuItemImage *helpMenuItem = MenuItemImage::create(
    "help-up.png",
    "help-down.png",
    CC_CALLBACK_1(HelloWorld::menuItemHelpCallback, this)); 
    helpMenuItem->setPosition(Director::getInstance()->convertToGL(Vec2(860, 480)));

    Menu* mu = Menu::create(startMenuItem, settingMenuItem, helpMenuItem, NULL);    
    mu->setPosition(Vec2::ZERO);
    this->addChild(mu);

    return true;
}

void HelloWorld::menuItemSettingCallback(Ref* pSender)
{   
    auto sc = Setting::createScene();
    auto reScene = TransitionJumpZoom::create(1.0f, sc);
    Director::getInstance()->pushScene(reScene);
    SimpleAudioEngine::getInstance()->playEffect("sound/Blip.wav");
}

void HelloWorld::menuItemHelpCallback(Ref* pSender)
{
    MenuItem* item = (MenuItem*)pSender;
    log("Touch Help %p", item);
    SimpleAudioEngine::getInstance()->playEffect("sound/Blip.wav");
}

void HelloWorld::menuItemStartCallback(Ref* pSender)
{
    MenuItem* item = (MenuItem*)pSender;
    log("Touch Start %p", item);
    SimpleAudioEngine::getInstance()->playEffect("sound/Blip.wav");
}

void HelloWorld::onEnter()
{
    Layer::onEnter();
    log("HelloWorld onEnter");      
}

void HelloWorld::onEnterTransitionDidFinish()
{
    Layer::onEnterTransitionDidFinish();
    log("HelloWorld onEnterTransitionDidFinish");
    //播放
    SimpleAudioEngine::getInstance()->playBackgroundMusic("sound/Jazz.mp3", true);
}

void HelloWorld::onExit()
{
    Layer::onExit();
    log("HelloWorld onExit");
}

void HelloWorld::onExitTransitionDidStart()
{
    Layer::onExitTransitionDidStart();
    log("HelloWorld onExitTransitionDidStart");
}

void HelloWorld::cleanup()
{
    Layer::cleanup();
    log("HelloWorld cleanup");  
    //停止
    SimpleAudioEngine::getInstance()->stopBackgroundMusic("sound/Jazz.mp3");
}

Setting.h文件

#ifndef __Setting_SCENE_H__
#define __Setting_SCENE_H__

#include "cocos2d.h"
#include "SimpleAudioEngine.h"

class Setting : public cocos2d::Layer
{
    bool isEffect;
public:
    static cocos2d::Scene* createScene();

    virtual bool init();  
    virtual void onEnter();
    virtual void onEnterTransitionDidFinish();
    virtual void onExit();
    virtual void onExitTransitionDidStart();
    virtual void cleanup();

    // a selector callback
    void menuSoundToggleCallback(cocos2d::Ref* pSender);
    void menuMusicToggleCallback(cocos2d::Ref* pSender);
    void menuOkCallback(cocos2d::Ref* pSender);

    // implement the "static create()" method manually
    CREATE_FUNC(Setting);
};

#endif // __Setting_SCENE_H__

Setting.cpp文件

#include "SettingScene.h"

USING_NS_CC;
using namespace CocosDenshion;

Scene* Setting::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::create();

    // 'layer' is an autorelease object
    auto layer = Setting::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

// on "init" you need to initialize your instance
bool Setting::init()
{
    //
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }

    log("Setting init");

    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    Sprite *bg = Sprite::create("setting-back.png");

    // position the label on the center of the screen
    bg->setPosition(Vec2(origin.x + visibleSize.width/2,
                             origin.y + visibleSize.height /2));
    this->addChild(bg);

    //音效
    auto soundOnMenuItem = MenuItemImage::create(
                             "on.png",
                             "on.png");
    auto soundOffMenuItem = MenuItemImage::create(
                             "off.png",
                             "off.png");

    auto soundToggleMenuItem = MenuItemToggle::createWithCallback(CC_CALLBACK_1(Setting::menuSoundToggleCallback, this), 
                                                soundOffMenuItem,
                                                soundOnMenuItem, 
                                                NULL);
    soundToggleMenuItem->setPosition(Director::getInstance()->convertToGL(Vec2(818, 220)));

    //音乐
    auto musicOnMenuItem  = MenuItemImage::create(
                             "on.png",
                             "on.png");
    auto musicOffMenuItem  = MenuItemImage::create(
                             "off.png",
                             "off.png");
    auto musicToggleMenuItem = MenuItemToggle::createWithCallback(CC_CALLBACK_1(Setting::menuMusicToggleCallback, this),
                                                    musicOffMenuItem,
                                                    musicOnMenuItem,
                                                    NULL );
    musicToggleMenuItem->setPosition(Director::getInstance()->convertToGL(Vec2(818, 362)));

    //Ok按钮
    auto okMenuItem  = MenuItemImage::create( 
                             "ok-down.png",
                             "ok-up.png",
                             CC_CALLBACK_1(Setting::menuOkCallback, this));

    okMenuItem->setPosition(Director::getInstance()->convertToGL(Vec2(600, 510)));

    Menu* mn = Menu::create(soundToggleMenuItem, musicToggleMenuItem,okMenuItem, NULL);
    mn->setPosition(Vec2::ZERO);
    this->addChild(mn);

    return true;
}

void Setting::menuOkCallback(Ref* pSender)
{
    Director::getInstance()->popScene();
    if (isEffect) {
    SimpleAudioEngine::getInstance()->playEffect("sound/Blip.wav");
    }
}

void Setting::menuSoundToggleCallback(Ref* pSender)
{
    auto soundToggleMenuItem = (MenuItemToggle*)pSender;
    log("soundToggleMenuItem %d", soundToggleMenuItem->getSelectedIndex());

    if (isEffect) {
    SimpleAudioEngine::getInstance()->playEffect("sound/Blip.wav");
    }

    if (soundToggleMenuItem->getSelectedIndex() == 1) {//选中状态Off -> On
    isEffect = false;
    } else {
    isEffect = true;
    SimpleAudioEngine::getInstance()->playEffect("sound/Blip.wav");
    }
}


void Setting::menuMusicToggleCallback(Ref* pSender)
{
    auto musicToggleMenuItem = (MenuItemToggle*)pSender;
    log("musicToggleMenuItem %d", musicToggleMenuItem->getSelectedIndex());

    if (musicToggleMenuItem->getSelectedIndex() == 1) {//选中状态Off -> On
    SimpleAudioEngine::getInstance()->stopBackgroundMusic("sound/Synth.mp3");
    } else {
    SimpleAudioEngine::getInstance()->playBackgroundMusic("sound/Synth.mp3");
    }
    if (isEffect) {
    SimpleAudioEngine::getInstance()->playEffect("sound/Blip.wav");
    }
}


void Setting::onEnter()
{
    Layer::onEnter();
    log("Setting onEnter");
}

void Setting::onEnterTransitionDidFinish()
{
    Layer::onEnterTransitionDidFinish();
    log("Setting onEnterTransitionDidFinish");  
    isEffect = true;
    //播放
    SimpleAudioEngine::getInstance()->playBackgroundMusic("sound/Synth.mp3", true);
}

void Setting::onExit()
{
    Layer::onExit();
    log("Setting onExit");  
}

void Setting::onExitTransitionDidStart()
{
    Layer::onExitTransitionDidStart();
    log("Setting onExitTransitionDidStart");
}

void Setting::cleanup()
{
    Layer::cleanup();
    log("Setting cleanup"); 
    //停止
    SimpleAudioEngine::getInstance()->stopBackgroundMusic("sound/Synth.mp3");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值