Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm sorry if I'm being stupid. I am just starting to learn Javascript and am messing around with loops. I'm currently messing about with this code:

    <!DOCTYPE html>
<html>
<body>

<button onclick="myFunction()">---</button>

<p id="hpcount"></p>
<p id="demo2"></p>

<script>
var health = 30;    
document.getElementById("hpcount").innerHTML = health;

while (health < 0){
    health = 0;
    document.getElementById("demo2").innerHTML = "Game over";
    break;
}

function myFunction() {
    if (health>0){
        health -= Math.floor(Math.random() * 10)+1;
        document.getElementById("hpcount").innerHTML = health;
    }
}

</script>

</body>
</html>

The idea is that the button subtracts a random integer 1-10 from the variable "health" as long as health is larger than 0. Then if it goes lower than that, display the "game over" message and reset health to 0. However, while the button stops working once health>0, the message just wont appear, and I just can't figure out why no matter how many times I look over the syntax and structure... Am I being stupid and missing something obvious?

share|improve this question
    
while is executed when the condition can be evaluated to true. In your case the loop is never executed. –  Teemu 19 hours ago

6 Answers 6

Change this:

while (health < 0){
    health = 0;
    document.getElementById("demo2").innerHTML = "Game over";
    break;
}

function myFunction() {
    if (health>0){
        health -= Math.floor(Math.random() * 10)+1;
        document.getElementById("hpcount").innerHTML = health;
    }
}

To this:

function myFunction() {
    // if health is above 0, game is still active
    if (health>0){
        // generate a new health value
        health -= Math.floor(Math.random() * 10)+1;

        // check if the game should end
        if (health <= 0) {
            health = 0;
            document.getElementById("demo2").innerHTML = "Game over";
        } else {
            document.getElementById("hpcount").innerHTML = health;
        }
    }
}

While you are learning Javascript, consider getting familiar with jQuery, which simplifies the use of javascript and dealing with cross-browser/device compatibility issues.

share|improve this answer

It looks like you actually want to write a loop using a named function and setTimeout

var health = 30, // initial health
    logbox = document.getElementById("demo2");

function checkHealth() {
    if (health <= 0) { // dead
        logbox.innerHTML = "Game over";
    } else { // alive
        logbox.innerHTML = "";
    }
    if (true) // set some condition so this doesn't go on forever?
        window.setTimeout(checkHealth, 500); // repeat every 500ms
}

checkHealth(); // start it running

Now when you have some change happen to health, it will be "monitored", but if lots of changes happen under (in this case) 500 ms, the code will only react to how it has ended up after the time has passed


An alternative way is to invoke a callback whenever a function modifies health, which does this check. This means you only check as it's needed, but if you have lots of changes happen in under 1 ms (think thousands or more for a PC) you may end up freezing up the browser until it's completed the functions. You also need to make sure you don't set up an infinite loop.

In this style, you would not modify health directly, but write some API, e.g.

var health = 30, // initial health
    logbox = document.getElementById("demo2");

function checkHealth() {
    // take real care if you want to call `setHealth` or `addHealth` here
    // otherwise you may end up with an infinite loop
    if (health <= 0) { // dead
        logbox.innerHTML = "Game over";
    } else { // alive
        logbox.innerHTML = "";
    }
}

function setHealth(x) {
    health = x;
    checkHealth();
}

function getHealth() {
    return health;
}

// or perhaps even
function addHealth(x) {
    health += x;
    checkHealth();
}

Now to modify health,

var x = getHealth(); // get current
setHealth(x - 3); // make change
// or
addHealth(-3);
share|improve this answer
    
This is a reasonable alternative to the technique I offered up, though in this specific case probably unnecessary. I think you should avoid using the phrase "monitored" here as it usually implies an observer-style pattern which this is definitely not, but otherwise yes, this is an important technique to understand in learning javascript. –  George Mauer 19 hours ago
    
I used quotes and further explained what I meant, but if you can think of a word which better describes what is happening than "monitored" I'd be happy to edit it –  Paul S. 19 hours ago
    
Maybe "checked" would be a better word? Don't get me wrong, I'm one of the +1s for the answer, I just wonder if we can make that one part clearer. –  George Mauer 19 hours ago

You don't need a while loop here at all. There is nothing to loop, you're doing one thing that's triggered by a click.

I took the liberty of rewriting your code to use unobtrusive javascript techniques, not expose globals, and be a bit clearer.

Here it is working

(function() {

var health = 30, 
    hpCountEl = document.getElementById("hpcount")
   ;    
document.querySelector('button').addEventListener('click', subtractHealth);
showHealth();

function showHealth() {
  hpCountEl.textContent = health;  
  if(health === 0)
    document.getElementById('demo2').textContent = "Game Over"
}
function subtractHealth() {
    if (health>0)
        health -= Math.floor(Math.random() * 10)+1;
    if(health <= 0)
      health = 0;
    showHealth()
}

})();

Something else to note - you typically do not want to put strings such as "Game Over" into javascript as it can be difficult to localize if you want to offer multiple language support. Instead you should prefer having a hidden element containing that text on the page, and simply make it visible when you need it.

share|improve this answer
    
Whilst I like unobtrusive JavaScript a lot, I think you may be using too many new concepts at once for someone just starting to learn –  Paul S. 19 hours ago
    
@PaulS. The selector cache might be a bit much, but I disagree about not introducing IIFEs and unobtrusive JS to beginners. Global state is such a huge cause of bugs, and such a weird javascript feature that I've found it's better to start with these features as a black box and let students get into how and why they work later on when they get curious. Otherwise people spend a lot of time chasing down heisenbugs (and more importantly - not learning) that really could have been avoided if we guided them into the pit of success in the first place. –  George Mauer 19 hours ago

Your while loop is being called once on initialization, evaluating to false, not being called and then never being called again.

You should move it inside myFunction as a normal if check.

share|improve this answer

This could be a variable scope problem . Try passing health as a parameter to your function .

function myFunction(health) {
    if (health>0){
        health -= Math.floor(Math.random() * 10)+1;
        document.getElementById("hpcount").innerHTML = health;
    }
share|improve this answer
    
The variable health is in the global namespace so it will be accessible within the myFunction() function. –  Haig Bedrosian 19 hours ago

I don't think you require a while loop, a simple if and else if check would do in this situation. Since you are only checking to see what the variable health is on click you would only need to check it once per click. Here is a jsfiddle of how I would do this.

  var health = 30;    
    document.getElementById("hpcount").innerHTML = health;

  function myFunction() {
     if(health <= 0) {
       health = 0;
       document.getElementById("demo2").innerHTML = "Game over";
     }
     else if (health>0){
       health -= Math.floor(Math.random() * 10)+1;
       document.getElementById("hpcount").innerHTML = health;
     }
   } 
share|improve this answer
    
FYI. This is not quite correct. The game should end when health drops below zero, so the value of health should be checked immediately after a new value is generated. The way this function is presently coded, the game won't end until after the user clicks the button again even if the health value has already dropped below zero in the prior click. –  Haig Bedrosian 19 hours ago

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.