问题
EDIT (more specific):
I have the following situation. I am building an experimental synthesizer interface with JavaScript. I am using the howler.js plugin to handle audio. The idea is that a sound is played if a certain condition is met. I have a number stored variable whose value changes via the heading of an iPhone compass. I use compass.js. It has a variable called heading.
$(function(){
Compass.watch(function (heading) {
$('.degrees').text(Math.floor(heading) + '°');
$('#rotate').css('-webkit-transform', 'rotate(' + (-heading) + 'deg)');
if (heading >= 10 && heading <= 30) {
sound.play("myFirstSound");
}
else if (heading >= 31 && heading <= 60) {
sound.play("mySecondSound");
} else { etc etc...
});
});
Even if heading is constant the .play command is executed not once but over and over again causing the audio engine to run out of memory. How can I execute the commands within the if loops only once? I can not access the value of heading outside the compass function. I always get var heading does not exist error.
回答1:
Just use a boolean variable.
var alreadyPlayed = false;
for(somecondition){
if(alreadyPlayed) continue;
sound.play("myFirstSound");
alreadyPlayed = true;
}
You get the idea.
回答2:
Take a Boolean variable like
var checkOnce= false;
if (myVariable >= 10 && myVariable <= 30) {
checkOnce=true;
sound.play("myFirstSound");
}
else if (myVariable >= 31 && myVariable <= 60) {
checkOnce=true;
sound.play("mySecondSound");
} else { etc etc...
In loop check the value of checkOnce. Loop will run till checkOnce=false
回答3:
Create a boolean flag
and play the sound only when false
.
var isPlayed = false;
var oldValue = myVariable;
if (myVariable >= 10 && myVariable <= 30 && !isPlayed) {
sound.play("myFirstSound");
isPlayed = false;
}
Then initialize variable when needed... For what you say i guess you will need a variable to compare the values inside the loop and set isPlayed
flag to false
:
if (myVariable != oldValue)
isPlayed = false;
回答4:
The boolean value is a good idea. You could also make a use of the onend
property of the sound
object, so you will know when you can start playing the sound again. Like this:
var playing = false;
sound.onend = function () { playing = false; };
while (condition) {
if (!playing & ...)
...
...
}
回答5:
Saw your edit to the question, add a delay to the next trigger, the compass might be firing too rapidly. Not familiar with compass.js but as I can see it, it fires per degree, and that is a lot... if you tilt the phone 180degrees thats 180 triggers. Something like,
setTimeout(function() { your_func(); }, 50);
for a 50ms delay
You can also limit the triggers available from 360 to 36 or less by adding a counter of 10, 1 degree is for 1 count. So it triggers only after 10 degree movement.
$(function(){
var counter = 0;
Compass.watch(function (heading) {
if(counter <=10){
counter++;
}
else{
counter = 0;
$('.degrees').text(Math.floor(heading) + '°');
$('#rotate').css('-webkit-transform', 'rotate(' + (-heading) + 'deg)');
if (heading >= 10 && heading <= 30) {
sound.play("myFirstSound");
}
else if (heading >= 31 && heading <= 60) {
sound.play("mySecondSound");
} else { etc etc...
}
});
});
回答6:
Add just a small layer of abstraction that will keep track of what's currently playing.
var nameOfSoundPlaying = null;
function play(soundName) {
if (nameOfSoundPlaying == soundName) {
return;
} else {
if (nameOfSoundPlaying != null) {
// stop currently playing sound (if still playing)
...
}
nameOfSoundPlaying = soundName;
sound.play(soundName);
}
}
Then it'll simplify your code :
$(function(){
Compass.watch(function (heading) {
$('.degrees').text(Math.floor(heading) + '°');
$('#rotate').css('-webkit-transform', 'rotate(' + (-heading) + 'deg)');
if (heading >= 10 && heading <= 30) {
play("myFirstSound");
}
else if (heading >= 31 && heading <= 60) {
play("mySecondSound");
} else { etc etc...
});
});
来源:https://stackoverflow.com/questions/28813349/how-to-execute-something-only-once-within-if-loop