How to reset a three.js watch?

I want to reset the clock, so clock.getElapsedTime() gives me a new time when I reset the clock (for example, useful when restarting the game level / scene a second time).

I start clock = new THREE.Clock(); in init() , and in my update() game loop, I use this clock. But when the game is finished, I want to reset the clock (I do not start the level again and just position the player back to the beginning, so I do not start a new clock).

How can i achieve this?

+5
source share
2 answers

The bad news is: it is not possible to reset THREE.Clock to zero time, starting with r73 , released in October 2015. An explanation is given below, and at the end of this answer you can find only possible workarounds.

Problematic design for three people. Depth research

The design of the watch is dangerous ...

- Mrdoob, Comment on the GitHub issue

To understand the flaws in THREE.Clock , we need to check the source code to see how it works. We see that in the constructor for the clock , several variables are created that first look like we can rewrite our Clock instance to reset to zero:

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

However, digging a little deeper, we need to find out when getElapsedTime() occurs. Under the hood, it calls getDelta() , which mutates this.elapsedTime , which means that getDelta and getElapsedTime are dangerous conflicting functions , but we still need to look closer at getDelta :

 var newTime = self.performance.now(); diff = 0.001 * ( newTime - this.oldTime ); this.oldTime = newTime; this.elapsedTime += diff; 

This function refers to an unknown, implicit global variable, self , and calls some odd function, self.performance.now() . Red flag! But keep digging ...

It turns out that three defines a global variable self with the property performance with the now() method in "main" Three. js file .

Returning to THREE.Clock for a moment, look how it calculates this.elapsedTime . It is based on the value returned by self.performance.now() . It seems innocent on the surface, except for the real problem. We can see that self.performance.now() creates the true "private" variable in closure, which means that no one from the outside world can see / access it

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

This start variable is the start time of the application, which is returned in milliseconds from Date.now() .

This means that when the Three.js library loads, start will be set to Date.now() . To clarify, including the Three.js script, global irreversible side effects for a timer. Looking back at the clock, we can see that the return value of self.performance.now() used to calculate the current elapsed time of the Clock . Since this is based on the closed, inaccessible "start time" of Three.js , it will always refer to when the Three.js script is included .

Workaround №1

Keep startTime = clock.getElapsedTime() at the start of the game / level and do all your calculations regarding this. Something like var currentTime = clock.getElapsedTime() - startTime , which is the only way to get the true absolute time from loading / starting your scene.

Workaround number 2

THREE.Clock under the hood is actually just a thin wrapper around Date.now() , which is an affordable IE9 + method. You are probably better off creating your own tiny abstraction around this in order to get a smart watch with an easy to use reset() method. If I find an npm package with this functionality or make my own, I will update this answer.

Workaround number 3

Wait for the Three.js THREE.Clock source code to be updated, possibly by me. Since he has an open ticket, a request for correction will most likely be accepted.

+3
source

Save time at the beginning of the game: var gameStartTime = clock.performance.now() and calculate the execution time after that by subtracting gameStartTime from clock.performance.now() at any other time in the game, including its end. For example: gameStartTime - gameStartTime will be zero, and clock.performance.now() - gameStartTime will give you seconds or minutes from the start of the game.

Here is a link to the performance.now() timer function in JavaScript.

0
source

Source: https://habr.com/ru/post/1241173/


All Articles