1

I want to resume the game after pausing it, and it freezes the game, but after resuming, the game only gives you one key and the score is glitching between 0 and whatever score you actually have.

I tried using the clearTimeout() function to stop the function, store the timer, lives, score, and current key, however it seems to stuck on the one key I gave it.

This is the pause function:

function pause() {
    window.addEventListener("keydown", (event) => {
      if (event.key == 'Tab') {
        if (!isPaused) {
          isPaused = true;
          gameIsPlaying = false;
          window.currentKey = item
          window.currentScore = score
          window.currentTime = seconds
          window.currentLives = lives
          console.log(currentKey, currentScore, currentTime)
          clearTimeout(timerId);
          clearTimeout(updateLives);
          clearTimeout(ScoreUpdate);
          bars.forEach((bar) => {
            bar.style.animationPlayState = 'paused';
          })
          AudioElement.pause();
        } else {
          isPaused = false;
          item = currentKey
          score = currentScore
          seconds = currentTime
          lives = currentLives
          game(item, seconds, lives, score);
          bars.forEach((bar) => {
            bar.style.animationPlayState = 'running';
          })
          AudioElement.play();
        }
      }
    })
  }

JSFiddle: https://jsfiddle.net/b30osaLp/ (Tab to Pause game)

Edit: I tried @code's solution in the comments.

window.addEventListener("keydown", (event) => {
      if (event.key == 'Tab') {
        pause();
      }
  })
    function pause() {
        if (!isPaused) {
          isPaused = true;
          gameIsPlaying = false;
          clearTimeout(timerId);
          clearTimeout(updateLives);
          clearTimeout(ScoreUpdate);
          bars.forEach((bar) => {
            bar.style.animationPlayState = 'paused';
          })
          AudioElement.pause();
        } else {
          isPaused = false;
          game();
          bars.forEach((bar) => {
            bar.style.animationPlayState = 'running';
          })
          AudioElement.play();
        }
    }

But it still is producing the same issue.

13
  • 2
    This is an anti-pattern leading to memory leaks and strange behavior. You're adding an event listener each time you call the function, but the previously registered event listeners don't get removed. I think you get the idea here. Instead, you can put your event listener outside that function, then create a flag variable, e.g. isPaused, accessible in scope both by pause() and your event listener handler, then have your event listener handler check whether it's paused each time it's fired to decide whether to execute. Commented Jan 13, 2023 at 1:58
  • 1
    so in basic terms, just put the function inside the event listener? Commented Jan 13, 2023 at 2:22
  • 1
    @code how would i break the game function from the pause function? Commented Jan 13, 2023 at 13:31
  • 1
    @code i tried attempting what you told me, but it's still not working, check updated question Commented Jan 13, 2023 at 13:48
  • 2
    Looked at your fiddle code, and your entire code is a mess. There are multiple times that you add event listeners. Event listeners should be added once unless removed. So every time you call letter(), two new event listeners are added. Every time game() is called, an event listener for pause is created. You need to refactor these from the game() method. Commented Jan 13, 2023 at 14:05

2 Answers 2

1
+50

I have managed to get your code to work, although I have re-written most of it.

I have removed all the extraneous features, such as AudioElement and the animated timer. I have simplified both your HTML and CSS.

You had 3 setIntervals, I have removed the Score and Lives intervals and replaced them by updating the relevant information when it is required do so.

I have collated all your event handlers into one per event type.

And I have used some functions, namely bindElement and styleElement, to tidy the code.

So now you can pause and restart the game! (Use Q - TAB has other uses and interferes with other code on the page).

window.focus();

var paused, timerId;
var item, pickTime;
var seconds, lives, score;

const keys = ["W", "A", "S", "D", "Q", "ENTER"];

function bindElement(ref) {
  return document.getElementById(ref);
}

function styleElement(ref, clr, txt) {
  ref.style.backgroundColor = clr;
  ref.innerHTML = txt;
}

const LetterGUI = bindElement("Letter");
const TimerGUI = bindElement("Timer");
const LivesGUI = bindElement("Lives");
const ScoreGUI = bindElement("Score");
const W = bindElement("W");
const A = bindElement("A");
const S = bindElement("S");
const D = bindElement("D");
const PA = bindElement("playAgain");

