ThreeJS motion - move in a circle over fixed time period - javascript

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

Related

arc to show reload time left in a shooter game

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

N-Body Gravity / Solar System Javascript Simulation

Good day, I am trying to create a simple 2D solar system model in javascript, but am having some trouble understanding how to go about calculating where planets will be for the next frame, aswell as a few other bits which I'll go into detail with soon.
After watching this very nice video and a whole bunch of his others, I made a quick MS paint image to try and simplify my situation.
With the second scene, you can see that the new position is calulated using the velocity, gravitational pull, and the angle between these two 'directions'?
I cannot get my head around how to figure this all out.
Below is a JS fiddle of my code. You'll notice I'm trying my best to use real NASA given data to keep it accurate.
You'll want to look specifically at lines 138 which is where all the calculations for its next move are made.
https://jsfiddle.net/c8eru7mk/9/
attraction: function(p2) {
// Distance to other body
var dx = p2.position.x - this.position.x;
var dy = p2.position.y - this.position.y;
var d = Math.sqrt(dx ** 2 + dy ** 2); // Possibly correct
// Force of attracrtion
this.f = G * (this.mass * p2.mass) / (d ** 2); // Possibly Correct
// Direction of force, If you read it hard enough you should be able to hear my screams of pain
// Not sure if this is correct, most likely not.
var theta = Math.atan2(dy, dx);
var fx = Math.cos(theta) * this.f;
var fy = Math.sin(theta) * this.f;
this.velocity.x += fx / this.mass;
this.velocity.y += fy / this.mass;
this.position.x += this.velocity.x;
this.position.y += this.velocity.y;
}
The problems I'm currently facing are
If I am to use NASA values, the distance between planets is so big, they won't fit on the screen, and I can't simply scale the distances down by multiplying them by 0.0002 or whatever, as that'll mess with the gravitational constant, and the simulation will be completely off.
I have no idea how to caluclate the next position and my brain has imploded several times this past week trying to attempt it several times.
I have no idea on how to check if my configuration data of planets is wrong, or if the simulation is wrong, so I'm pretty much just guessing.
This is also my first time actually coding anything more complex than a button in javascript too, so feedback on code layout and whatnot is welcome!
Many thanks
Using NASA values is not a problem when using separate coordinates for drawing. Using an appropriate linear transfomration from real coordinates to screen coordinatees for displaying does not influence the physical values and computations.
For simulating the motion of a planet with iterative updates one can assume that the gravitational force and the velocity are constant for a small portion of time dt. This factor dt is missing in your conversions from accelration to velocity and from velocity to distance. Choosing an appropriate value for dt may need some experiments. If the value is too big the approximation will be too far off from reality. If the value is too small you may not see any movement or rounding errors may influence the result.
For the beginning let us assume that the sun is always at (0,0). Also for a start let us ignore the forces between the planets. Then here are the necessary formulas for a first not too bad approximation:
scalar acceleration of a planet at position (x,y) by the gravitational force of the sun (with mass M): a = G*M/(d*d) where d=sqrt(x*x+y*y). Note that this is indepent of the planet's mass.
acceleration vector: ax = -a*x/d, ay = -a*y/d (the vector (-x,-y) is pointing towards the sun and must be brought the length a)
change of the planet's velocity (vx,vy): vx += ax*dt, vy += ay*dt
change of the planet's position: x += vx*dt, y += vy*dt

Drag Positioning math

I'm trying to implement a feature where you can drag on your screen to change the Position of an Object.
Right now the object is moving similarly to the change of the mouseX.
What I want is the further down on the screen you drag your mouse, the slower the object moves.
I'm pretty bad at maths so i dont really now how to achieve that in a good way.
Right now I'm doing it like that
factor = Math.abs(e.deltaY)/4;
this.newX = this.currentX + (e.deltaX / factor);
currentX is the start X value of the object.
No idea if it is clear what i want to achieve or if i provided all information, but any help is appreciated!
Your arithmetics always makes step equal to 4.
Consider using some function like exponent. For example,
factor = Exp(- k * Abs(deltaX))
If you want to provide factor 1 at close distances and factor halves per every 100 pixels (I've got arbitrary reasonable values), then
0.5 = exp( - k * 100)
ln(0.5) = -k * 100
k = - ln(0.5) / 100 ~= 0.007
note that I mean multiplicative factor:
factor = Exp(- 0.007 * Abs(deltaX))
this.newX = this.currentX + (e.deltaX * factor);
Now speed will be 1 for small distances, 0.5 for 100, 0.25 for 200, 0.125 for 300 and so on.
If you want another dependence, it is possible to find appropriate function.

How can I determine which half of an elliptical path a point is currently on?

Here is a static frame from an atom animation I'm working on in JavaScript, modelled off this image.
Here is the code used to determine the position of an electron in its orbit based on time:
// Get position along elliptical path.
var x = Math.cos( this.timer.delta() * this.speed ) * ( this.pathWidth / 2 );
var y = Math.sin( this.timer.delta() * this.speed ) * ( this.pathHeight / 2 );
What I'd like to do is place the electron above the nucleus when on the orange part of the path, and below the nucleus during the green segment.
When this.timer.delta() == 0, the electron is at the extreme-right end, and then proceeds to travel counter-clockwise.
I'm looking for help with the following two things:
1) Finding the point in time in which the electron will be at the far left of its orbit.
2) Determining which half of the path an electron is currently on for any given time.
Ideally, the solutions should work regardless of the value of this.speed (which is number multiplier for speeding up or slowing down the animation).
It all depends on the angle - and the angle is this part in your expression:
this.timer.delta() * this.speed
So you can simply determine whether the angle is between zero and PI - and if it is - the nucleus is "in front".
Of course simply checking whether y is non-negative does the same trick.

Understanding Animation/Physics/Math Implemention with EaselJS

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 :-)

Categories

Resources