What is the best way to restart the clock in three.js?

I am looking for a way to reset the clock in my game so that each time I call clock.getElapsedTime(), it provides a fresh time from the moment I reset the clock. This would be particularly useful when restarting a game level or scene for the second time.

Currently, I am creating a new clock instance in the init() function, and then using this clock in the update() function of my game loop. However, once the game is over and I need to reset the clock without initializing the level again, I am faced with the challenge of achieving this.

Do you have any suggestions on how I can accomplish this task seamlessly?

Answer №1

Unfortunately, resetting the THREE.Clock to zero time is not feasible after the r73 release in October 2015. The explanation is provided below, with potential workarounds outlined towards the end of this response.

An In-Depth Analysis of the Flawed Design of Three.Clock

The design of Clock is problematic...

-- Mrdoob, GitHub issue comment

To comprehend the issues with THREE.Clock, a thorough examination of the source code is necessary. Upon inspecting the constructor of a Clock, it becomes apparent that certain variables are initialized, leading to the misconception that these can be overwritten on individual Clock instances to reset the timer to zero:

this.startTime = 0;
this.oldTime = 0;
this.elapsedTime = 0;

However, a deeper analysis reveals the implications of calling getElapsedTime(). This method internally invokes getDelta(), which alters the this.elapsedTime property. Essentially, getDelta and getElapsedTime are conflicting and risky functions, necessitating a closer examination of getDelta:

var newTime = self.performance.now();

diff = 0.001 * ( newTime - this.oldTime );
this.oldTime = newTime;
this.elapsedTime += diff;

This function notably refers to an implicit global variable, self, and invokes an unusual function, self.performance.now(). This raises concerns, prompting a more detailed investigation...

It emerges that Three.js defines the global variable self with the property performance containing the method now() as defined in the main Three.js file.

In revisiting THREE.Clock, the dependence of this.elapsedTime on the return value of self.performance.now() becomes evident. Although this might seem harmless initially, the underlying issue becomes apparent. The function self.performance.now() establishes a true "private" variable within a closure, rendering it inaccessible from external sources:

( function () {
    var start = Date.now();
    self.performance.now = function () {
        return Date.now() - start;
    }
} )();

The variable start denotes the application's start time in milliseconds, as obtained from Date.now().

Essentially, upon loading the Three.js library, start is set to the value of Date.now(). Consequently, simply including the Three.js script leads to global and irreversible impacts on the timer. The recalculated elapsed time in Clock is tied to this private "start time" linked to Three.js' inclusion, inherently relative to that moment.

Potential Solutions

Workaround #1

To address this issue, store

startTime = clock.getElapsedTime()
at the launch of your game or level, basing all subsequent calculations on this initial point. For instance, calculate the current time as
var currentTime = clock.getElapsedTime() - startTime
to accurately track the absolute time from scene load/start.

Workaround #2

Recognizing that Three.Clock essentially mirrors Date.now() in its core functionality, consider establishing a custom abstraction around this method for a more manageable clock implementation, supplemented with an easy-to-implement reset() feature. Keep an eye out for any relevant npm packages or consider creating your own solution.

Workaround #3

Stay informed about updates to the Three.js Three.Clock source code, potentially by monitoring the ongoing ticket. A future pull request aimed at resolving this issue may be considered for integration.

Answer №2

To keep track of time at the beginning of the game, use the code:

var gameStartTime = clock.performance.now()
. Then, to calculate the elapsed time during the game, simply subtract gameStartTime from clock.performance.now() at any other point in the game, including the end. For instance, gameStartTime - gameStartTime would result in zero, while
clock.performance.now() - gameStartTime
would provide the number of seconds or minutes since the game started.

For more information on the performance.now() timer function in JavaScript, refer to the link.

Answer №3

This code snippet creates a new clock object and updates the elapsedTime variable every 5 seconds without resetting the clock:

let clock = new THREE.Clock();

const updateClock = () => {
  let elapsedTime = clock.getElapsedTime();
  if (elapsedTime > 5) {
    clock = new THREE.Clock();
  }
  window.requestAnimationFrame(updateClock);
};

Answer №4

One trick I like to use for controlling the timing of my animations is a simple workaround that lets me easily start, pause, and reset the runtime.

let timeOffset = 0; // in milliseconds

let isRunning = false;

function resetTimer() {

    timeOffset = 0;    

    isRunning = false;

}

function startTimer() {
    
    if ( isRunning ) return;

    timeOffset += performance.now();    

    isRunning = true;

}

function pauseTimer() {
    
    if ( !isRunning ) return;

    timeOffset -= performance.now();    

    isRunning = false;

}

const animationRuntime = performance.now() - timeOffset;

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Retrieving values using the jQuery .each() function and passing them to an AJAX request