document.onkeydown = function(e) {
  var key = e.key.toUpperCase();

  if (!keys.includes(key)) return;

  if (key == 'Q') {
    if (!paused) {
      paused = true;
      clearTimeout(timerId);
    } else {
      paused = false;
      timerId = setTimeout(countdown, 0);
    }
    return;
  }

  if (key == "ENTER" && PA.style.visibility == "visible") {
    game();
    return;
  }

  if (key != item) {
    lives--;
    score -= 50;
    if (lives < 1) {
      gameOver();
      return;
    }
  } else {
    var elapsed = Math.floor(Date.now() / 1000) - pickTime;
    if (elapsed < 1.5) score += 500;
    else if (elapsed < 3) score += 350;
    else if (elapsed < 5) score += 150;
  }
  ScoreGUI.innerHTML = "Score: " + score;
  LivesGUI.innerHTML = "Lives: " + lives;

  if (key == "W")
    if (key == item) styleElement(W, 'lime', '');
    else styleElement(W, 'red', '');

  if (key == "A")
    if (key == item) styleElement(A, 'lime', '');
    else styleElement(A, 'red', '');

  if (key == "S")
    if (key == item) styleElement(S, 'lime', '');
    else styleElement(S, 'red', '');

  if (key == "D")
    if (key == item) styleElement(D, 'lime', '');
    else styleElement(D, 'red', '');

  letter();
}

document.onkeyup = function(e) {
  var key = e.key.toUpperCase();
  if (key == "W") styleElement(W, 'white', 'W');
  if (key == "A") styleElement(A, 'white', 'A');
  if (key == "S") styleElement(S, 'white', 'S');
  if (key == "D") styleElement(D, 'white', 'D');
}

function letter() {
  item = keys[Math.floor(Math.random() * 4)];
  LetterGUI.innerHTML = "Letter: " + item;
  pickTime = Math.floor(Date.now() / 1000);
}

game();

function game() {
  paused = false;

  styleElement(W, 'white', 'W');
  styleElement(A, 'white', 'A');
  styleElement(S, 'white', 'S');
  styleElement(D, 'white', 'D')

  TimerGUI.style.color = "white";

  PA.style.visibility = "hidden";

  seconds = 20;
  lives = 3;
  score = 0;
  letter();
  ScoreGUI.innerHTML = "Score: " + score;
  LivesGUI.innerHTML = "Lives: " + lives;
  timerId = setTimeout(countdown, 0);
}

function countdown() {
  seconds--;
  if (seconds < 0) {
    gameOver();
    return;
  }
  if (seconds <= 5) TimerGUI.style.color = "red";
  if (seconds > 9) TimerGUI.innerHTML = "Time: " + seconds;
  else TimerGUI.innerHTML = "Time: 0" + seconds;
  timerId = setTimeout(countdown, 1000);
}

function gameOver() {
  clearTimeout(timerId);

  styleElement(W, 'red', '');
  styleElement(A, 'red', '');
  styleElement(S, 'red', '');
  styleElement(D, 'red', '')

  LetterGUI.innerHTML = "";
  TimerGUI.innerHTML = "";
  ScoreGUI.innerHTML = "Score: " + score;
  LivesGUI.innerHTML = "Lives: " + lives;

  PA.style.visibility = "visible";
}
body {
  background-color: #abcdef
}

.info {
  color: white;
  font-size: 18px
}

.letter {
  height: 50px;
  width: 50px;
  text-align: center
}

.center {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 0;
  bottom: 100px;
  left: 0;
  right: 0
}

.footer {
  position: fixed;
  text-align: center;
  bottom: 0px;
  width: 100%;
  font-size: 22px;
  color: green;
  font-family: "Courier New"
}
<div id="Letter" class="info"></div>
<div id="Lives" class="info"></div>
<div id="Score" class="info"></div>
<div id="Timer" class="info"></div>
<table class="center">
  <tr>
    <td></td>
    <td id="W" class="letter"></td>
    <td></td>
  </tr>
  <tr>
    <td id="A" class="letter"></td>
    <td id="S" class="letter"></td>
    <td id="D" class="letter"></td>
  </tr>
</table>
<span id="playAgain" class="footer">Press [Enter] to restart</span>

Sign up to request clarification or add additional context in comments.

1 Comment

tysm so much, i wish it was it was before but the code is so much cleaner and actually works properly.
0

Are you sure you intended to start the game with setInterval(resetGame, 0)?

That would repeatedly reset the game, every 0 ms.

Perhaps you meant to start it after a 0 ms timeout, i.e. once the interpreter became next free:

setTimeout(resetGame, 0);

When I change it in your fiddle, it seems to work as expected.

3 Comments

@gamer merch, If this worked, remember to mark this answer as accepted. 8-)
so if i make this simple change, i can pause and restart from where i left at without any issues? (I'll test it out later)
this solution didn't work, it doesn't really change anything at all.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.