如何用Three.js的THREE.AudioLoader实现音频源即时切换?
解决方案
问题根源
你猜的没错,问题确实出在animate函数里——它每帧都会调用sound.play(),哪怕你在changeAudio里调用了sound.stop(),下一帧animate又会重新触发原音频播放,导致新音频只能等原音频结束才会启动。
具体修复步骤
1. 限制animate中的播放触发逻辑
修改animate函数里的播放代码,只在音频未处于播放状态时才调用play(),避免每帧重复触发:
const distanceToCharacter = camera.position.distanceTo(characterPosition); if (distanceToCharacter < distanceToShow) { nearCharacter.style.display = 'block'; // 只在音频未播放时才触发播放 if (!sound.isPlaying) { sound.play(); } sound.setLoop(false); } else { nearCharacter.style.display = 'none'; characterRun.style.display = 'none'; characterPayToll.style.display = 'none'; // 离开范围时停止音频 sound.stop(); }
2. 优化changeAudio函数,确保即时切换并播放新音频
在加载新音频buffer后,立即停止当前播放、替换buffer并启动新音频,同时避免animate的干扰:
function changeAudio() { console.log('Button clicked!'); // 立即停止当前音频并重置播放位置 sound.stop(); sound.currentTime = 0; // 切换音频文件(如需来回切换,可保留判断逻辑) audioFile = audioFile === 'audio/police_officer.wav' ? 'audio/siren.wav' : 'audio/police_officer.wav'; // 加载新音频并立即播放 audioLoader.load(audioFile, function( buffer ) { sound.setBuffer( buffer ); sound.setRefDistance( 0.1 ); sound.setMaxDistance( 0.01 ); sound.setRollOffFactor( 0.1 ); // 加载完成后直接播放新音频 sound.play(); }); }
3. 可选优化:预加载所有音频(避免切换时加载延迟)
如果对话音频数量不多,建议提前预加载所有需要的buffer,切换时无需等待加载,体验更流畅:
// 预加载音频缓存 const audioBuffers = {}; const audioFiles = ['audio/police_officer.wav', 'audio/siren.wav']; // 提前加载所有音频 audioFiles.forEach(file => { audioLoader.load(file, buffer => { audioBuffers[file] = buffer; }); }); // 修改changeAudio函数,直接从缓存取buffer function changeAudio() { console.log('Button clicked!'); sound.stop(); sound.currentTime = 0; // 切换音频文件 audioFile = audioFile === 'audio/police_officer.wav' ? 'audio/siren.wav' : 'audio/police_officer.wav'; // 直接使用预加载的buffer sound.setBuffer(audioBuffers[audioFile]); sound.setRefDistance(0.1); sound.setMaxDistance(0.01); sound.setRollOffFactor(0.1); sound.play(); }
内容的提问来源于stack exchange,提问作者Daniel Rush
相关产品推荐
相关产品推荐

