What does date.now() 'then' does here? - Javascript - javascript

I've used this tutorial to help me out writing a simple JS game for my school assignment. However I am now looking at the gameloop and I have no clue how this particular function is working.
Here is the URL of the tutorial. The block of code you're looking for is at 8 "The main game loop"
http://www.lostdecadegames.com/how-to-make-a-simple-html5-canvas-game/
//Gameloop
var main = function () {
//var with timestamp
var now = Date.now();
//where does 'then' come from? I never declared it.
var delta = now - then;
//next up it just calls another func and provides parameter delta divided by 1000 which is the amount of miliseconds in a second
update(delta / 1000);
//and it calls my render function
render();
//then it sets then back to Date.now()
then = now;
//No idea what this line does. still looking into it
requestAnimationFrame(main);
};

I will try to explain what I understood from the code in the tutorial.
A game often runs in a fixed framerate, like 60 frames per seconds (FPS).
In the tutorial, that is not the case.
Instead of having a fixed framerate and moving the character at a fixed distance in the update function, you have a delta variable used to calculate the distance.
hero.y -= hero.speed * modifier; // modifier is (delta / 1000)
Like the other answers said, then is set in the beginning, in the outer scope of the main function.
// Let's play this game!
var then = Date.now();
reset();
main();
I will add that the tutorial is a little old (2011) and some details can be improved. For example, you can use performance.now() instead of Date.now() as reported by lighthouse.

Read Start Game Number 10:
// Let's play this game!
var then = Date.now();
reset();
main();
The following description also:
"Almost there, this is the last code snippet! First we we set our timestamp (with the variable then) to seed it. Then we call reset to start a new game/level."

Related

How to reset three.js clock?

I want to reset the clock so that clock.getElapsedTime() gives me a new time from when I reset the clock (for example, useful when restarting a game level/scene the second time).
I am initiating clock = new THREE.Clock(); in init(), and in my game loop update(), I am using this clock. But when the game is over, I want to reset the clock (I am not initiating the level again and am just positioning the player back to the beginning so I am not initiating a new clock).
How can I achieve this?
Bad news: It's impossible to reset the THREE.Clock to zero time, as of r73, released Oct 2015. The explanation is below, and the only possible workarounds are at the end of this answer.
The Problematic Design of Three.Clock Investigated in Depth
The design of Clock is dangerous...
-- Mrdoob, GitHub issue comment
To understand the flaw(s) in THREE.Clock we must inspect the source code to see how it works. We can see that in the constructor for a Clock, a few variables are instantiated, which at first glace looks like we can overwrite on our Clock instance to reset to zero:
this.startTime = 0;
this.oldTime = 0;
this.elapsedTime = 0;
However, digging a little deeper, we need to figure out happens when getElapsedTime() is called. 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 is referencing some unknown, implicit global variable, self, and calling some odd function, self.performance.now(). Red flag! But let's keep digging...
It turns out Three defines a global variable, self, with a property performance with a method now() in the "main" Three.js file.
Stepping back to THREE.Clock for a moment, look how it calculates this.elapsedTime. It's based on the value returned by self.performance.now(). That seems innocent enough on the surface, except the true problem arises here. We can see that self.performance.now() creates a true "private" variable in a closure, meaning no one in the outside world can ever 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 app, as returned in milliseconds from Date.now().
That means that when the Three.js library loads, start will get set to the value Date.now(). To clarify, simply including the Three.js script has global, irreversible side effects for the timer. Looking back on the clock, we can see that the return value of self.performance.now() is used to calculate the current elapsed time of a Clock. Because this is based on the private, inaccessible "start time" of Three.js, it will always be relative to when you include the Three.js script.
Workaround #1
Store startTime = clock.getElapsedTime() on your game/level start and making all your calculations relative to that. Something like var currentTime = clock.getElapsedTime() - startTime which is the only way to get the true absolute time from your scene load / start.
Workaround #2
Three.Clock under the hood is really just a thin wrapper around Date.now(), which is an IE9+ available method. You're probably better off creating your own tiny abstraction around this to get a sane clock, with an easy to implement reset() method. If I find an npm package with this functionality, or make my own, I will update this answer.
Workaround #3
Wait for the Three.js Three.Clock source code to be updated, possibly by me. Since there is an open ticket for it, a pull request to fix it will likely be accepted.
Save the time at the start of the game: var gameStartTime = clock.performance.now(), and calculate the run of time thereafter by subtracting gameStartTime from clock.performance.now() at any other point during the game, including its end. For example: gameStartTime - gameStartTime would equal zero, and clock.performance.now() - gameStartTime would give you the seconds or minutes since the game began.
Here's a reference to the performance.now() timer function in JavaScript.
This will not reset the clock but it will generate a new clock object and assign the new value to the elapsedTime variable every 5 seconds:
let clock = new THREE.Clock();
const animate = () => {
let elapsedTime = clock.getElapsedTime();
if (elapsedTime > 5) {
clock = new THREE.Clock();
}
window.requestAnimationFrame(animate);
};
Here is simple workaround I use to start pause and reset the runtime of my animation systems.
let offsetTime = 0; // in milliseconds
let start = false;
function reset() {
offsetTime = 0;
start = false;
}
function start() {
if ( start ) return;
offsetTime += performance.now();
start = true;
}
function pause() {
if ( start ) return;
offsetTime -= performance.now();
start = false;
}
const animationRuntime = performance.now() - offsetTime;

