Button won't respond when execute the setInterval function - javascript

I would like to have the second button ( "free five") to keep checking the condition that it would reappear when the number reached 5 again after I clicked it. However, it never showed up again after I pressed it, unless I press the first button.
Game instruction is in the p section.
let birdNum = document.getElementById("birdNum")
let catchBtn = document.getElementById("catch")
let freeBtn = document.getElementById("free")
function catchBird() {
birdNum.innerHTML++;
if (birdNum.innerHTML > 4) {
freeBtn.classList.add("fadeIn");
freeBtn.disabled = false;
}
}
document.getElementById("catch").addEventListener("click", catchBird);
function freeBird() {
birdNum.innerHTML -= 5;
setInterval(() => {
birdNum.innerHTML++;
}, 1000);
if (birdNum.innerHTML <= 4) {
freeBtn.classList.remove("fadeIn");
freeBtn.disabled = true;
}
}
document.getElementById("free").addEventListener("click", freeBird);
#free {
opacity: 0;
}
#free.fadeIn {
opacity: 1;
}
<P>
press "catch one" to catch one bird. <br> press "free five" to free five bird. <br>
<br> Once you free five birds, they will come back with their kids, one bird per second.
</P>
<span id="birdNum">0</span>
<button id="catch">
catch one
</button>
<button id="free" disabled=t rue>
free five
</button>

