第一次写博客,好紧张哦。嘿嘿。欢迎转载与探讨!
言归正传,今天策划提了个音效需要循环播放的需求,cocos2dx引擎本来就支持循环播放音效的,但是发现在播放循环音效之后,继续添加新的音效后,之前的循环音效没声音了。果断的看源码!!跟踪发现,原来CocosDenshion.m文件里面有个_sourceGroups的玩意,它的最大size为32,即同时只能播放32个音效,如果这个时候在加进来一个新的音效怎么办呢?它会直接替换掉当前记录index的下一个index,即如果当前index为31,新的就替换第一个音效,当前index变为0,如果当前index为20,新的特效index取21,当前index也取为21。这样就能理解最开始提出的循环特效为什么播着播着就没声音了。。。
于是怎么办呢?
后来又研究了下源码,发现
CocosDenshion.m文件中,方法-(int) _getSourceIndexForSourceGroup:(int)sourceGroupId
中有这么一句注释:
while (!complete) {
//Iterate over sources looking for one that is not locked, first bit indicates if source is locked
if ((thisSourceGroup->sourceStatuses[thisSourceGroup->currentIndex] & 1) == 0) {
//This source is not locked
说明每个index中是可以指定是否有没有锁定的,如果该index锁定了,新的音效加进来就不会占用这个index。这样就好办了, 在加入音效的时候,发现如果是循环的音效,就锁定该index,找到添加音效的地方:
- (ALuint)playSound:(int) soundId sourceGroupId:(int)sourceGroupId pitch:(float) pitch pan:(float) pan gain:(float) gain loop:(BOOL) loop {
//....省略无数 找到
if((lastErrorCode_ = alGetError()) == AL_NO_ERROR)
{
//加如下2句话即可!!
[self _lockSource:sourceIndex lock:loop];
sourceGroup *thisSourceGroup = &_sourceGroups[sourceGroupId];
//Everything was okay
_sources[sourceIndex].attachedBufferId = buffer;
return source;
} else {
if (alcGetCurrentContext() == NULL) {
CDLOGINFO(@"Denshion::CDSoundEngine - posting bad OpenAL context message");
[[NSNotificationCenter defaultCenter] postNotificationName:kCDN_BadAlContext object:nil];
}
return CD_NO_SOURCE;
}
此时循环的音效便不会被替换了,不过也有新的问题。。如果循环的音效也超过32个了怎么办呢?目前我没去处理,只能说尽量去规避这个问题。
好了,最后还需要做一下移除的处理。即主动移除的时候需要把锁定的index解锁。
如下:
- (void)stopSound:(ALuint) sourceId {
if (!functioning_) {
return;
}
alSourceStop(sourceId);
alGetError();//Clear error in case we stopped any sounds that couldn't be stopped
//移除之前锁定的index
sourceGroup *thisSourceGroup = &_sourceGroups[0];
int size = thisSourceGroup->totalSources-1;
while (size>=0)
{
if(_sources[size].sourceId == sourceId)
{
[self _lockSource:size lock:NO];
break;
}
size--;
}
alGetError();//Clear error in case we stopped any sounds that couldn't be stopped
}
同理,停止全部音效时,也需要解锁:
- (void) stopAllSounds {
for (int i=0; i < sourceTotal_; i++) {
alSourceStop(_sources[i].sourceId);
//remove lock
[self _lockSource:i lock:NO];
}
alGetError();//Clear error in case we stopped any sounds that couldn't be stopped
}
测试下来后,是可行的,不过是否有其他的隐患还待考证。。。或者有其他更好的办法也说不定,只是我目前也没找到更好的办法。
当然这个只限于mac和iOS的ping平台,安卓平台会怎么样还不知道,没试过。