打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
从保卫萝卜看Cocos2d-x循环播放音效的问题

魔法球这种塔,很有意思。这种塔的攻击力虽然低,但是攻击速度快啊,而且升级后还能攻击多个目标,用在对付血少速度快的怪物再适合不过了.玩了挺久发现这个塔的音效有些问题:

  1. 屏幕中有多个魔法球塔时,卖掉其中一个可能会导致所有魔法球塔的音效停止.

  2. 有时候卖掉所有的魔法球塔,但是声音还在播放!

一般情况下我是不会mind这种细节的,但由于保卫萝卜是用cocos2d-x制作的,所以我稍微多想了一下:

猜想1:由于攻击速度十分快,所以我假设魔法球这个塔的音效播放和其他的塔不太一样,可能是这个样子的:切换为攻击模式时循环播放音效,切换为待机模式时停止音效!

猜想2. 如果假设成立,这个音效由于会循环播放,如果声音太吵的话,会十分的吵,萝卜显然注意到了这点.

猜想3. 所有的魔法球塔会公用一个特效声音,要不造的塔多了就根本没法开声音玩了!

其实这座塔的音效播放逻辑十分的复杂!

验证

下面让我验证下我的猜想,看看能否帮萝卜解决这个问题!

验证1:循环播放音效

这个十分简单,我在保卫萝卜2的资源中找到了CarrotFantasy.app\Music\Towers\Ball.mp3,看了时长1s左右,但是魔法球塔的攻击速度绝对大于2次,开2倍速的会大于4次,1s播放4次音效,没有人会这么做!所以魔法球塔是循环播放音效的!

验证2:音效的特性

这个大家听一下就会知道了,魔法球的塔混在其他塔的音效里实在是太弱了!为此,我还假装很专业的用GoldWave查看了一下:

图中上面的声音是瓶子炮的声音,下面是魔法球的声音,从图上可以看出,虽然魔法球的声音很长,但是只有在0.65s时声音较大,其他时候声音都很小!

验证3.公用一个音效

开启循环播放音效十分简单,只需在playEffect("1.ogg",true)时第二个参数填true即可,这时playEffect会返回一个unsigned int类型的id,这个id会用于stopEffect(id),如下:

1
2
3
unsigned int uID=SimpleAudioEngine::sharedEngine()->playEffect("1.ogg", true);//开始循环播放
SimpleAudioEngine::sharedEngine()->stopEffect(nID);//停止播放

这样看起来似乎很简单嘛,攻击的时候播,顺带记下ID,待机的时候停,这么简单,萝卜的程序太差了吧,这都能写错!其实不然,这只是场景中只有一座塔时的情况!

下面我们来试一下如果我们连续调用多次playEffect,会发生什么问题?我做了测试项目,将每次playEffect的返回ID打在屏幕上,win32截图如下:

额,你没有看错,win32下播放同一个音效返回的id都是一样的,只要点击一下停止就全部都停了,为什么呢?让我们看一下win32下声音的id是怎么生成的吧,在SimpleAudioEngine中我们可以看到这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//播放音效的函数
unsigned int SimpleAudioEngine::playEffect(const char* pszFilePath, bool bLoop)
{
    unsigned int nRet = _Hash(pszFilePath);//可以断定nRet就是返回的id
    preloadEffect(pszFilePath);
    EffectList::iterator p = sharedList().find(nRet);
    if (p != sharedList().end())
    {
        p->second->Play((bLoop) ? -1 : 1);
    }
    return nRet;
}
//生成id的函数
unsigned int _Hash(const char *key)
{
    unsigned int len = strlen(key);
    const char *end=key+len;
    unsigned int hash;
    for (hash = 0; key < end; key++)
    {
        hash *= 16777619;
        hash ^= (unsigned int) (unsigned char) toupper(*key);
    }
    return (hash);
}
这下明白了吧,win32下的id是根据音效的路径pszFilePath算出来的,这一点确实比较坑,大家以后要注意一下!下面我看一下在android上的效果吧!

Adnroid版是正常的,每次playEffect返回的id会递增,可以明显的听出又多了一个音效,当我音效叠了5层之后已经很乱了,但是萝卜的显然不是如此,所以所有的魔法球共用一个音效是正确的!

注意:这里一定要提前preloadEffect,不然第一次返回的id是0,这样那个音效就永远停不下来了!

分析

基于以上猜想,我们来分析下魔法球塔的逻辑:

1.对于单个的魔法球塔,由于多目标,所以要监听目标数量的变化,当target_count>0时,开始播放音效,当target_count=0时,停止播放音效.

2.卖掉塔时,如果处于攻击状态,应该调用停止播放音效.

3.对于所有的魔法球塔,音效应该采用类此引用计数的方法,每调用一次++m_uReference;,每停止一次--m_uReference;,当m_uReference==0时调用真正的停止音效方法.

总结

综上所述,我们在编写游戏音效逻辑的代码时,要注意:

1.循环音效多次播放在windows上有问题,可以考虑在android或ios端调试.

2.音效一定要preloadEffect. 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
求一个数的最短二进制表达式
工具:在线查询B站弹幕发送者
《Python编程与实践》之 聊聊hash函数与id函数
freeswitch 加密存储密码 —8000hz
Win10系统关联失效解决方法
【赏】丁恺词二首
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服