Try the following code, see if it works for you:
Edit: I realised your issue, I edited to work now.
So in your code, you were only checking whether or not to make the 'free' button visible once. And you only checked when it was pressed. For example, we are playing your game and get to 6. We press the 'free birds' button and we go down to one and the 'free birds' button disappears. Now the setInterval keeps making the number of birds go up. We get to 5 and the button does not reappear because we are not running any code to make it reappear. In the setInterval, as well as incrementing the counter, we need to check whether or not we can make the 'free birds' button visible again. See the resetInterval() function. In the setInterval's callback, we are now checking whether of not the birds counter is above 5. If the condition returns true, we will show the 'free birds' button.
With the below JS, it should work nicely.
const birdNum = document.getElementById("birdNum");
const catchBtn = document.getElementById("catch");
const freeBtn = document.getElementById("free");
const initialTimeout = 1000;
let timesBirdsFreed = 0;
let intervalId;
function resetInterval(delay) {
if (delay < 10) delay = 10;
if (intervalId) clearInterval(intervalId);
intervalId = setInterval(() => {
birdNum.innerHTML++;
// if statement from catch bird function is needed here too
if (birdNum.innerHTML >= 5) {
freeBtn.classList.add("fadeIn");
freeBtn.disabled = false;
}
}, delay);
}
function catchBird() {
birdNum.innerHTML++;
if (birdNum.innerHTML >= 5) {
freeBtn.classList.add("fadeIn");
freeBtn.disabled = false;
}
}
catchBtn.addEventListener("click", catchBird);
function freeBird() {
timesBirdsFreed++;
birdNum.innerHTML -= 5;
resetInterval(initialTimeout/timesBirdsFreed);
if (birdNum.innerHTML <= 4) {
freeBtn.classList.remove("fadeIn");
freeBtn.disabled = true;
}
}
freeBtn.addEventListener("click", freeBird);
#free {
opacity: 0;
}
#free.fadeIn {
opacity: 1;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Bird Game</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<p>press "catch one" to catch one bird. <br> press "free five" to free five bird. <br><br> Once you free five birds, they will come back with their kids, one bird per second.</p>
<span id="birdNum">0</span>
<button id="catch">catch one</button>
<button id="free" disabled=true>free five</button>
<script src="script.js"></script>
</body>
</html>
Edit 2: Further explanation and added links to setInterval() method and clearInterval() method.
function resetInterval(delay) {
// if delay is too small (less than 10 ms) make delay 10 ms
if (delay < 10) delay = 10;
// in beginning of the program, intervalId is undefined
// so we will only use clearInterval if intervalId is not undefined (if we've used setInterval already)
if (intervalId) clearInterval(intervalId);
// use setInterval method with a delay which was passed to the function as an argument
intervalId = setInterval(() => {
// make birds go up by one
birdNum.innerHTML++;
// if statement from catch bird function is needed here too
// (if birds counter is 5 or more, show 'free birds' button)
if (birdNum.innerHTML >= 5) {
freeBtn.classList.add("fadeIn");
freeBtn.disabled = false;
}
}, delay);
// all of this resets the interval but at a smaller delay so birds go up faster each time
}
The resetInterval() function just stops an existing setInterval() from executing code by using clearInterval(intervalId) which uses the ID returned when setInterval() when it was called. An ID can be, for example, 239 or maybe 146. After the existing setInterval() was cleared, another setInterval() is called and its ID is stored in the variable (intervalId) to be used to clear the new setInterval() the next time resetInterval() is called (the next time you free five birds). The difference though is with each call of the resetInterval() function, the setInterval's delay which was passed into the function is smaller, making the number of birds go up faster.
The way this is done is when the resetInterval function is called, a delay is passed into the function as a parameter like so resetInterval(initialTimeout/timesBirdsFreed). initialTimeout is set to always be 1000 (milliseconds). timesBirdsFreed is a number which tells you how many times you clicked the 'free birds' button. If you clicked 'free birds' once, initialTimeout/timesBirdsFreed will be 1000/1 which is 1000 (ms). So the first time you clicked 'free birds', the number of birds will go up by one bird every second. The second time you click 'free birds', initialTimeout/timesBirdsFreed will be 1000/2 which is 500 (ms), meaning now birds will go up by one every half a second.
Because of this, the more you click 'free birds', the faster they will go up (up to a limit - smallest delay possible is 10ms, so it won't go any faster than that).
References
MDN Web Docs
setInterval() method
W3Schools
setInterval() method
clearInterval() method

If you need to stop the setInterval you should keep its instance and then call clearInterval(instance)
I'm not sure what you want to achieve but you may get the idea from the this code:
let intervalInstance;
function freeBird() {
birdNum.innerHTML -= 5;
if (intervalInstance) {
clearInterval(intervalInstance);
}
intervalInstance = setInterval(() => {
birdNum.innerHTML++;
}, 1000);
if (birdNum.innerHTML <= 4) {
freeBtn.classList.remove("fadeIn");
freeBtn.disabled = true;
}
}

Related

How do I make a countdown feature in a button in HTML5

I am creating a clicker-like game in HTML5+Javascript and for the clicking part, there is a timeout... I tried it my self but for some reason it does not work.
HTML:
function pursuit() {
var btn = document.getElementById("pursuit");
setInterval(function(){
timeOnPursuit -= 1;
}, 1000)
while(timeOnPursuit > 0){
btn.value = "In Pursuit: " + timeOnPursuit;
}
}
<div class="button">
<button id="pursuit" class="pursuit" onClick="pursuit()"> Go on a Pursuit </button>
</div>
A few things to consider here...
First, the code is producing an error in the browser console. You never defined the timeOnPursuit variable, so you aren't really controlling its scope. Simply declare that variable with an initial value (whatever value you like) before trying to use it:
var timeOnPursuit = 10;
Aside from that, your loop is going to block the thread. Because the variable is initially greater than 0, and because nothing in that loop modifies that value, it's going to run forever and never let the interval get a chance to modify the value.
Get rid of the loop entirely and rely on the interval instead. Within the interval you can update the UI. (Which, incidentally, should probably be innerText instead of value in this case.) Then within that interval you can also check when to stop the interval, which is what I suspect you were trying to do with the loop.
For a bonus, you might also want to disable the button so the user can't click it again, which would create another counter.
Overall, maybe something like this:
function pursuit() {
var btn = document.getElementById("pursuit");
// Start the "pursuit"
var timeOnPursuit = 10;
btn.innerText = "In Pursuit: " + timeOnPursuit;
btn.disabled = true;
// Repeat every second
var interval = setInterval(function(){
// Update the "pursuit"
timeOnPursuit -= 1;
btn.innerText = "In Pursuit: " + timeOnPursuit;
// Stop the interval at 0
if (timeOnPursuit <= 0) {
clearInterval(interval);
}
}, 1000)
}
<div class="button">
<button id="pursuit" class="pursuit" onClick="pursuit()"> Go on a Pursuit </button>
</div>
function pursuit() {
let timeOnPursuit = 10 // define time
var btn = document.getElementById("pursuit");
const timer = setInterval(function() {
console.log(timeOnPursuit)
if (timeOnPursuit > 0) {
btn.innerHTML = "In Pursuit: " + timeOnPursuit;
timeOnPursuit -= 1; // reduce time
} else {
btn.innerHTML = "Pursuit";
clearInterval(timer) // stop the timer
}
}, 1000)
}
<div class="button">
<button id="pursuit" class="pursuit" onClick="pursuit()"> Go on a Pursuit </button>
</div>
I was going to write a lot of what David wrote so it seems a little redundant now. Instead here's an alternative approach that uses setTimeout instead of setInterval.
// Cache the element and add a click listener to it
// (no need for inline JS)
const btn = document.querySelector(".pursuit");
btn.addEventListener('click', pursuit, false);
function pursuit() {
// Initialise timeOnPursuit
function loop(timeOnPursuit = 10) {
// Display the button text, and disable the button
btn.innerText = `In Pursuit: ${timeOnPursuit}`;
btn.disabled = true;
// If timeOnPursuit is greater than zero
// call loop again with a a decremented timeOnPursuit
if (timeOnPursuit > 0) {
setTimeout(loop, 1000, --timeOnPursuit);
}
}
// Call the loop function
loop();
}
<div class="button">
<button class="pursuit"> Go on a Pursuit </button>
</div>

How to reset game score and button text

I'm making a whack a mole game for a school project and I've gotten the actual game to work, however I'm having an issue resetting the game once the 30 second timer runs out. The game is made with javascript and p5.js and as of right now when you load the page, the game div display is set to hidden, but when you click "begin" the display changes to block and the timer starts (the game is on github for reference https://abm96testgithub.github.io/whackamole/). When the 30 seconds are up, the "begin" button changes to "reset" and the game display goes back to "none" (both done using document.getElementByID).
Is there a way to make it so that when the player hits "reset" the entire page will reload or so that the button will read "begin" again and the score will reset?
I know I can make a separate reset button with a function for this, but I feel like it would mess up the aesthetic of the page to have two buttons.
The html for the button when the page first loads is
<button id="startButton" onclick="startGame();startTimer()">Begin!</button>
and the javascript for it is
function startGame() {
document.getElementById('sketch-holder').style.display = "block";
}
function countdown () {
var startCountdown = setInterval(function() {
document.getElementById('timerVar').innerHTML = counter + "s";
counter--;
if (counter < 0) {
clearInterval(startCountdown);
document.getElementById('sketch-holder').style.display = "none";
document.getElementById('startButton').innerHTML = "Reset";
}
}, 1000)
}
function startTimer() {
if (timerOn === false) {
timerOn = true;
countdown();
}
}
It's a little strange to use setInterval() when you're using P5.js. P5.js has its own internal timing mechanisms, which we talked about in your last question.
Instead of using setInterval(), I'd use the millis() function or the frameCount variable to perform timing logic. See my code in my answer to your last question:
function setup() {
createCanvas(200,200);
background(32);
}
function draw(){
// 60 frames is 1 second
if(frameCount % 60 == 0){
ellipse(random(width), random(height), 25, 25);
}
}
This code draws a circle once per second. This is just an example, but you could do something very similar to reset your game after 30 seconds.
Then to reset your game, all you really need to do is set any variables you're using back to their default values. Try writing a reset() function that does exactly that.
If I understood right, Instead of Button You can go witha a tag with void href then on click you can add href="javascript:window.location.href=window.location.href" which will reload the page.
function startGame() {
document.getElementById('sketch-holder').style.display = "block";
}
function countdown () {
var startCountdown = setInterval(function(){
document.getElementById('timerVar').innerHTML = counter + "s";
counter--;
if (counter < 0) {
clearInterval(startCountdown);
document.getElementById('sketch-holder').style.display = "none";
document.getElementById('startButton').innerHTML = "Reset";
document.getElementById('startButton').setAttribute("href", 'javascript:window.location.href=window.location.href"');
}
}, 1000)
}
function startTimer() {
if (timerOn === false) {
timerOn = true;
countdown();
}
}
Begin!

JavaScript page update while a script is running

I have a web page that does a lot of calculations as part of it's loading.
I want to display a spinner bar while the page is "thinking" so that the end user knows the delay is to be expected.
The way I was going to do this is to display a GIF file that would be a spinning wheel, and hide the table that would be my output.
The problem is, once the function starts, updates to the page seem to freeze until the function is done. Therefore, the end user never sees the "In Process" section.
The sample code I put together to demonstrate my problem is:
<!DOCTYPE html>
<html>
<body>
<script>
function show(id, value) {
document.getElementById(id).style.display = value ? 'block' : 'none';
}
function Processing(x)
{
if (x === true)
{
show('page', false);
show('loading', true);
}
else
{
show('page', true);
show('loading', false);
}
}
function MainProcess()
{
Processing(true) // Set to "Show processing..."
var start = new Date().getTime(); // Sleep a few seconds
for (var i = 0; i < 5; i++) {
if ((new Date().getTime() - start) < 3000) { i = 1 }
}
Processing(false) // Set to "Show Completed processing..."
}
window.onload = function() {
show('page', false);
show('loading', false);
};
</script>
<div id="loading">
<h1>Processing your request.</h1>
</div>
<div id="page">
<DIV class="body">
<h3>Done Processing your request.</h3>
</DIV>
</div>
<div id="buttons">
<button onclick="MainProcess();">Start Timer</button>
<button onclick="Processing(false);">Set to Completed</button>
<button onclick="Processing(true);">Set to Processing</button>
</body>
</html>
When I run this, it presents three buttons.
When you hit "Start Timer", it should show processing for a few seconds, then display done. Instead, the button changes colors and otherwise appears to do nothing till the timer is done, and it displays complete.
(I am new to JavaScript but a seasoned pro in several other languages. Is there a "DoEvents" type of call I can make like in Visual Basic or Powershell?)
The problem seems to be that the DOM update (i.e. changing the display properties on your DIVs) doesn't complete before your processing function starts. One option would be to use window.setTimeout to delay the start of your processing function to allow the DOM update to complete:
function MainProcess()
{
Processing(true); // Set to "Show processing..."
// Pause for 100 ms before starting time-consuming code to allow dom update to c
var domUpdateDelay = 100;
window.setTimeout(function() {
var start = new Date().getTime(); // Sleep a few seconds
for (var i = 0; i < 5; i++) {
if ((new Date().getTime() - start) < 3000) { i = 1 }
}
Processing(false) // Set to "Show Completed processing..."
}, 100);
}
window.setTimeout takes two arguments: the first argument is a function that runs after x milliseconds, where x is the second argument.
The problem with this approach is that an appropriate delay for setTimeout will vary across machines/users/browsers/runs. However, my guess is that this will probably not be an issue in 99% of cases.
I think you can take advantage of a function like setTimeout (https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout), say:
setTimeout(function() {
Processing(false);
}, 5000);
I think what's happening is you're nearly crashing the browser with that loop. I may have misunderstood what parts of your question were just there for demonstration purposes.

javascript, timeout, button, movement.

I've only been working with javascript for the past 3 days and I have an assignment to do. (Don't ask me why they're making me create a game on my first js assignment) I've made this game you can view it here http://nwdevelopment.host56.com/game.html
How it should work: Click the start button, then the start button goes away and the animation starts on the character. Timer will still go until 30 seconds are up. (1 second currently for testing purposes) Game ends and displays amounts of clicks in pop up ( + 50 to win). Start button comes back up and you can play again.
The problem i'm having is:
1: I need to make the button go away when clicked, but still continue to count down until the end of the game but come back up when the game ends. Where can I learn to do this? Direct me to a site or show me please.
2: During all of this, when you press start game, i need Ganon to move around slowly while you click on him and the score goes up. I got the score to go up but I can't get him to move and I'm not even sure where to start. Also, when you click on him I need it to move 10 pixels randomly on the screen.
I need this in the simplest form you can give me with javascript. Can you point me in the right direction for tutorials or something? Here is the code so far, sorry the CSS and scripts are in one file currently. (leaving out the CSS as i don't think you need it.)
<div id="textWrapper">
<h1>Try to Defeat<br /> Ganon!</h1>
<p class="description">Click on Ganon and watch your score rise! If you hit Ganon enough times before the time runs out, you win!</p>
<ul>
<li>Home</li>
<li>UNIT3A</li>
<li>UNIT3B</li>
<li>Game</li>
</ul>
<br />
<!-- Counter -->
<div id="numberCounter">
<p>0</p>
</div>
</div>
<div id="backgroundImageWrapper">
<div id="ganonWrapper">
<img src="ganon.png" alt="ganon" onclick="myFunction()"/>
</div>
<div id="buttonWrapper">
<button id="button" onclick="myTimer()">Start Game</button>
</div>
</div>
<!-- START JAVASCRIPT -->
<script>
var counter = 0;
function add() {
return counter += 1;
}
function myFunction(){
document.getElementById("numberCounter").innerHTML = add();
}
function myTimer() {
setTimeout(function(){ alert("Game over!"); }, 1000);
}
</script>
Maybe this little fiddle can help you get the timer things to work.
http://jsfiddle.net/2zfdLf0q/2/
// lets put everything in our game object
var game = {
//this is the init function (we call this function on page load (see last line))
init: function(){
//we attach a click event on the button
document.getElementById('start').addEventListener('click', function(){
//we hide the button
document.getElementById('start').style.display = "none";
//on click we start the timer
game.timer.start();
});
},
//this is the timer object
timer: {
startTime: 5, //the time we start with (used to reset)
currentTime: 5, //the counter used to remember where the counter is
interval: null, //the interval object is stored here so we can stop it later
start: function(){
//when we start the timer we set an interval to execute every 1000 miliseconds
game.timer.interval = setInterval(function(){
game.timer.currentTime -= 1; //we minus 1 every second to the timer current time
//update the textbox to show the user what the time is
document.getElementById('counter').value = game.timer.currentTime + ' seconds';
//if timer hits 0 we show the game is over and reset the game, we also clear the timer
//so it wouldn't count below zero
if(game.timer.currentTime == 0){
alert('game over');
game.reset();
clearTimeout(game.timer.interval);
}
},1000);
}
},
//this is the reset function
reset: function(){
document.getElementById('start').style.display = 'inline-block';
game.timer.currentTime = game.timer.startTime;
document.getElementById('counter').value = game.timer.currentTime + ' seconds';
}
}
//we start the game on page load
//you should wrap this in
//window.onload = function(){}
//but jsFiddle does this automaticly
game.init();

Count the number of mouse clicks in one second

Hi I'm working on an application that I want to improve the performance.(I know the question is kinda lengthy one- I apologize.)
I will explain in detail its a bidding application that uses only qtscript/qscript(kinda javascript) and no html.
When a user click on a Button, I want to point to a text field(For a normal user its okay like -1 or 2 clicks per second). But the user crazily click on button(5 -10 clicks per second - yeah some people click like that), it decreases the performance like the amount take delay to display because every click it points to focus on text field.
I'm thinking of some work around like if the user clicks more than 3 times in 1 second we call the focus function only after the last click- I don't know this is a right solution if you guys know anything better please suggest. Another problem is I can't use setInterval() and clearInterval().
Any help would be greatly appreciated.
I would take a look at Underscore.js's _.throttle function.
_.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
var previous = 0;
options || (options = {});
var later = function() {
previous = options.leading === false ? 0 : new Date;
timeout = null;
result = func.apply(context, args);
};
return function() {
var now = new Date;
if (!previous && options.leading === false) previous = now;
var remaining = wait - (now - previous);
context = this;
args = arguments;
if (remaining <= 0) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};
It looks really complex, but a basic example would be:
var func = function(){alert("Only do this once every second");},
throttled = _.throttle(func, 1000);
// Call func() three times in under a second, and
// you get 3 message boxes
func(); // alerts
func(); // alerts
func(); // alerts
// Call throttled() three times in under a second, and
// you only get a message box the first time
func(); // alerts
throttled(); // does nothing
throttled(); // does nothing
// ... wait >1 second ...
func(); // alerts
throttled(); // does nothing
throttled(); // does nothing
example.xhtml - No frameworks, no script elements in the body and counts both left and right clicks.
Additionally you can add e.preventDefault(); at the end of the anonymous onclick event function. Keep in mind that if you're trying to protect content you will ultimately fail against anyone smart enough to realize that if it's already on their computer (memory, cache, etc) that they already have it in their possession. If you're trying to protect images you must use watermarks.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>Click Counter</title>
<script type="application/javascript">
//<![CDATA[
var click_left = 0;
var click_right = 0;
window.onclick = function(e)
{
if (e.which==1) {click_left++;}
else if (e.which==3) {click_right++;}
alert('Left clicks: '+click_left+'\n\nRight Clicks: '+click_right);
}
//]]>
</script>
</head>
<body>
<div><p>Left or right click</p></div>
</body>
</html>
First of all you should add check that the text edit you want to select after user clicked certain button already has focus. That will dramatically reduce loading on event queue.
Second you can implement your own button (by subclassing) and play around with options, like for example just ignore clicks which came within certain (small) interval. In case user starts spawning clicks very fast, you can also 'visualise' it on a button in certain way, showing to a user that your application had limit reactions on user input, switching it off after specified timeout.

Categories