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。
音频文件的预处理
预处理只需要在整个游戏运行过程中处理一次就可以了,如果不进行预处理,则会发现在第一次播放这个音频文件时感觉卡顿。
预处理有两个相关函数:preloadBackgroundMusic
和preloadEffect
。
//初始化背景音乐 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");
}