skip to Main Content

HelloWorld!

I’m coding a Memory Game that display the time you’re taking to finish the game.
My code provided is just a more basic Vue template of the feature I use, but it’s a fairly similar use case.
My problematics are in the comments of each functions. basically i’m encountering issues with stopping the timer and un-stoping it.

What Do I need?

  • Display the formatted time on my html since you started a click interaction represented here by the startChrono() function.
  • Automatically stop the time if you’re not interacting for a period of time OR if the game is finished.
  • Automatically resume the time if you interact again.
  • resetting the time completely in the code and the DOM.
<script setup>
import { ref } from 'vue';

const startTime = ref(0); // Initial TimeStamp
const endTime = ref(false); // Boolean to stop the Chrono
const elapsedTime = ref(0); // Chrono Time
const isGameActive = ref(false);

function startChrono() {
  /* 
  I want pauseChrono() to be used here IF the startChrono() function hasnt been called since "x" time  
  or IF the isGameActive boolean is set to false
  (auto pause if you're not clicking on the start button in other words) 
  In my mind I should use a Debounce but cant really figure how to do it properly...
  */
  isGameActive.value = true;
  startTime.value = new Date().getTime();
  endTime.value = false;
  updateChrono();
}

function pauseChrono() {
  /*
  Issue here is when you stop the pause it still uses the initial timestamp
  so the delta time is still counted instead of 
  adding the time elapsed before the pause to a new timestamp chrono time...
  */
  if (endTime.value === true) endTime.value = false;
  if (endTime.value === false) endTime.value = true;
  updateChrono();
}

function updateChrono() {
  const intervalId = setInterval(() => {
    const currentTime = new Date().getTime();
    elapsedTime.value = Math.floor((currentTime - startTime.value) / 1000);

    if (endTime.value == true) {
      clearInterval(intervalId);
    }
  }, 1000);
}

function formatTime(seconds) {
  if (seconds < 0 || seconds > 3600) {
    return;
  }
  const minutes = Math.floor(seconds / 60);
  const remainingSeconds = seconds % 60;
  if (minutes === 0) {
    return `${remainingSeconds} s`;
  } else {
    return `${minutes} min ${remainingSeconds} s`;
  }
}

function resetChrono() {
  isGameActive.value = false;
  startTime.value = 0;
  endTime.value = true;
  elapsedTime.value = 0;
  updateChrono();
}
</script>

<template>
  <main>
    <h1>
      Time:<span>{{ formatTime(elapsedTime) }}</span>
    </h1>
    <button @click="startChrono()">Start</button>
    <button @click="pauseChrono()">Pause</button>
    <button @click="resetChrono()">Reset</button>
  </main>
</template>

<style scoped>
main {
  background-color: lightslategray;
  padding: 5rem;
}
button {
  font-weight: bold;
  font-size: 18px;
  padding: 0.2rem 1rem;
  margin-right: 1rem;
  margin-block: 1rem 0;
  cursor: pointer;
}
span {
  color: rgb(2, 255, 120);
  margin-left: 1rem;
}
</style>

2

Answers


  1. Fixing the pause/unpause issue:

    To pause the timer, call clearInterval on the setInterval return value. In the code below, when the timer starts, assign the return value to a new value isRunning.

    Then in the pause function, if isRunning has a value, clearing the interval and setting isRunning back to null/undefined will pause the game. Else, unpause by calling updateChrono again (which assigns a new setTimeout value to isRunning). Also, the startTime will need to be set to the current time minus elapsed time for the timer to continue running from it’s previous value.

    const isRunning = ref(null)
    
    function updateChrono() {
      isRunning.value = setInterval(() => {
        const currentTime = new Date().getTime();
        elapsedTime.value = Math.floor((currentTime - startTime.value) / 1000);
      }, 1000);
    }
    
    function pauseChrono() {
      if (isRunning.value) { // pause
        isRunning.value = clearInterval(isRunning.value);
      } else { // unpause
        startTime.value = new Date().getTime() - elapsedTime.value * 1000;
        updateChrono();
      }
    }
    

    Vue Playground #1

    I think there are multiple ways you could handle an "idle timer"

    One basic idea would be a function that has a setTimeout function that calls pauseChrono after some X amount of time.

    const idleTimer = ref(null);
    
    function resetIdle() {
      clearTimeout(idleTimer.value);
      idleTimer.value = setTimeout(() => {
        pauseChrono();
      }, 10000); // auto-pause after 10 seconds
    }
    

    It also clears its own timer every time it’s called, restarting the countdown for as long as it continues to be called. If this function is called every time the user interacts with the game, and the user interacts more than once every X seconds, then the timer is never hit. Otherwise, the game will pause after X seconds of no interactions.

    Vue Playground #2

    Login or Signup to reply.
    1. Write Date.now(); to some variable when paused and take it into account when resumed.
    2. If you want to stop the timer through, for example, const pausedTime = 5; // pauseChrono after 5s, compare the value of elapsedTime.value when updating the timer.

    Here’s your starting point: Vue SFC Playground

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search