Three.js / ShaderParticleEngine — SPE.Group.tick bad delta argument?

I'm using the ShaderParticleEngine library for Three.js to create particle emitters.
I picked several code snippets on the Internet to have a working emitter.
Firstly I believed that is wasn't working.
But in fact, the emitter was displayed on the map, but a single motionless particle was on the screen.
After some debugging I undestood that the particle was moving but infinitely slowly. I need to use tick(delta * 1000) to see the emitter in action. And the result is quite ugly (full of gaps, alone particles).I have no problem of low FPS.
The only solution I found is to remove delta argument in the tick function call: particleGroup.tick().
The result is better but is still deceiving, judge by yourself:
Online Emitter Editor:
My result:
I can't understand. I use the same code proposed in the library examples and I use the export feature in the emitter editor.
If I try other variations (eg. on particle life/velocity) I get a very different result in my game, maybe the particle life is not computed correctly because delta argument isn't given?
My game loop:
var animate = function () {
requestAnimationFrame( animate );
render();
stats.update();
};
var render = function() {
time = ctx3d.clock.getElapsedTime();
delta = ctx3d.clock.getDelta();
particleGroup.tick(delta);
if(ctx3d.move)
{
ctx3d.ship.position.z += delta * 500 * 3000;
//ctx3d.camera.position.x = ctx3d.ship.position.x;
//ctx3d.camera.position.z = ctx3d.ship.position.z;
}
ctx3d.renderer.render(ctx3d.scene, ctx3d.camera);
}
Delta value loop by loop:
30.0000010000003385357559
9.999985195463523e-7
30.0000020000006770715117
0.0000010000003385357559
30.0000020000006770715117
0.0000010000003385357559
0.0000020000006770715117
30.0000010000003385357559
0.000002999999196617864
0.0000010000003385357559
9.999985195463523e-7
0.000002999999196617864
0.0000010000003385357559
0.000001999998858082108
0.0000010000003385357559
20.0000020000006770715117
9.999985195463523e-7
0.0000010000003385357559
To solve smoothness, try the following:
function makeSmoothSPETick(simulator, timeDelta, maxSubstepSize){
var numSubsteps = Math.floor(timeDelta/maxSubstepSize);
var leftOverTime = timeDelta%maxSubstepSize;
while(numSubsteps-->0){
simulator.tick(maxSubstepSize);
}
if(leftOverTime> 0){
//handle the rest
simulator.tick(leftOverTime);
}
}
If you use this function in your code - it will allow you to essentially subdivide steps that are too large into smaller ones of fixed size. As SquareFeet pointed out, say 16ms for 60FPS - you could use something like this:
var render = function() {
time = ctx3d.clock.getElapsedTime();
delta = ctx3d.clock.getDelta();
makeSmoothSPETick(particleGroup, delta, 0.016);
if(ctx3d.move)
{
ctx3d.ship.position.z += delta * 500 * 3000;
//ctx3d.camera.position.x = ctx3d.ship.position.x;
//ctx3d.camera.position.z = ctx3d.ship.position.z;
}
ctx3d.renderer.render(ctx3d.scene, ctx3d.camera);
}
You should get results visually similar to what you'd expect if you were running at smooth 60fps. Beware though, if target hardware can't handle these substeps - you may need to get more logic into your solver algorithm. I'd suggest keeping statistics for past 100 frames or so, and using that to decide how much you can split your incoming step value.
EDIT:
To make sure your timing isn't getting mangled, please try the following:
var lastFrameTime = Date.now()/1000;
var animate = function () {
requestAnimationFrame( animate );
render();
stats.update();
};
var render = function() {
time = Date.now()/1000; //getting current time in seconds since epoch
delta = time-lastFrameTime;
lastFrameTime = time;
particleGroup.tick(delta);
if(ctx3d.move)
{
ctx3d.ship.position.z += delta * 500 * 3000;
//ctx3d.camera.position.x = ctx3d.ship.position.x;
//ctx3d.camera.position.z = ctx3d.ship.position.z;
}
ctx3d.renderer.render(ctx3d.scene, ctx3d.camera);
}
I hope posting this as an answer is okay...
I've bumped the particle engine up a minor version to 0.7.7, having implemented a fix for your issue of "not-very-smooth-looking" emitters.
What was happening before was this:
SPE.Emitter.tick() called with a dt value
This tick function determines how many particles should be marked alive based on the dt argument passed to it. For larger dt values, more particles are marked as alive, for smaller values fewer are marked as alice.
The emitter then resets these particles and waits for the next call.
Assuming more than one particle is going to be marked as alive per frame, and they all originate at the same position in space, then all the particles will be at the same place when they're activated. This is why you saw some "clumping" happening.
What happens now is this:
SPE.Emitter.tick() called with a dt value, just as before.
The tick function now determines how many particles should be marked as alive, and whilst marking them so, sets each particles age to be a fraction of the dt value passed in.
So (!), assuming 100 particles are emitted per frame, and a dt value of 0.016 is passed to the emitter's tick function, each of those 100 particles that will be marked as alive is assigned an age value of (0.016 / 100) * i where i is the particle index (in this case, a value of 0 to 100).
I hope that makes sense. You can see the changes here: https://github.com/squarefeet/ShaderParticleEngine/blob/master/src/ShaderParticleEmitter.js#L240-L246
Master branch has been updated.

