我使用HTML5来编写游戏;我现在遇到的障碍是如何播放音效。

具体要求不多:

播放和混合多种声音, 多次播放相同的样本,可能会重复播放, 在任何时候中断样本的回放, 最好播放WAV文件包含(低质量)原始PCM,但我可以转换这些,当然。

我的第一个方法是使用HTML5 <audio>元素并在我的页面中定义所有音效。Firefox播放WAV文件的效果很好,但是多次调用#play并不能真正地多次播放示例。根据我对HTML5规范的理解,<audio>元素还跟踪播放状态,这就解释了为什么。

我的第一个想法是克隆音频元素,所以我创建了以下小型JavaScript库来为我做这件事(依赖于jQuery):

var Snd = {
  init: function() {
    $("audio").each(function() {
      var src = this.getAttribute('src');
      if (src.substring(0, 4) !== "snd/") { return; }
      // Cut out the basename (strip directory and extension)
      var name = src.substring(4, src.length - 4);
      // Create the helper function, which clones the audio object and plays it
      var Constructor = function() {};
      Constructor.prototype = this;
      Snd[name] = function() {
        var clone = new Constructor();
        clone.play();
        // Return the cloned element, so the caller can interrupt the sound effect
        return clone;
      };
    });
  }
};

现在我可以写snd。boom();从Firebug控制台并播放snd/boom.wav,但我仍然不能多次播放相同的样本。<audio>元素似乎更像是一个流媒体功能,而不是用来播放声音效果的。

有什么聪明的方法可以做到这一点,最好只使用HTML5和JavaScript?

我还应该提一下,我的测试环境是Ubuntu 9.10上的Firefox 3.5。我尝试过的其他浏览器——Opera、Midori、Chromium、Epiphany——产生了不同的结果。有些不播放任何内容,有些则抛出异常。


当前回答

我有个主意。将某一类声音的所有音频加载到一个单独的音频元素中,其中src数据是连续音频文件中的所有样本(可能需要一些静默,这样你就可以在超时时捕捉和剪切样本,从而减少下一个样本的风险)。然后,寻找样本,并在需要时播放它。

如果你需要多个音频元素来播放,你可以用相同的src创建一个额外的音频元素,这样它就会被缓存。现在,你有效地拥有多个“轨道”。你可以利用你最喜欢的资源分配方案(如轮询等)来利用轨道组。

您还可以指定其他选项,如将声音排队到音轨中,以便在资源可用时播放或剪切当前播放的样本。

其他回答

Web音频API

编辑:截至2021年12月,Chrome、Firefox、Safari和所有其他主要浏览器(当然不包括IE)基本上都支持Web Audio API。

截至2012年7月,Web Audio API已在Chrome中得到支持,Firefox也至少部分支持,并计划在IOS 6版中添加。

尽管Audio元素足够健壮,可以通过编程方式用于基本任务,但它从未打算为游戏和其他复杂应用程序提供完整的音频支持。它的设计目的是允许在页面中嵌入单个媒体片段,类似于img标签。在游戏中使用it存在很多问题:

定时卡瓦在音频元素中很常见 每个声音实例都需要一个Audio元素 加载事件还不是完全可靠的 没有常用的音量控制,没有淡出,没有过滤器/效果

这里有一些很好的资源来开始使用Web Audio API:

MDN documentaion 从WebAudio文章开始 《FieldRunners WebAudio案例研究》也是一本不错的读物

所选答案将在除IE之外的所有程序中工作。我写了一个关于如何使它跨浏览器工作的教程。下面是我写的函数:

function playSomeSounds(soundPath) {
    var trident = !!navigator.userAgent.match(/Trident\/7.0/);
    var net = !!navigator.userAgent.match(/.NET4.0E/);
    var IE11 = trident && net
    var IEold = (navigator.userAgent.match(/MSIE/i) ? true : false);
    if (IE11 || IEold) {
        document.all.sound.src = soundPath;
    } else {
        var snd = new Audio(soundPath); // buffers automatically when created
        snd.play();
    }
}

你还需要添加以下标签到html页面:

<bgsound id="sound">

最后,你可以调用这个函数,并简单地通过这里的路径:

playSomeSounds("sounds/welcome.wav");

这里有一种方法可以同时播放相同的声音。结合预加载器,你就万事俱备了。这至少适用于Firefox 17.0.1,还没有在其他任何东西上测试过。

// collection of sounds that are playing
var playing={};
// collection of sounds
var sounds={step:"knock.ogg",throw:"swing.ogg"};

// function that is used to play sounds
function player(x)
{
    var a,b;
    b=new Date();
    a=x+b.getTime();
    playing[a]=new Audio(sounds[x]);
    // with this we prevent playing-object from becoming a memory-monster:
    playing[a].onended=function(){delete playing[a]};
    playing[a].play();
}

将此绑定到键盘键,并享受:

player("step");

我有个主意。将某一类声音的所有音频加载到一个单独的音频元素中,其中src数据是连续音频文件中的所有样本(可能需要一些静默,这样你就可以在超时时捕捉和剪切样本,从而减少下一个样本的风险)。然后,寻找样本,并在需要时播放它。

如果你需要多个音频元素来播放,你可以用相同的src创建一个额外的音频元素,这样它就会被缓存。现在,你有效地拥有多个“轨道”。你可以利用你最喜欢的资源分配方案(如轮询等)来利用轨道组。

您还可以指定其他选项,如将声音排队到音轨中,以便在资源可用时播放或剪切当前播放的样本。

你可以尝试AudioContext,它的支持有限,但它是web音频api工作草案的一部分。如果你打算在未来发布一些东西,这可能是值得的。如果你只会为chrome和Firefox编程,那你就太棒了。