Звук пропускается во время быстрого касания IOS - PullRequest
0 голосов
/ 14 апреля 2020

Я создал игру памяти с перевернутой плиткой. Последовательность плиток перевернется, показывая цвет. Пользователь должен запомнить последовательность и повторить ее. Когда пользователь выбирает правильно, проигрывается правильный Mp 3. На Iphone, если плитки выбираются быстро, звук не воспроизводится для каждого прикосновения, как будто звук пропускается для некоторых. ссылка

const elements = {
    gameContainer: $('#game-container'),
    gameMenu: $('#game-menu'),
    audioPlayer: document.querySelector('#player'),
    audioPlayer2: document.querySelector('#player2'),
    audioPlayer3: document.querySelector('#player3'),
    tiles: $('.tile'),
    correctAlert: $('#correct-alert'),
    wrongAlert: $('#wrong-alert'),
    failAlert: $('#fail-alert'),
    alertModal: $('#alert-modal'),
    stageNumber: $('.stage-number'),
    maxStageNumber: $('.max-stage-number'),
    gamemodeCheckbox: $('#gamemode-checkbox'),
    stageProgress: $('#stage-progress'),
    waitText: $('#wait-text'),
    wonAlert: $('#won'),
    goText: $('#go-text')
};

function tileClicked(tile) {
  console.dir(tile)
  // only allow clicking on tiles when game is started and game is not showing pattern
  if (!game.showing && game.started && !tile.classList.contains('flip-card-onclick')) {

    flipTile(tile);

    // check if game reached maximum number of stages i.e. game has been won
    if (game.playerMove <= game.maxStageNumber) {

      // check if current move (tile clicked) matches the tile in the generated pattern
      if (parseInt(tile.id) == game.currentGame[game.playerMove]) {
        // increase the pattern pointer
        game.playerMove++;

        // play sound when correct tile has been clicked
        elements.audioPlayer.pause();
        elements.audioPlayer.currentTime = 0;
        elements.audioPlayer.play();



        // check if we reached the end of the current pattern
        if (game.playerMove == game.currentGame.length) {
          // update the progress bar
          elements.stageProgress.css('width', `${(game.currentGame.length / game.maxStageNumber) * 100}%`);

          // show alert prompting user to go to the next stage
          elements.correctAlert.modal('show');
        }
        // current move did not match current pattern, wrong move
      } else {

        if (game.strictGamemode) {
          elements.audioPlayer2.play();
          // show fail alert and prompt to restart or exit game if strict mode has been selected
          elements.failAlert.modal('show');
        } else {
          // show wrong move alert and prompt to show pattern again
          elements.audioPlayer2.play();
          elements.wrongAlert.modal('show');
        }
      }
    }
  }
}
<!--Audio Player-->
<audio controls id="player" class="d-none">
         <source id="player-src" src="assets/audio/correct.mp3">
      </audio>
<audio controls id="player2" class="d-none">
         <source id="player-src-2" src="assets/audio/incorrect.mp3">
      </audio>
<audio controls id="player3" class="d-none">
         <source id ="player-src-3" src="assets/audio/won.mp3">
	  </audio>

1 Ответ

0 голосов
/ 14 апреля 2020

Очень сложно сказать, откуда возникла ваша ошибка, поэтому найти решение может быть не так просто. Некоторые исследования могут рассказать вам кое-что, но в противном случае есть альтернатива, которую вы можете попробовать.

API-интерфейс Web Audio - это интерфейс, позволяющий получить больший контроль над воспроизводимым звуком. Поэтому в вашем случае вместо манипулирования элементом <audio> используйте API-интерфейс Web Audio для воспроизведения ваших аудиофайлов.

Здесь я создал фрагмент, который использует этот API. В настоящее время он выбирает все ваши элементы <audio> и извлекает звук в узел, который затем можно использовать для воспроизведения звука. Это дает вам контроль над тем, как воспроизводится звук.

Таким образом, здесь создается объект, который хранится в константе sounds, в которой все имена являются ключами, а игроки - значениями. Примерно так:

const sounds {
  'correct': MediaElementAudioSourceNode,
  'incorrect': MediaElementAudioSourceNode,
  'won': MediaElementAudioSourceNode
};

Каждый из этих MediaElementAudioSourceNode - это звуки, которые можно воспроизводить. Позже в скрипте есть функция playSound, которая воспроизводит один из звуков, найденных в вашем sounds объекте.

const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioContext = new AudioContext();

const audioElements = document.querySelectorAll('audio');

const createAudioSources = audioElements => {
    const audioSources = {};
    for (const audioElement of audioElements) {
        const name = audioElement.dataset.name;
        const track = audioContext.createMediaElementSource(audioElement);
        audioSources[name] = track;
    }
    return audioSources;
};

const sounds = createAudioSources(audioElements);

function playSound(track) {
    const sound = sounds[track];
    if (sound === undefined) return;
    sound.connect(audioContext.destination);
    sound.start(audioContext.currentTime);
};

playSound('correct');
playSound('incorrect');
playSound('won');

Так что все это можно добавить над вашим оригинальным скриптом, чтобы звук файлы загружены и готовы к использованию. А затем используйте функцию playSound() в любом месте вашего скрипта, когда вы хотите воспроизвести любой из звуков. Пример ниже:

function tileClicked(tile) {
  console.dir(tile)
  // only allow clicking on tiles when game is started and game is not showing pattern
  if (!game.showing && game.started && !tile.classList.contains('flip-card-onclick')) {

    flipTile(tile);

    // check if game reached maximum number of stages i.e. game has been won
    if (game.playerMove <= game.maxStageNumber) {

      // check if current move (tile clicked) matches the tile in the generated pattern
      if (parseInt(tile.id) == game.currentGame[game.playerMove]) {
        // increase the pattern pointer
        game.playerMove++;

        // play sound when correct tile has been clicked
        playSound('correct');

        // check if we reached the end of the current pattern
        if (game.playerMove == game.currentGame.length) {
          // update the progress bar
          elements.stageProgress.css('width', `${(game.currentGame.length / game.maxStageNumber) * 100}%`);

          // show alert prompting user to go to the next stage
          elements.correctAlert.modal('show');
        }
        // current move did not match current pattern, wrong move
      } else {

        if (game.strictGamemode) {
          playSound('incorrect');
          // show fail alert and prompt to restart or exit game if strict mode has been selected
          elements.failAlert.modal('show');
        } else {
          // show wrong move alert and prompt to show pattern again
          playSound('incorrect');
          elements.wrongAlert.modal('show');
        }
      }
    }
  }
}

Кроме того, добавьте атрибут data-name к каждому элементу <audio>, чтобы JavaScript знал, как вызывать каждого игрока и сопровождающий его звук.

<audio controls id="player" class="d-none" data-name="correct">
  <source id="player-src" src="assets/audio/correct.mp3">
</audio>
<audio controls id="player2" class="d-none" data-name="incorrect">
  <source id="player-src-2" src="assets/audio/incorrect.mp3">
</audio>
<audio controls id="player3" class="d-none" data-name="won">
  <source id ="player-src-3" src="assets/audio/won.mp3">
</audio>

Весь мой код выше не протестирован и может выдать ошибку, или, что еще хуже, не имеет значения вообще. Но, по крайней мере, стоит попробовать.

...