HTML Canvas Interval vs RequestAnimationFrame

So, maybe total brainfart here. The syntax for setInterval() is pretty clear. Do something every x miliseconds. How is this best translated to using the requestAnimationFrame() ?
I have about 300 objects and each is supposed to perform an animation sequence at a certain interval (every 8, 6, 2, etc seconds)? How can I best accomplish this using requestAnimationFrame() which gets called ~60 times a second? There is probably an easy answer, I just, for the life of me, can't figure it out.
To force requestAnimationFrame to stick to a specific FPS you can use both at once!
var fps = 15;
function draw() {
setTimeout(function() {
requestAnimationFrame(draw);
// Drawing code goes here
}, 1000 / fps);
}
A little weird, but noth the most confusing thing in the world.
You can also use requestAnimationFrame not with FPS but with elapsed time in order to draw objects that need to be updated based on the time difference since the last call:
var time;
function draw() {
requestAnimationFrame(draw);
var now = new Date().getTime(),
dt = now - (time || now);
time = now;
// Drawing code goes here... for example updating an 'x' position:
this.x += 10 * dt; // Increase 'x' by 10 units per millisecond
}
These two snippets are from this fine article, which contains additional details.
Good question by the way! I don't think I've seen this answered on SO either (and I'm here way too much)
requestAnimationFrame is pretty low level, it just does what you already said: roughly gets called at 60fps (assuming the browser can keep up with that pace). So typically you would need to build something on top of that, much like a game engine that has a game loop.
In my game engine, I have this (paraphased/simplified here):
window.requestAnimationFrame(this._doFrame);
...
_doFrame: function(timestamp) {
var delta = timestamp - (this._lastTimestamp || timestamp);
for(var i = 0, len = this.elements.length; i < len; ++i) {
this.elements[i].update(delta);
}
this._lastTimestamp = timestamp;
// I used underscore.js's 'bindAll' to make _doFrame always
// get called against my game engine object
window.requestAnimationFrame(this._doFrame);
}
Then each element in my game engine knows how to update themselves. In your case each element that should update every 2, 6, 8 seconds needs to keep track of how much time has passed and update accordingly:
update: function(delta) {
this.elapsed += delta;
// has 8 seconds passed?
if(this.elapsed >= 8000) {
this.elapsed -= 8000; // reset the elapsed counter
this.doMyUpdate(); // whatever it should be
}
}
The Canvas API along with requestAnimationFrame are rather low level, they are the building blocks for things like animation and game engines. If possible I'd try to use an existing one like cocos2d-js or whatever else is out there these days.

Add a countdown in my scoring script (javascript/jquery)

I have the following script in a js file:
// Ad score
var score = 0;
//$('#score').text(score);
function foundMatchingBlocks(event, params) {
params.elements.remove();
score += 100;
$('#score').text(score);
};
Now on each matching, 100 points are added to var score. This all works. Now I want to extend this a bit. As soon as the page loads I want to start a countdown to reduce the number of points (starting with 100) with 1 point a second for 60 seconds. So the minimum number of points a user can get is 40. When someone gets the points, the counter should reset and countdown again.
Example:
Page loads (timer starts from 100)
User has a match after 10 seconds (+90 points are added)
Counter resets and countdown from 100 again
User found a match after 35 sec (+65 points are added)
etc etc
Problem is, I have no idea how to do this :( Hope someone can help me with this.
The above is fixed, thanks all for helping!!!
The big picture is, you'll need to become pretty familiar with timeouts and intervals in javascript. This is the reference page I keep going back to when I need to refresh my memory: http://www.elated.com/articles/javascript-timers-with-settimeout-and-setinterval/
For your specific task, you'll probably want to use an Interval that triggers every 1000 milliseconds to calculate the second-by-second point reduction, and a separate Timeout for failure that resets every time the user completes their challenge.
Here are a few tips for working with timeouts and intervals that usually lead to followup questions:
When you set a timeout, always capture the return value (I think it's basically a random integer). Save it to some global var for convenience.
var failureTimer; // global var high up in your scope
failureTimer = setTimeout ( "gameOver()", 100000 ); // 100 seconds * 1000ms
Then in whichever method gets called when the player completes their challenge, you call this:
clearTimeout (failureTimer); // resets the timer and gives them another 100 seconds
failureTimer = setTimeout ( "gameOver()", 100000 ); // yes call this again, to start the 100 sec countdown all over again.
The second pain point you're likely to encounter when working with Timeouts and Intervals is how to pass parameters to the functions like gameOver() in my example above. You have to use anonymous functions, as described here:
Pass parameters in setInterval function
For more on anonymous functions, this is a good overview:
http://helephant.com/2008/08/23/javascript-anonymous-functions/
Good luck with your project! Let me know if you have any questions.
Here's some code without the use of timers. Call startCountdown() every time you want to re-initialize the count-down. Call getAvailableScore() when you want to fetch the current available score. You will have to decide what to do when the available score goes to zero.
var beginCountDownTime;
function startCountdown() {
beginCountDownTime = new Date();
}
function getAvailableScore {
var now = new Date();
var delta = (now.getTime() - beginCountDownTime.getTime()) * 1000; // time elapsed in seconds
var points = 100 - (delta / 60);
return(Math.round(Math.max(points, 0))); // return integer result >= 0
}
Maybe something like:
// Ad score
var score = 0;
var pointsAvailable = 100;
//$('#score').text(score);
function foundMatchingBlocks(event, params) {
params.elements.remove();
score += pointsAvailable;
$('#score').text(score);
pointsAvailable = 100;
};
$(document).ready(function() {doTimer();});
function doTimer() {
setTimeout('reducePoints()',1000);
}
function reducePoints() {
if(pointsAvailable>40) {
pointsAvailable--;
}
doTimer();
}

Counting down for x to 0 in Javascript?

I have from the backend a time on the format 00:12:54 and I display it to the screen. But, I would like to have this time to continue to go down. I have though to create a variable in javascript that will old the time and with setTimeout to loop to display with document.getElementById the new value. I think it can be problematic if I have many time to go down in same time. I might require an array?
How would you do that? If I have no other suggestion, I will try my way, but I am curious to know if it does have a more secure way to do it.
Do you know jQuery Framework? It's a Javascript framework that have a lot of utilities methods and functions that let you do Javascript stuff more easily.
Here is a count down plugin (haven't tested it).
I suggest you to download JQuery than download the plugin . Check the sample of code from the "relative" tab on the website. You can have something like :
$('#until2d4h').countdown({until: '+12M +54S'});
*The only drawback with what I suggest you is that you will require 2 .js to be added. Try to add them only when needed and you will be find.
General algorithm:
Read time from server.
Read the current time.
Call a function.
In your function, read the current time, get the delta from the initial time you read in step 2.
Subtract the delta from the initial time you read from the server in step 1 and display the remainder.
The function should call window.setTimeout to call itself in 1000ms (or adjust according to time elapsed within the function), if you want to continue counting down.
Here's a rough cut:
window.onload = function () {
var countdown_start_in_ms = 6000; // from server
function tick() {
var now = new Date().getTime();
var disp = start - now;
if (disp < 0) {
disp = 0;
}
var el = document.getElementById("countdown");
el.innerHTML =
// quick hack to format time
/(\d\d:\d\d:\d\d) ...$/.exec(new Date(disp).toUTCString())[1];
if (disp > 1000) {
var elapsed = new Date().getTime() - now;
window.setTimeout(tick, 1000 - elapsed);
} else {
// stop countdown and set color to light grey
el.style.color = "#ccc";
}
}
var start = new Date().getTime() + countdown_start_in_ms;
tick();
}
You won't like the taste of this one, but it'll do you good:
Google for 'javascript timer' and get your hands dirty reading through the various examples and tutorials returned by that search.
You'll learn a lot more than just how to write a count-down timer. :-)
Good luck!
Take a look at Grab hands and set your own time. and inspect its code. While it is written with Dojo, the "clock" part is in plain JavaScript. In your case the only difference is how to advance the counter — decrease rather than increase it.

Categories

Resources