quick question about a game engine I am writing in Javascript in Khan Academy: i have on arc that represents the amount of reload time left. (in processing js, drawing an arc works like this: arc(x,y,width,height,start,stop);)
I already have the value of the time left in seconds stored in a variable, so how can I accuratly have the arc wedge = time currently reloading divided by total reload time?
When the arc is a circle, reload is complete. When the arc is nothing, it just started reloading.
Also, the reload arc wedge stroke starts on the center top, and moves clockwise around the outside.
if(weapon.reloading){
arc(300,300-player.size-player.size/2,40,40,-90,round((w.reloadCounter/w.reloadTime/100)*100)*6-95);
}
this redundant code works when fps(frames per second equals 60)
i already have a variable called fps that equals frames per second, so if any help is given, use that in example.
Thanks!
Edit: would this be accurate - from what i can see from testing, it is mostly accurate:
var time = round(w.reloadCounter/fps*10)/10;//seconds currently spent reloading(rounded to the nearest 10th)
var t = round((w.reloadTime-time)*10)/10;//time left to finish reloading
var timeLeftArc = map(t,0,w.reloadTime,270,-90);
arc(300,300-player.size-player.size/2,40,40,-90,timeLeftArc);
We know that 360 degree make up a full circle - which equals to a fully reloaded weapon in your case. To get the proper arc for in-between values we need to figure out how many percent of the reloading phase is processed.
This can simply be done by dividing the time passed by the total time required - so just like you already did:
w.reloadCounter / w.reloadTime
This will give a float between 0 and 1. If we then multiply this number by 360 we have the in-between angles for the arc.
arc(300, 300 - player.size - player.size / 2, 40, 40, -90, w.reloadCounter / w.reloadTime * 360 - 90);
As a simple example:
Say the time required is 1000ms and 500ms have elapsed:
500 / 1000 * 360 = 0.5 * 360 = 180
Related
I am trying to control the speed of an animation so it matches the actual speed that a vehicle took.
let counter = 0;
const animate = () => {
counter += 1;
// Update point geometry to a new position based on the animation
// And the distance the point has travelled along the route.
const updatedPoint = turf.along(lineString, (counter / 100) * lineDistance, 'kilometers');
moveVehicleToPoint(updatedPoint);
// updatedPoint represents a point between/along between origin and destination
if (updatedPoint.geometry.coordinates[0] !== destination) {
requestAnimationFrame(animate);
}
}
animate();
I'm nearly there but maths isn't my strongest asset.
lineDistance is roughly 0.01-0.02km on average.
lineString contains the start and end coordinate.
turf.along take the lineString, a set distance, and returns the distance from the start to your provided distance along the line in kilometers.
Currently, I've included an arbitrary value of 100 to divide by. If the vehicle move took 1 second, this is pretty good. It will move along to the next point by roughly a second.
If it took 2 seconds, it'll be too slow, and finish moving well before the vehicle would have.
How can I include my durationSeconds variable, so that if I say it took 2 seconds, the animate() will perfectly animate along the line over 2 seconds?
Try setting up a variable in the outer scope that relates to the speed you need. Change it's value accordingly to control it.
I'm attempting to get an object to move along a circular path in a fixed time period.
The application of this is a 'smooth motion' clock.
So, instead of moving the position to a fixed co-ordinate everytime .getSeconds() updates, I want to use a combination of ( .getSeconds() + ( .getMilliseconds()/1000 ) in order to accurately represent the motion of the second hand at all times.
For doing circular motion in the past I have used the following pair of functions:
var OrbitCalculationX = function(velocityPartial, orbitalRadius) {
return (Math.sin(Date.now() / 16000 * velocityPartial) * orbitalRadius);
};
var OrbitCalculationZ = function(velocityPartial, orbitalRadius) {
return (Math.cos(Date.now() / 16000 * velocityPartial) * orbitalRadius);
};`
The 16000 in that calculation controlled the orbital time. However, this is not accurate. Is there a way to control a x-axis sin vs z-axis cos equation set that has accurate time constraints?
If not, is there a way to set an animation path to complete in an exact time period in THREEjs?
I hope that I understood you correctly here...
Take one minute which has 60 secs and 60,000 msecs. So, the first step we want is to have numbers in that range.
var millisInMinute = Date.now() % 60000;
next thing we want is to normalize the value, so that it goes from 0 to 1:
var millisInMinuteNormalized = millisInMinute / 60000;
Now, to make a whole circular movement with sin and cos where we know that our variable will be between 0 and 1, we need to multiply it by 2*PI see plot here
The rest with the radius is like you did it, resulting in
var orbitCalculation = function(radius) {
return {x: (Math.sin((Date.now()%60000)/60000 * Math.PI * 2) * radius),
z: (Math.cos((Date.now()%60000)/60000 * Math.PI * 2) * radius)};
}
The actual seconds are now displayed correctly, you can compare it with your system time. Here is a working JSFiddle
I was trying to rotate the object by a variable number of degrees to represent a dial. As the first step I tried doing the following:
window.onload = function() {
var paper = new Raphael(document.getElementById('canvas_container'), 500, 500);
var circle = paper.circle(100, 100, 80);
var arrow = paper.path("M 100 100 l -56.5 56.5 z");
arrow.attr({stroke: '#0a0', 'stroke-width': 3});
for(var i=0;i<=100; i+=1){
rotate_cw(arrow);
}
}
function rotate_cw (element){
element.animate({transform:"r-1,100,100"}, 10);
}
The animate works by itself but I am unable to make it work with an external function.
Any solutions or workarounds?
Your code works - the animation is happening and the function works - but it doesn't look like it works for two reasons:
Raphael transforms are absolute, not relative. So, it rotates to one degree, then rotates to the same position. You're not telling it to rotate by one degree 100 times, you're telling it to rotate to one degree 100 times.
Fix this by keeping track of the rotation position, and incrementing it.
The for loop just happens, more or less instantaneously. So after you fix the first problem, you'll find the animations just jump to the end, regardless of the 10 milisecond delay, because they are all called at more or less the same time. It calls the function 100 times in the space of barely 1 milisecond, and each function call takes 10 ms to animate, so it's reached the end of the 100th rotation in less than 11 miliseconds - not the 1000 miliseconds you probably want.
Fix this by calling the next animation in Raphael's animate callback parameter
Here's an example that I think is more like what you were hoping for:
http://jsbin.com/oxufuh/1/edit
This is in part an EaselJS problem and in part a Physics/animation programming question.
I'm trying to learn EaselJS by studying the examples included in the EaselJS zip file. Right now, I'm looking at the SimpleTransform example,(http://bit.ly/LebvtV) where the robot rotates and fades into the background and expands towards the foreground. I find this effect really cool, and would like to learn how to achieve it. However, when I came to this set of code, I'm lost:
function tick() {
angle += 0.025;
var value = (Math.sin(angle) * 360);
bmp.setTransform (bmp.x , bmp.y , bmp.scaleX , bmp.scaleY , value/2 , bmp.skewX, bmp.skewY , bmp.regX , bmp.regY );
bmp.scaleX = bmp.scaleY = ((value)/360) + 0.25;
stage.update();
}
(For those unfamiliar with EaselJS, tick() is a function that dictates the actions on each tick, whose interval is set with setFPS. So if I've set FPS to be 20, then tick() will execute its statements 20 times in a second. I believe. And bmp here is a Bitmap object that points to the robot image.)
I've never been a wizard in Math, but I do understand the basics. I can see that angle += 0.025; is used to increased the angle variable so that the value passed into setTransform can change with time. However, I can't understand why a) 0.025 is used. b) what (Math.sin(angle) * 360) and ((value)/360) + 0.25 means, and c) why value is not just passed into setTransform, but divided by 2 (value/2).
I know it might be a challenge to explain this here, but any help is appreciated. In fact, if anyone thinks I'm a noob and needs to go study some Physics first, I'll most appreciate if someone can point me to a resource (book/url) for me to turn to.
Thanks in advance.
I can understand why you are confused. The code isn't efficient and that makes it harder to figure out what is going on. But here is the gist of it:
a) 0.025 is used because it is approximately π/125. With a Ticker speed of 25FPS, this means that the angle value will start at 0 and get to π at just about 5 seconds. π is used because Math.sin uses radians, not degrees (π radians == 180 degrees)
b) Math.sin(angle) will essentially start at 0, increase until it hits 1, decrease until it hits -1, then increase back to 0 -- all over a period of 10 seconds with sinusoidal rhythm.
(Math.sin(angle) * 360) has the same behavior as Math.sin(angle), just with a range of -360 to 360.
((value)/360) + 0.25) has the same behavior as Math.sin(angle), just with a range of -0.75 to 1.25.
c) value/2 is there so the robot only rotates 180 degrees instead of 360 degrees. I know what you are thinking -- why multiply by 360 only to divide by 2 one line later? Well, there is no reason for it really.
Here's a slightly clearer version of tick:
function tick() {
angle += Math.PI/125;
var sineValue = Math.sin(angle);
bmp.rotation = sineValue * 180;
bmp.scaleX = bmp.scaleY = sineValue + 0.25;
stage.update();
}
b) The Math.sin(angle)*360 seems like a conversion between degrees and radians.
Math.sin( x ) always evaluates to -1>=x>=1,
and therefore
Math.sin( angle ) is also always -1>=angle>=1
(we just substituted x), and
var value = Math.sin( angle ) * 360 is always -360>=value>=360.
(In the context of degrees rotated that is thus 1 whole rotation left or one whole rotation right).
We can see that the setTransform function exists as follows:
p.setTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {}
Obviously, we can see that there is a direct connection between value & angle. What we further see is that both the transform & scaleX are again depending on value. We can pull the conclusion that each tick there will be -after some calculations- a changing transform and scaleX.
So as the variable 'value' is passed as a parameter, this means that we wish to rotate 'this' much, as much as value tells us (-360>=x>=360). That means, /2 and 0.025 is just configured like this.
Hope this is helpful :-)
I'm using Raphael.js to animate an SVG circle's radius on hover. I like the stock elastic effect that the library offers, but I'd like to increase the amplitude - i.e., make the circle grow and shrink with a lot more gusto when it's hovered - not with extra speed, but to grow larger and shrink smaller when the effect runs.
I copied the elastic function and renamed it super_elastic, and have been tinkering with it here:
http://jsfiddle.net/ryWH3/
I have no idea how the function works, so I've just been tinkering with its numerical values to see what happens. So far I haven't found anything that appears to do what I want. Can anyone recommend any modifications to the function (or a different function altogether) that might do what I'm looking for?
Thanks!
UPDATE:
Thanks for the replies! Sorry, I may not have explained this very well. I'm guessing that the statement "grow larger and shrink smaller" was especially misleading.
I'm aware that the r property affects the final radius of the circle after the animation runs; what I'm trying to do, though, is make the elastic animation "bounce" with greater amplitude. That is, while the animation will still start and end at the same r values that I've set for the circle, I'd like the elastic transition to be a lot more dramatic - expand and contract the circle much more aggressively during the transition before arriving at the final r values. To do this, I'm assuming that I need to modify the equation used in the elastic function to make the effect more dramatic.
Hopefully that makes sense - it's kind of hard to explain without showing an example, but if I had an example, I wouldn't have needed to post this question. ;-)
OK, based on your clarification, here's a new answer. To expand the effect of the easing (amplification), you need to multiply the easing result with a multiplier like this.
return 6 * Math.pow(2, -10 * n) * Math.sin((n - .075) * (2 * Math.PI) / .3) + 1;
But, when you do that, you find that the large part of the amplification goes too fast. The small part goes slow and the large part goes fast. So, the pace when it's larger needs to be changed. My guess (which seems to work) was to change Math.sin() to Math.cos() because that shifts the phase and it seems to work as you can see here: http://jsfiddle.net/jfriend00/fuaNp/39/.
return 6 * Math.pow(2, -10 * n) * Math.cos((n - .075) * (2 * Math.PI) / .3) + 1;
Other things to understand about this easing function. This part:
(2 * Math.PI) / .3
determines how many bounce cycles there are. The larger that multipler is, the more bounces it will have (but the faster the bounces will go). The smaller that multipler is, the fewer bounces it will have (and the slower those bounces will go).
This part:
Math.pow(2, -10 * n)
determines how fast the bounce decays since this value gets smaller the larger n gets which negates the other multipliers as n gets large. So:
Math.pow(2, -5 * n)
makes it decay slower (you see more of the larger swings at the beginning and less of the smaller swings at the end.
To make the circle go larger when you hover over it, you change the hovered radius which I've upped to r: 100 here. To make the circle smaller, you change the initial size and the unhovered size from 25 to something smaller like this:
var paper = Raphael(0, 0, 300, 300),
circle = paper.circle(150, 150, 10); // <== change initial radius here to make it smaller
circle.attr({
'stroke': '#f00',
'stroke-width': 4,
'fill': '#fff'
});
circle.hover(function() {
this.animate({ r: 100 }, 1000, 'super_elastic'); // <== change enlarged size here
}, function() {
this.animate({ r: 10 }, 1000, 'super_elastic'); // <== change small size here
});
// no changes made to the easing function
Raphael.easing_formulas.super_elastic = function(n) {
if (n == !!n) {
return n;
}
return Math.pow(2, -10 * n) * Math.sin((n - .075) * (2 * Math.PI) / .3) + 1;
};
You can see it here: http://jsfiddle.net/jfriend00/fuaNp/.
The super_elastic() function is the easing function which controls what pace the animation moves at different parts of the cycle. Easing doesn't control the overall amplitude. That's done with the parameters to the animate() method.
If you wanted to slow down the animation, you would increase the time of the animation (make the two 1000 arguments to animate() be larger numbers. If you wanted to speed up the animation, you make those two numbers smaller. These are milliseconds for the animation. Smaller numbers means the animation runs in fewer milliseconds (which means faster).