Is it possible to set jQuery AJAX outside of .each in the script provided below? $('#btnUpdate').click(function() { $('#result').html(''); $('.moduleIDInput').each(function() { var uid = $(this). ...

Issue with Browsersync causing task to malfunction in Gulp 4

Gulp Local v4.0.2, CLI v2.3.0 Browsersync v2.26.13 gulpfile.js: 'use strict' const gulp = require('gulp') const concat = require('gulp-concat') const babel = require('gulp-babel') const uglify ...

Fetching data from database and populating dropdown menu through Struts 2 action class with the assistance of jtable

Utilizing the jtable jQuery plugin (http://jtable.org/) in my current project has been a game-changer. It allows for the creation of AJAX based CRUD tables without the need to code HTML or JavaScript. For more details, refer to this image: The jtable cod ...

Syntax error in node/express: missing closing parenthesis after argument list

Just starting out with Node.js... const express = require('express'); const bodyParser= require('body-parser'); const MongoClient = require('mongodb').MongoClient; const app = express(); app.use(bodyParser.urlencoded({extend ...

Ways to terminate a looping function in jquery

My latest project involves creating a function that loops through a set of divs, fading in and out the next one. The challenge I'm facing is figuring out how to stop this loop upon either a click event, an if/else condition, or focus. After some resea ...

What is the best way to trigger the scrollTo function after the list (ul) with images has finished reflowing?

In my React application, I used the Material-UI List component to display images with varying dimensions and limited to a max-width of 25%. Upon loading the page, I call scrollTo({top: some-list-top-value}) on the list to position it at a specific point. ...

Is it feasible to implement different themes besides 'light' and 'dark' in React Material UI?

Currently, I am developing a user interface (UI) using React in combination with Material UI (v5+). The documentation provides information on how to utilize the extendTheme function along with CssVarsProvider to incorporate MUI colors into CSS. It also men ...

Maintaining the $index value across all pagination pages in AngularJS while matching it with the items in the data list

Is there a way to maintain the original $index numbers in my list data after pagination? For example, if data.length is 50 and they start from index 0, the first page contains 10 items ending at index 9. The next item on the second page should start at in ...

Modify the array value and access it outside of an asynchronous function

Is there a way to set values in an array from an asynchronous function and access it outside of that function's scope? I am working on a project where I need to randomize values in an array, so that I can assign images randomly to different div eleme ...

Adjusting a polyline in Google Maps

I've successfully used Google Maps V3 API to create a polyline with 2 points. However, I now need to shorten the polyline. Issue: My goal is to make the polyline extend from the start point to the midpoint between the start and end points. How can I ...

Utilizing Salesforce and DocuSign: A guide to automatically filling in the recipient of my envelope through DocuSign with the contacts from my records

In my Salesforce work, I'm currently customizing the Quote object. The default button labeled "Send with DocuSign" is already included on the Quote layout. My goal is to automatically populate the recipient of the DocuSign envelope with the contact(s) ...

Using withRouter() to redirect will display all components

I'm brand new to Reactjs and am currently diving into routing. In my journey, I stumbled upon the use of withRouter() for programmatic redirection. I had assumed the flow would follow: constructor->Willmount->render, but it seems the current or ...

Trouble with Displaying HTML Table in Bootstrap 4.3.1 Tooltip

Struggling for hours to set up a custom HTML table in a tooltip box, I finally found that the Bootstrap version solves the issue. Surprisingly, it works perfectly under Bootstrap 4.0.0 but fails under Bootstrap 4.3.1. Could this be a bug or am I overlooki ...

Having problems updating threejs while working with shaders

Currently, I am working on a 3D data visualization project where I aim to showcase a world with data integrated into it. To help guide me, I have been using the Chrome Experiments (chromeexperiments.com/globe) as a reference. One hurdle I have encountered ...

position a div element at the bottom of its parent container

I am facing a challenge with this issue: I want to position a red div at the bottom of another div. The red div should always stay at the bottom of its parent div. .homepage-wrapper{ max-width: 1028px; margin-left: auto; ...

Dealing with unhandled exceptions while passing promises into pg-promise batch transactions

Currently, I am diving into the realm of learning express and pg promise. However, during this journey, I have encountered a puzzling issue that I suspect stems from my somewhat shaky understanding of promises. Essentially, I have crafted some functions f ...

Guide on dynamically displaying a page based on the response from express/mssql middleware

I have developed a full stack application that includes a registration feature which successfully adds data to the database. Now, I am looking for a way to conditionally display the home page based on whether the login credentials are correct. Within my l ...

Combining objects while utilizing SetState within a loop: a guide

Inside my component, the state is structured as follows: class MainClass constructor(props) { super(props); this.state = { form: { startDate:"1/11/2020", endDate:"5/11/2020", .... }, ...

Adjusting the settimeout delay time during its execution

Is there a way to adjust the setTimeout delay time while it is already running? I tried using debounceTime() as an alternative, but I would like to modify the existing delay time instead of creating a new one. In the code snippet provided, the delay is se ...

Unable to locate the module '/workspace/mySQL/node_modules/faker/index.js'

Hi there, I'm currently facing an issue while trying to run the app.js file in my project through the terminal. It keeps showing me an error message that I am unable to resolve. To provide some context, I have already installed the faker package using ...