I'm in the process of creating an incremental game in JavaScript (like CookieClicker, if you've ever played it).
To use CookieClicker as an example, you generate a certain number of cookies every second. If you're making 700 cookies per second, the counter increments by 1 cookie 700 times a second (or appears to).
Currently in my game, if you are making 700 "cookies" per second, the counter will increment by 700 "cookies" once per second, rather than increasing smoothly by a fixed amount.
I'm at a loss on how to do this. I've made a function that calculates the number of "cookies" you make per second, and I tried using that number to make the time parameter of window.setInterval() a variable, but I'm not even sure if that's possible let alone practical.
I'm pretty sure this isn't the right approach but I'll post the relevant code anyway:
function getManaPerSecond(){
manaPerSecond = earthEssence + (windEssence * 5) + (waterEssence * 10) +
(fireEssence * 150);
};
window.setInterval(function(){
getManaPerSecond();
}, 1000);
window.setInterval(function(){
if(manaPerSecond>0){
incrementalMana++;
document.getElementById('incrementalMana').innerHTML = incrementalMana;
}
}, (1000/manaPerSecond));
Whenever the frequency changes, you need to stop the old interval function and start a new one.
var manaCounter;
var oldManaPerSecond = 0;
function restartManaCounter(manaPerSecond) {
if (manaPerSecond != oldManaPerSecond) {
clearInterval(manaCounter);
oldManaPerSecond = manaPerSecond;
if (manaPerSecond > 0) {
manaCounter = setInterval(function() {
incrementalMana++;
document.getElementById('incrementalMana').innerHTML = incrementalMana;
}, 1000/manaPerSecond);
}
}
}
function getManaPerSecond(){
var manaPerSecond = earthEssence + (windEssence * 5) + (waterEssence * 10) + (fireEssence * 150);
return manaPerSecond;
};
window.setInterval(function() {
restartManaCounter(getManaPerSecond());
}, 1000);
Related
I am trying to create a function that measures the average of a microphone input level over five minutes, then stores the sum of calculations in a variable.
At the moment, an interval is set to run the function every five minutes but only calculates the average of the single last input value, instead of the values over time.
function measureLevel() {
average = 0;
for (counter = 0; counter < 75000; counter++) {
average += absoluteLevel / 75000;
}
averageAbsoluteLevel = Math.abs(average);
averageDbLevel = Tone.gainToDb(averageAbsoluteLevel) * scale + offset;
console.log('Counter reached. Average level is: ' + averageDbLevel);
}
window.setInterval(measureLevel, 300000);
Thanks in advance.
but only calculates the average of the single last input value,
instead of the values over time.
You are setting the average to 0 every time, you need to remember two things
Total sum of mic value
Number of times this timer has already run
Finally divide the total mic sum value by number of times this timer has run. Try
(function(){ //create a IIFE so that micSum and timerCounter is localized and don't pollute global namespace
var micSum = 0;
var timerCounter = 0;
window.setInterval(function(){
var absoluteLevel = Math.abs( Tone.Meter.getValue() );
micSum += Tone.gainToDb(absoluteLevel ) * scale + offset; //keep adding to the sum
timerCounter++;
console.log('Counter reached. Average level is: ' + (micSum/timerCounter) ); //take the average by dividing micSum with counter.
}, 300000);
})(); //set the timer
The approach I think of would be to gather measurements, until 5 minutes are passed. You could use two timers for this, one to collect the measurements (interval, repeating), and one timeout when 5 minutes have passed to collect the average (and stop the interval).
So something like this should get you started:
var measurements = []
function collectMeasurement() {
var absoluteLevel = Math.abs( Tone.Meter.getValue() );
measurements.push(absoluteLevel);
}
collectInterval = window.setInterval(collectMeasurement, 100);
function calculateAverage() {
window.clearInterval(collectInterval);
// .. calculate average of all measurements here ..
console.log('Measure for 5 minutes: average level is: ' + calculatedAverage);
}
window.setTimeout(calculateAverage, 300000);
So things to play around with:
vary the timeout between measurements? (how soon can you get a reliable measurements, how many measurements are wanted, ...)
instead of using a set time to measure, you could also use a set amount of measurements, which would make it easier, but probably less optimal?
So I'm working on a basic shooter, part of which involves moving a target around the screen. I'm using babylon.js as the engine and my goal is to have the target appear for 0.75 seconds on the screen, then disappear for 0.5 seconds, then reappear at a different random location. The current code I have for that is this:
function moveTarget(canvas, scene){
setTimeout( function (){
scene.meshes[10].visibility = 0; //how I access the target object
randX = genRandNum(minX, maxX); //This is a separate function that works
randY = genRandNum(minY, maxY);
scene.meshes[10].position = new BABYLON.Vector3(randX, randY,
scene.meshes[10].position.z);
scene.meshes[10].visibility = 1;
x ++;
if (x < amount){
moveTarget(canvas, scene);
}
}, tarDuration * 1000)
}
which succeeds in everything except the 0.5 second delay between appearances of the target, ie currently it flashes from location to location with no space in between. I'm thinking that I need a second setTimeout but I'm not entirely sure how to include that or where it would go. Any pushes in the right direction would be much appreciated.
The way I would do this is to set a timeout for the full cycle time (0.75 s + 0.5 s) and then another timeout inside that for the 0.5 s delay.
function moveTarget(canvas, scene){
setTimeout( function (){
setTimeout( function(){
// Your other code
x ++;
if (x < amount){
moveTarget(canvas, scene);
}
}, yourDelayHere)
}, tarDuration * 1000)
}
Where yourDelayHere gives the desired 0.5 s delay. I created a Babylon.js playround which shows a simplified example here.
My goal is to write a mini-game using canvas, one of the task is to create "bug" object entering the scene between every 1-3 seconds. I did try functions like setTimeOut,setInterval but I couldn't get it right. Here is my attempt
bugs =[];
function addBug(){
var bug = createBug();
bugs.push(bug);
}
function createRandomNumber(max){
return Math.floor((Math.random() * max) + 1);
};
var enterBug = setInterval(addBug,createRandomNumber(10)*1000);
currently I got it spawning at constant rate but don't know how to change it to every 1-3.Any suggestion? thanks in advance.
Currently, you are only setting the rate once at initial setInterval call. You would likely need to use setTimeout like this:
...
function addBug(){
...
bugTimeout = setTimeout(addBug, createRandomNumber(10)*1000);
}
...
bugTimeout = setTimeout(addBug, createRandomNumber(10)*1000);
You also may think about your random number generation if you want to get more randomness. Right now you can only get exact second values 1-10 since you are multiplying by 1000 to convert to seconds AFTER the random generation is done. If you want something more random you might use:
function createRandomNumber(maxSeconds){
minSeconds = 1;
if (maxSeconds < minSeconds) {
maxSeconds = minSeconds;
}
interval = maxSeconds - minSeconds;
return (Math.floor(Math.random() * interval) + minSeconds) * 1000;
};
You of course would not need to multiply by 1000 anymore when setting timeout.
bugTimeout = setTimeout(addBug, createRandomNumber(10))
I have a for loop that is running a timeout function that needs dynamic numbers but instead I'm getting the end result instead of the increments in some cases.
Here's my code (p.s. yes I realize setting 'start' variable inside for loop is not ideal):
var new_answer_start = 0;
var seconds = 0;
for (start=0; start<50; start++) {
new_answer_start = new_answer_start + 50;
seconds = seconds + 10000; //10 seconds
setTimeout(function(){reloadXMLDoc(xmlurl, new_answer_start);},seconds);
}
What I'm trying to accomplish is that increasing every 10 seconds the function will run with the new_answer_start equaling increments of 50. Instead I'm getting every 10 seconds the function is outputting each time starting at 2500 (the last set of numbers after 50 loops). I've had a similar issue before, something to do with closures and I used "let" to fix it then. However when I tried:
let new_answer_start = new_answer_start + 50;
I started getting NaN (not a number) errors. I thought it was weird that the timeout would increment in seconds (10, 20, 30, etc) but not the variable sent to the function. I'm assuming that's because once the function goes to run 10 seconds later, the variable increment has completed to the end. So how do I send the 'fixed' number to the function?
After doing research on similar questions here, I also tried putting the number into a closure:
setTimeout(function(){reloadXMLDoc(xmlurl, (new_answer_start));},seconds);
But this still start outputting at 2500.
Try using an actual closure:
setTimeout((function (new_answer_start) {
return function () {
reloadXMLDoc(xmlurl, new_answer_start);
};
})(new_answer_start), seconds);
window.new_answer_start = 0;
var interval = setInterval(function() {
window.new_answer_start = window.new_answer_start + 50;
}, 10000);
I know a few questions have been asked like this one before, such as this: Check FPS in JS? - which did work to some degree, I was able to find out how long each loop took to complete.
What I am looking for though is something more readable and controllable. I want to be able to set the refresh rate for the FPS counter to make it slow so it is human readable or as fast as the application can run, so I can use it on some kind of speedometer.
Anyway so here is the code I have right now:
var lastLoop = new Date().getTime();
function updateStage()
{
clearCanvas();
updateStageObjects();
drawStageObjects();
var thisLoop = new Date().getTime();
var fps = (thisLoop - lastLoop);
$('#details').html(fps);
lastLoop = thisLoop;
iteration = setTimeout(updateStage, 1);
}
Am I right to be setting the setTimeout function to a speed of 1 millisecond? I was thinking this will just make it loop as fast as it possibly can.
Should I count every 100 frames or so, find out how many milliseconds it took to run 100 frames then make a calculation to find out how many frames it would have done if the milliseconds were 1000? What would this calculation be?
To make the result more accurate I am guessing I need to display averages as one frame can vary a significant amount, how should I do this?
Any tips are greatly appreciated.
Thanks.
Note that the faster you update your output, the more you will affect your measurement. Although minimal, I try to update my fps output once per second or less unless it's necessary to go faster.
I like to have a low-pass filter on my results so that a temporary hiccup doesn't affect the values too strongly. This is easier to compute and write than a moving average, and doesn't have the problem of an overall average where your 'current' readings are affected by total performance over the entire run (e.g. anomalous readings during startup).
Put together, here's how I usually measure FPS:
var fps = 0, now, lastUpdate = (new Date)*1;
// The higher this value, the less the FPS will be affected by quick changes
// Setting this to 1 will show you the FPS of the last sampled frame only
var fpsFilter = 50;
function drawFrame(){
// ... draw the frame ...
var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
if (now!=lastUpdate){
fps += (thisFrameFPS - fps) / fpsFilter;
lastUpdate = now;
}
setTimeout( drawFrame, 1 );
}
var fpsOut = document.getElementById('fps');
setInterval(function(){
fpsOut.innerHTML = fps.toFixed(1) + "fps";
}, 1000);
Ive tried something out,
If you change the
lastUpdate = now
to
lastUpdate = now * 1 - 1;
Your NaN problem is solved! This is also used where the lastUpdate is defined. Probably because it is not able to convert the date to unix timestamp.
The new result will be:
var fps = 0, now, lastUpdate = (new Date)*1 - 1;
// The higher this value, the less the FPS will be affected by quick changes
// Setting this to 1 will show you the FPS of the last sampled frame only
var fpsFilter = 50;
function drawFrame(){
// ... draw the frame ...
var thisFrameFPS = 1000 / ((now=new Date) - lastUpdate);
fps += (thisFrameFPS - fps) / fpsFilter;
lastUpdate = now * 1 - 1;
setTimeout( drawFrame, 1 );
}
var fpsOut = document.getElementById('fps');
setInterval(function(){
fpsOut.innerHTML = fps.toFixed(1) + "fps";
}, 1000);
I've taken the solution(s) posted and enhanced them a little. Have a look here - http://jsfiddle.net/ync3S/
I fixed that NaN error by using Date.now() instead of constructing a new date object each time and trying to reference it. This also prevents some garbage collection necessity.
I neatened up the variable and function names a bit and added some extra commenting - not necessary but nice to have.
I included some drawing code for testing.
I added fpsDesired as a test var for the engine loop.
I started fpsAverage at fpsDesired so with the fpsFilter it doesn't work up from 0 to the real FPS, rather starting at the desired FPS and adjusting from there.
Drawing now blocks incase it already was drawing, and this can be used for pausing and other control functions.
The main block is as follows:
var fpsFilter = 1; // the low pass filter to apply to the FPS average
var fpsDesired = 25; // your desired FPS, also works as a max
var fpsAverage = fpsDesired;
var timeCurrent, timeLast = Date.now();
var drawing = false;
function fpsUpdate() {
fpsOutput.innerHTML = fpsAverage.toFixed(2);
}
function frameDraw() {
if(drawing) { return; } else { drawing = true; }
timeCurrent = Date.now();
var fpsThisFrame = 1000 / (timeCurrent - timeLast);
if(timeCurrent > timeLast) {
fpsAverage += (fpsThisFrame - fpsAverage) / fpsFilter;
timeLast = timeCurrent;
}
drawing = false;
}
setInterval(fpsUpdate, 1000);
fpsUpdate();
setInterval(frameDraw, 1000 / fpsDesired);
frameDraw();
Going to have a tinker and see if I can come up with something smoother, as this thread is near the top in Google results.
Let's see what we can all come up with as a team, and I think it's always neat to not use 3rd party libraries, making the code portable for anyone :)
-Platima
Just set a interval that is resetting the fps counter every second.
var fpsOut, fpsCount;
var draw = function () {
fpsCount++;
..Draw To Canvas..
..Get the fps value: fpsOut
requestAnimationFrame(draw);
};
setInterval(function () {
fpsOut = fpsCount;
fpsCount = 0;
}, 1000);
draw();
If you want real-time updates, consider making it loop again and again in real time. To make it affect the performance less, only update the controlled variable, in this case, the FPS. You can have optional Frame Latency, which I will put here, just in case. Just copy, paste and tweak the code to your needs.
Take note that a single frame lasts for 16.66 miliseconds.
setInterval(function(){var latencybase1 = parseFloat(new Date().getTime());
var latencybase2 = parseFloat(new Date().getTime());
var latency = latencybase2-latencybase1;
var fps = Math.round(1000/latency);
if (latency<16.66)
{document.getElementById("FPS").innerHTML = fps+"
FPS";}
else {document.getElementById("FPS").innerHTML = ""+fps+" FPS";}
document.getElementById("Latency").innerHTML = latency+" ms";}, 0);