Speeding up an object in JS game after every 10 points - javascript

I am trying to speed up an object in JS game x2 every 10 points.
In the game at the same time I use
let game = setInterval(draw,100);
Which technique should I try? I have been searching for a really long time yet trying to do it with changing the setInterval didn't work as it should (it accelerated over and over).
Would be really grateful for any advice (not looking for a ready code, just saying!).

You just need to hang onto the game value returned from setInterval. You can use that to stop the current interval timer with clearInterval() and then start a new one with your new rate. Since you didn't post much code here's a contrived example that counts to 100 speeding up every 10 numbers:
let i = 0
let speed = 1
let basespeed = 1000
function play() {
console.log("play", i++)
if (i % 10 == 0) {
speed *= 2
clearInterval(int)
if (i >= 100) return
int = setInterval(play,basespeed/speed)
}
}
let int = setInterval(play, basespeed)

Related

JS for loop not showing correct result

The question:
At exactly 10:25:21 , car speed is at 6.
11 mins later which is 10:36:21, car speed increased by 1, so is 7.
After 10:46:21 until 12:00:00, for every min, car speed increase steadily by 1, so is 8 onwards.
<script>
var date = new Date();
date.setHours(10);
date.setMinutes(25);
date.setSeconds(21);
var speed;
for (let i = 0; i < 95; i++) {
if (i < 35) {
speed = 6;
}
//increase speed by 1 after 10:36:21
else if (i < 45)
{ speed = 7;
}
// speed continously increase by 1 after 10:46:21
else
{ speed++;
}
date.setMinutes(25+i);
document.write(date + ":" + speed + "m/s <br><br>");
}
</script>
The result is showing me 6 till 10:59:21 instead of 10:36:21
And when the speed increased to 7, the hours and minutes increased too.
Any help is appreciated. I apologized if i'm a newbie here.
The logic in the code is weird, to say the least.
Rather than use a counter to manually work through each minute, why not simply create dates that start and end the trip, and mark the two places where the speed increases:
var startTime = new Date();
startTime.setHours(10);
startTime.setMinutes(25);
startTime.setSeconds(21);
var endTime = new Date();
endTime.setHours(12);
endTime.setMinutes(0);
endTime.setSeconds(0);
var time1 = new Date();
time1.setHours(10);
time1.setMinutes(36);
time1.setSeconds(21);
var time2 = new Date();
time2.setHours(10);
time2.setMinutes(46);
time2.setSeconds(21);
var thisTime = startTime;
var speed = 0;
while (thisTime < endTime) {
if (thisTime < time1) {
speed = 6;
} else if (thisTime < time2) {
speed = 7;
} else {
speed++;
}
document.write(thisTime + ":" + speed + "\n<br>");
thisTime.setMinutes(thisTime.getMinutes() + 1);
}
Using thisTime as the current time in the route, we just update that by 1 minute for each iteration. This is a while loop that runs from the start time to the end time, so as soon as thisTime is greater than endTime it ends the loop.
With
for (let i = 0; i < 95; i++) {
you are iterating over i which holds the amount of minutes - 25, because you started with 25 minutes.
if (i < 35) {
will be true until the 35th loop (including).
You could just subtract your start value:
if (i < 10) {
speed = 6;
}
//increase speed by 1 after 10:36:21
else if (i < 20)
{ speed = 7;
}
I think you have a problem with the amounts you are using, besides, here you have another idea:
var date = new Date();
date.setHours(10);
date.setMinutes(25);
date.setSeconds(21);
var speed;
var dateToShow;
function addMinutes(date, minutes) {
return new Date(date.getTime() + minutes*60000);
}
for (let i = 1; i < 96; i++) {
if (i < 11) {
speed = 6;
}
//increase speed by 1 after 10:36:21
else if (i < 22)
{ speed = 7;
}
// speed continously increase by 1 after 10:46:21
else
{ speed++;
}
dateToShow = addMinutes(date, i);
document.write(dateToShow + ":" + speed + "m/s <br></br>")
}
I think this solves your problem.
I have added an extra function to add the minutes to a new date so you won't have more problems
Before you start coding anything, you need to establish a few things first: Objects, Facts, Variables, States and Output
Objects:
1 What objects provide something that you need to use in your code?
2 What objects do you need to create in your code?
3 What objects do you need to manipulate in your code?
4 What objects are completely irrelevant to your code?
5 What will you do with any object used in your code?
Facts:
What are the known, static, facts?
What value or values will never change during the execution of the code but are required in the code?
Variables:
What are the unknowns?
What value or values will, or could, change during the execution of the code?
States:
1 What is the starting state of any object(s) or variable(s)?
2 What is desired/required final state of any object(s) or variable(s)?
Output:
1 Do you need to provide any "printed" output - eg, to the screen or the console?
2 Do you need to return anything - eg, is this a function that returns one or more values?
So, with this in mind, if we look at your question:
Objects:
There are two:
Car - completely irrelevant as nothing in the question is based on the type of vehicle, so we can ignore this object
Clock - required to determine the elapse of time in minutes. But, there is no need to create this as an object, a variable will handle this as we only actually need to know the time the clock would show. Presumbably, the car's clock or the driver's watch, for example, would be used to determine the time, but we are not looking at either as we have our own method of determining the time.
We could create a custom object for the car and its speed. However, the only value we would maintain on that object would be the speed. If, however, we needed to run the code for multiple vehicles, using different times, we could create an object for each. That is not required here as there is only one car. Likewise, the clock's value could be added to a car object, but, again, we only really need to know the time, not the fact that it is shown on a clock or that the clock/watch actually exists.
Facts:
There are six:
1 Start time
2 Speed change 1 time
3 Speed change 2 time
4 End time
5 We are checking the speed every minute
6 The speed is dependant on the time
The four times are static values, so we can create variables to hold these values and nothing in the code will change these values. Often, these are created using const but I've used var in my code example.
The fact that we are checking/changing the speed every minute just provides us with a reason to pinpoint particular times between the start and end times. A variable is required to handle this as the current time value will change during the running of the code.
States:
There are two initial states:
1 The time starts at 10:25:21
2 We start driving at 6mph
There is one final state:
The time stops at 12:00:00
Note that the speed will be whatever the code has calculated, so has an unknown final state
Output:
In this case, the output is written into the document. When testing, it is more usual to output to the console, using console.log(...)
Given all that, we can look at what code is required.
1 Create the static variables - the four points in time
2 Create the other variables - the speed and the current time
3 Create a loop that will move us through time from the "Start time" to the "End time", one minute at a time, using the current time variable to keep track of where we are
4 Create if/else tests to determine what the current time is in relation to the static times
5 Determine what speed the car should be going at that time
6 Output the time and speed - as we are not in a function, we output to either the page or the console as desired as we are not returning a value to other code
7 End the loop once "End time" is reached.
There are three types of loops we could use:
1 a for loop - this is normally used to iterate over collections, by referencing the collection's items by index number, or to provide a counter that can be used within the loop. As we don't need a counter and don't have a collection, we won't use this
2 a while loop - this is not dependant on counters, it simply tests a condition statement before starting an iteration of the loop. If the test fails, the condition is not met and the loop doesn't run.
3 a do/while loop - similar to a while loop except that the condition is checked AFTER the first iteration, so will run at least once. If the condition is met, the loop starts again. We could use this as we know that the loop needs to run at least once. However, if the current time was already after the end time, we would not want the loop to run, so I have avoided this loop
There are other types of loops available, such as for/in, for/of and forEach but these are generally used for objects and collections, so are not relevant here.
Thus, the best loop to use is the while loop as the requirement is to "...do something until..."
So, now we know all we need to know to construct the code.
// Create the static time variables
// Start time
var startTime = new Date();
startTime.setHours(10);
startTime.setMinutes(25);
startTime.setSeconds(21);
// Speed change 1 time
var endTime = new Date();
endTime.setHours(12);
endTime.setMinutes(0);
endTime.setSeconds(0);
// Speed change 2 time
var time1 = new Date();
time1.setHours(10);
time1.setMinutes(36);
time1.setSeconds(21);
// End time
var time2 = new Date();
time2.setHours(10);
time2.setMinutes(46);
time2.setSeconds(21);
// Create the other variables
// "thisTime" is initially set to "startTime" but will be incremented by the loop code
var thisTime = startTime;
// A variable to hold the current speed through the loops
// This could be set to 6, but if the loops don't run (ie, the condition is not met), we would not want the speed to be 6
var speed = 0;
// Start a loop - check that the current time (thisTime) is less than the endTime
while (thisTime < endTime) {
// If it is, check if we have reached the first speed change time - "time1"
if (thisTime < time1) {
// If we haven't, keep the speed at 6
speed = 6;
// If we have, check if we have reached the second speed change time - "time2"
} else if (thisTime < time2) {
// If we haven't, the speed is 7
speed = 7;
// If we have, we can now increase the speed 1mph for each minute (ie, for all further iterations of the loop)
} else {
speed++;
}
// Output the time and speed
document.write(thisTime + ":" + speed + "\n<br>");
// Add one minute to the thisTime variable which will be tested at the start of the next iteration of the loop
thisTime.setMinutes(thisTime.getMinutes() + 1);
}
And, to convert this all back into English:
Given these four points in time and checking my speed every minute, I start driving at the first time point. If I've not reached the second time point, I'm doing 6mph. But, if I have reached that, but haven't yet reached the third time point, I'm doing 7mph. But if I've reached that, I keep increasing my speed by 1mph for every minute. I stop driving at the final time point. Throughout, I'm making a note of the time and my speed.

Javascript - requestAnimationFrame Frame Rate

I have a sprite sheet animation where I am using requestAnimationFrame method to animate a spritesheet with only 4 images on the sheet This is my code:
http://hyque.com/ryan/ani-ryan-2.html
The problem is that it is too fast at 60 fps, so I want to slow the fps. I have been reading several articles on different ways to do it using either setInterval or Date(). I can’t seem to get the code to work correctly. Can anyone help, please.
Here is one of the articles that I tried to merge into my code:
http://codetheory.in/controlling-the-frame-rate-with-requestanimationframe/
So what I like to use to control animation apart form the "game loop."
var lastRender = 0;
var counter = 0;
function render(time)
{
//checks to see if enough time has passed
if(time - lastRender<16){requestAnimationFrame(render);return;}
lastRender = time;
counter++;
if(counter %20 && counter != 0)
animation();
if(counter >= 60)
counter=0;
requestAnimationFrame(render);
}
requestAnimationFrame(render);
This gives you greater control over your sprites so you can now have them at different speeds and your logic stays at 60fps.
Generally, for Game Engines you will want your rendering speed to be different from your logic speed.
Logic speed should simply be as fast as possible
setInterval( logic, 0 ); // runs as fast as possible
OR
setTimer( logic, 0 ); // logic() runs this again ( i think this is generally better )
Whereas render should remain as you have it, as fast as rendering is done
requestAnimationFrame( render ) // per render frame
However, requestAnimationFrame is unstable between machines, and for the most part will run 60 frames per second ( depending on the users hardware ).
In this case, for consistency you should base your animation on consistent TIME or setTimeout.
In your animation you could use something like
var date = new Date(), // date object
milliseconds = date.getMilliseconds(), // 0 - 999 of the second
totalSpriteFrames = 4
frame = Math.floor( milliseconds / ( 1000 / totalSpriteFrames ) ); // break the second into four frames
Create the date object outside of your animation scope for optimization, and this math can easily be used to choose which " frame " your sprite is on. You can also use this for multiple sprites, just change their " totalSpriteFrames "
This is also scalable in case you end up with a frame heavy sprite with many frames.

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.

requestAnimationFrame at a limited framerate

As I understand it, usage of the JS requestAnimationFrame API is intended for cases where the framerate isn't in need of being controlled, but I have a use case where it's essential that a <canvas> only updates at a certain fps interval that may be anywhere between 1 and 25 (between 1 and 25 frames per second, that is). Can I then somehow still effectively use rAF to get at the optimizations it offers?
This question has similarities to mine, but the accepted answer there made close to zero sense to me in the context of that question.
I have two possible solutions for this. The first one involves using a while loop to halt the execution of the script for a specified delay before calling requestAnimationFrame from within the callback. In the example where I saw this, it effectively limited the fps of the animation, but it also seemed to slow down the entire tab. Is this still actually a good solution? The second alternative, as mentioned in the question I linked to above, calls requestAnimationFrame within a setInterval. To me that seems a bit convoluted, but it could be that's the best option?
Or is there a better alternative to accomplish this?
Yoshi's answer is probably the best code solution to this problem. But still I'll mark this answer as correct, because after some research I basically found that my question was invalid. requestAnimationFrame is really meant to keep frame rates as high as possible, and it optimizes for scenarios where animation is meant to be kept consistent and smooth.
Worth noting though is that you don't need requestAnimationFrame to get optimization (even though rAF was touted as a great performance booster) since browsers still optimize regular drawing of a <canvas>. For example, when a tab isn't focused, Chrome for one stops drawing its canvases.
So my conclusion was that this question was invalid. Hope this helps anyone who was wondering something similar to me.
This is just a proof of concept.
All we do is set our frames per second and intervals between each frame. In the drawing function we deduct our last frame’s execution time from the current time to check whether the time elapsed since the last frame is more than our interval (which is based on the fps) or not. If the condition evaluates to true, we set the time for our current frame which is going to be the “last frame execution time” in the next drawing call.
var Timer = function(callback, fps){
var now = 0;
var delta = 0;
var then = Date.now();
var frames = 0;
var oldtime = 0;
fps = 1000 / (this.fps || fps || 60);
return requestAnimationFrame(function loop(time){
requestAnimationFrame(loop);
now = Date.now();
delta = now - then;
if (delta > fps) {
// Update time stuffs
then = now - (delta % fps);
// Calculate the frames per second.
frames = 1000 / (time - oldtime)
oldtime = time;
// Call the callback-function and pass
// our current frame into it.
callback(frames);
}
});
};
Usage:
var set;
document.onclick = function(){
set = true;
};
Timer(function(fps){
if(set) this.fps = 30;
console.log(fps);
}, 5);
http://jsfiddle.net/ARTsinn/rPAeN/
What you can do, though I don't really know if this is really any better is:
render to an invisible context with requestAnimationFrame
update a visible context with setInterval using a fixed fps
Example:
<canvas id="canvas"></canvas>​
<script type="text/javascript">
(function () {
var
ctxVisible = document.getElementById('canvas').getContext('2d'),
ctxHidden = document.createElement('canvas').getContext('2d');
// quick anim sample
(function () {
var x = 0, y = 75;
(function animLoop() {
// too lazy to use a polyfill here
webkitRequestAnimationFrame(animLoop);
ctxHidden.clearRect(0, 0, 300, 150);
ctxHidden.fillStyle = 'black';
ctxHidden.fillRect(x - 1, y - 1, 3, 3);
x += 1;
if (x > 300) {
x = 0;
}
}());
}());
// copy the hidden ctx to the visible ctx on a fixed interval (25 fps)
setInterval(function () {
ctxVisible.putImageData(ctxHidden.getImageData(0, 0, ctxHidden.canvas.width, ctxHidden.canvas.height), 0, 0);
}, 1000/40);
}());
</script>
Demo: http://jsfiddle.net/54vWN/

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();
}

Categories

Resources