Box2D (Cocos2D) Constant force over time - xcode

I am a fairly intelligent person, but when I see a certain kind of math I might as well be a gigantic moron. I could really use some help here.
I have been researching a ton of things as I learn iOS game development and I came across a formula while doing some searches. Here is the formula:
x(t) = x(0) + v(0)*t + .5 (F/m) * t^2
Also stated was solving for x and y:
Fx = (x(t) - x(0) - vx(0)*t) * 2m/t^2
Fy = (y(t) - y(0) - vy(0)*t) * 2m/t^2
Source: Box2D.org forums
Now for my actual question, what does that mean? Keep in mind that in this situation I am an idiot. It would be great if someone could explain the variables in simple terms and how they relate to box2d. How would I apply this formula? Here is an example of my code (firing projectiles):
- (void)spawnProjectile:(CGPoint)from direction:(CGPoint)direction inParent:(CCNode*)parentNode
{
double curTime = CACurrentMediaTime();
double timeTillShotDies = curTime + SHOT_TYPE1_EXIST_TIME;
b2Body *shotBody = projectileBodyTracker[nextShot];
b2Vec2 moveToPosition = b2Vec2(from.x/PTM_RATIO, from.y/PTM_RATIO);
shotBody->SetTransform(moveToPosition, 0.0);
shotBody->SetActive(true);
CCSprite *shot = [projectiles objectAtIndex:nextShot];
shot.position = ccp(from.x/PTM_RATIO, from.y/PTM_RATIO);
shot.visible = YES;
[projectilesTracker replaceObjectAtIndex:nextShot withObject:[NSNumber numberWithDouble:timeTillShotDies]];
CCParticleSystemQuad *particle = [projectileParticleTracker objectAtIndex:nextShot];
[particle resetSystem];
nextShot++;
if(nextShot >= projectiles.count) nextShot = 0;
// dx2 and dy2 are analog stick values (see below code)
b2Vec2 force = b2Vec2(dx2, dy2);
shotBody->SetLinearVelocity(force);
[AudioController playLaserShot];
}
In this particular chunk of code I am firing from the player at the angle the analog is at. I also would need to use the formula to fire from the enemy to the player. This is a top down space shooter.
So to summarize, how do I solve constant force over time for x and y, in terms of box2d code?
Extra info:
dx2 = (float)joypadBG2.position.x - (float)convertedPoint.x;
dy2 = (float)joypadBG2.position.y - (float)convertedPoint.y;
All objects are preloaded and kept that way. Bodies are set inactive and sprites set invisible. Particle systems are stopped. The opposite is true for using a projectile again.
Thank you very much for any help you may be able to provide. I hope I haven't forgotten anything.

The first equation describes the movement of an object that is subject to a constant force.
The object starts at position x(0) and has speed v(0). Both x and v are vectors, so in a 2d shooter, x(0) would be (x0,y0), or the xy-position, and v(0) would be (vx0, vy0).
If there is no gravity then F=0 on unpropelled projectiles (projectiles without thrusters),
so the velocity will be constant.
x(t1) = x(t0) + vx * (t1-t0)
y(t1) = y(t0) + vy * (t1-t0)
t1-t0 or dt (delta-t) is the time elapsed since the last time you updated the position of the projectile.
If thusters or gravity are excerting force on an object then the velocity will change over time.
vx(t1) = vx(t0) + ax * (t1-t0)
vy(t1) = vy(t0) + ay * (t1-t0)
a is the acceleration. In a game you usually don't care about mass and force, just acceleration. In physics, a = F/m.
Edit 1:
In computer games, you update the position of an object very frequently (typically around 60 times per second). You have the position and velocity of the object at the previous update and you want to calculate the new position.
You update the position by assuming that the velocity was constant:
positionVectorAt(newTime) = positionVector(lastTime) + velocityVector*(newTime - lastTime);
If the velocity of the object is changed you also update the velocity:
velocityVectorAt(newTime) = velocityVector(lastTime) + accelerationVector*(newTime - lastTime);
Let's say we have a sprite at
positionVector.x=100;
positionVector.y=10;
The initial speed is
velocityVector.x = 3;
velocityVector.y = -10;
The sprite is using thrusters which is giving a horizonal acceleration per second of
thrusterVector.x= 5;
and it is also subject to gravity which gives a vertical acceleration per second of
gravityVector.y = -10;
The code to update the sprites position will be:
deltaTime = now - lastTime; // Time elapsed since last position update
// Update the position
positionVector.x = positionVector.x + velocityVector.x * deltaTime;
positionVector.y = positionVector.y + velocityVector.y * deltaTime;
// Update the velocity
velocityVector.x = velocityVector.x + (thrusterVector.x + gravityVector.x) * deltaTime;
velocityVector.y = velocityVector.y + (thrusterVector.y + gravityVector.y) * deltaTime;
// Done! The sprite now has a new position and a new velocity!

Here is a quick explanation:
x(t) = x(0) + v(0)*t + .5 (F/m) * t^2
Fx = (x(t) - x(0) - vx(0)*t) * 2m/t^2
Fy = (y(t) - y(0) - vy(0)*t) * 2m/t^2
These 3 equations are standard movement ones:
t: time
x(t): position at time t
v(t): speed at time t
vx(t): horizontal component of speed at time t
vy(t): vertical component of speed at time t
m: mass
F: force
Fx: horizontal component of the force
Fy: vertical component of the force
So of course, each time you see x(0) or vy(0), these values are taken at time t, i.e. they are initial values. These equations are basic cinematic equations with the basic cinematic variables (position, speed, force, mass).

Related

How to calculate the trajectory of an object with an initial velocity so that it stops at a given point

The subject comes from an old challenge on codingame.com.
The play area was a rectangle of 10000 x 8000 units.
I have an object with a position (objectX, objectY) and a velocity vector (speedX, speedY).
I have an object with a position (objectX, objectY) and a velocity vector (speedX, speedY).
To move this object, I have to display the coordinates (thrustX, thrustY) of the thrust destination followed by a thrust value (ranging from -100 to 100).
Friction: Each steps (ticks), previous speed vector is multiplied by 0.9 before applying thrust
I want to move and stop this objet at a point with coordinates targetX, targetY (with a given error rate).
How to calculate the list of targetX, targetY and thrustValue ?
Following example use these data:
initial objectX and objectY = 1000, 2500
initial speedX and speedY = -500, 1000
targetX, targetY = 8000, 3000
thrustX, thrustX = targetX, targetY
This table use these formulas:
objectX(step) = objectX(step-1) + speedX(step)
objectY(step) = objectY(step-1) + speedY(step)
speedX(step) = speedX(step-1)*0.9 + thrustX(step-1)
speedY(step) = speedY(step-1)*0.9 + thrustY(step-1)
angle(step) = degrees(atan2(targetX(step) - objectX(step); targetY(step) - objectY(step)))
thrustX(step) = cos(radians(angle(step))) * thrust(step)
thrustY(step) = sin(radians(angle(step))) * thrust(step)
I want to find the algorithm that would make me get directly to the target rather than turn around

how to figure out cursive paths for an enemy to follow

The Problem
I am making a game where enemies appear at some point on the screen then follow a smooth curvy path and disappear at some point. I can make them follow a straight path but can't figure out the way to make them follow the paths depicted in the image.
Attempts
I started with parabolic curve and implemented them successfully. I just used the equation of parabola to calculate the coordinates gradually. I have no clue what is the equation for desired paths supposed to be.
What I want
I am not asking for the code.I just want someone to explain me the general technique.If you still want to show some code then I don't have special preference for programming language for this particular question you can use C,Java or even pseudo-code.
First you need to represent each curve with a set of points over time, For example:
-At T(0) the object should be at (X0, Y0).
-At T(1) the object should be at (X1, Y1).
And the more points you have, the more smooth curve you will get.
Then you will use those set of points to generate two formulas-one for X, and another one for Y-, using any Interpolation method, like The La-grange's Interpolation Formula:
Note that you should replace 'y' with the time T, and replace 'x' with your X for X formula, and Y for Y formula.
I know you hoped for a simple equation, but unfortunately this is will take from you a huge effort to simplify each equation, and my advise DON'T do it unless it's worth it.
If you are seeking for a more simple equation to perform well in each frame in your game you should read about SPline method, In this method is about splitting your curve into a smaller segments, and make a simple equation for every segment, for example:
Linear Spline:
Every segment contains 2 points, this will draw a line between every two points.
The result will be some thing like this:
Or you could use quadratic spline, or cubic spline for more smooth curves, but it will slow your game performance. You can read more about those methods here.
I think linear spline will be great for you with reasonable set of points for each curve.
Please change the question title to be more generic.
If you want to generate a spiral path you need.
Total time
How many full rotations
Largest radius
So, total time T_f = 5sec, rotations R_f = 2.5 * 2 * PI, the final distance from the start D_f = 200px
function SpiralEnemy(spawnX, spawnY, time) {
this.startX = spawnX;
this.startY = spawnY;
this.startTime = time;
// these will change and be used for rendering
this.x = this.startX;
this.y = this.startY;
this.done = false;
// constants we figured out above
var TFinal = 5.0;
var RFinal = -2.6 * 2 * Math.PI;
var RStart = -Math.PI / 2;
var DFinal = 100;
// the update function called every animation tick with the current time
this.update = function(t) {
var delta = t - this.startTime;
if(delta > TFinal) {
this.done = true;
return;
}
// find out how far along you are in the animation
var percent = delta / TFinal;
// what is your current angle of rotation (in radians)
var angle = RStart + RFinal * percent;
// how far from your start point should you be
var dist = DFinal * percent;
// update your coordinates
this.x = this.startX + Math.cos(angle) * dist;
this.y = this.startY + Math.sin(angle) * dist;
};
}
EDIT Here's a jsfiddle to mess with http://jsfiddle.net/pxb3824z/
EDIT 2 Here's a loop (instead of spiral) version http://jsfiddle.net/dpbLxuz7/
The loop code splits the animation into 2 parts the beginning half and the end half.
Beginning half : angle = Math.tan(T_percent) * 2 and dist = Speed + Speed * (1 - T_percent)
End half : angle = -Math.tan(1 - T_percent) * 2 and dist = **Speed + Speed * T_percent
T_percent is normalized to (0, 1.0) for both halfs.
function LoopEnemy(spawnX, spawnY, time) {
this.startX = spawnX;
this.startY = spawnY;
this.startTime = time;
// these will change and be used for rendering
this.x = this.startX;
this.y = this.startY;
this.last = time;
this.done = false;
// constants we figured out above
var TFinal = 5.0;
var RFinal = -2 * Math.PI;
var RStart = 0;
var Speed = 50; // px per second
// the update function called every animation tick with the current time
this.update = function(t) {
var delta = t - this.startTime;
if(delta > TFinal) {
this.done = true;
return;
}
// find out how far along you are in the animation
var percent = delta / TFinal;
var localDelta = t - this.last;
// what is your current angle of rotation (in radians)
var angle = RStart;
var dist = Speed * localDelta;
if(percent <= 0.5) {
percent = percent / 0.5;
angle -= Math.tan(percent) * 2;
dist += dist * (1 - percent);
} else {
percent = (percent - 0.5) / 0.5;
angle -= -Math.tan(1 - percent) * 2;
dist += dist * percent;
}
// update your coordinates
this.last = t;
this.x = this.x + Math.cos(angle) * dist;
this.y = this.y + Math.sin(angle) * dist;
};
}
Deriving the exact distance traveled and the height of the loop for this one is a bit more work. I arbitrarily chose a Speed of 50px / sec, which give a final x offset of ~+145 and a loop height of ~+114 the distance and height will scale from those values linearly (ex: Speed=25 will have final x at ~73 and loop height of ~57)
I don't understand how you give a curve. If you need a curve depicted on the picture, you can find a curve is given analytically and use it. If you have not any curves you can send me here: hedgehogues#bk.ru and I will help find you. I leave e-mail here because I don't get any messages about answers of users from stackoverflow. I don't know why.
If you have some curves in parametric view in [A, B], you can write a code like this:
struct
{
double x, y;
}SPoint;
coord = A;
step = 0.001
eps = 1e-6;
while (coord + step - eps < B)
{
SPoint p1, p2;
p1.x = x(coord);
p1.y = y(coord);
coord += step;
p2.x = x(coord);
p2.y = y(coord);
drawline(p1, p2);
}

Camera speed dependent on 3D scene extents

I'm working on a 3D scene viewer with the HOOPS Engine
I want to implement support for a 3D mouse. Everything is working fine but there is one remaining problem I don't know how to solve:
I move my camera with following formula:
HC_Dolly_Camera(-(factor.x * this->m_speed), factor.y * this->m_speed, factor.z * this->m_speed);
this->m_speed is dependent on scene extents. But if the scene is really big (e.g. a airport) the camera speed is on a deep zoom level ridiculous fast.
My first attempt was to implement a kind of damping factor which is dependent on the distance from objects to my camera. It works ... somehow. Sometimes I noticed ugly "bouncing effects" which I can avoid with smooth acceleration and a modified cosine function.
But my question is: Is there a best practice to reduce camera speed in closeup situations in a 3D scene? My approach is working, but I think it is not a good solution due it uses many raycasts.
Best regards,
peekaboo777
P.S.:
My code
if(!this->smooth_damping)
{
if(int res = HC_Compute_Selection_By_Area(this->view->GetDriverPath(), ".", "v", -0.5, 0.5, -0.5, 0.5) > 0)
{
float window_x, window_y, window_z, camera_x, camera_y, camera_z;
double dist_length = 0;
double shortest_dist = this->max_world_extent;
while(HC_Find_Related_Selection())
{
HC_Show_Selection_Position(&window_x, &window_y, &window_z, &camera_x, &camera_y, &camera_z);
this->view->GetCamera(&this->cam);
// Compute distance vector
this->dist.Set(cam.position.x - camera_x, cam.position.y - camera_y, cam.position.z - camera_z);
dist_length = sqrt(pow((cam.position.x - camera_x), 2) + pow((cam.position.y - camera_y), 2) + pow((cam.position.z - camera_z), 2));
if(dist_length < shortest_dist)
shortest_dist = dist_length;
}
// Reduced computation
// Compute damping factor
damping_factor = ((1 - 8) / (this->max_world_extent - 1)) * (shortest_dist - 1) + 8;
// Difference to big? (Gap)
if(qFabs(damping_factor - damping_factor * 0.7) < qFabs(damping_factor - this->last_damping_factor))
{
this->smooth_damping = true;
this->damping_factor_to_reach = damping_factor; // this is the new damping factor we have to reach
this->freezed_damping_factor = this->last_damping_factor; // damping factor before gap.
if(this->last_damping_factor > damping_factor) // Negative acceleration
{
this->acceleration = false;
}
else // Acceleration
{
this->acceleration = true;
}
}
else
{
this->last_damping_factor = damping_factor;
}
}
}
else
{
if(this->acceleration)
{
if(this->freezed_damping_factor -= 0.2 >= 1);
damping_factor = this->freezed_damping_factor +
(((this->damping_factor_to_reach - this->freezed_damping_factor) / 2) -
((this->damping_factor_to_reach - this->freezed_damping_factor) / 2) *
qCos(M_PI * this->damping_step)); // cosine function between freezed and to reach
this->last_damping_factor = damping_factor;
if(damping_factor >= this->damping_factor_to_reach)
{
this->smooth_damping = false;
this->damping_step = 0;
this->freezed_damping_factor = 0;
} // Reset
}
else
{
if(this->freezed_damping_factor += 0.2 >= 1);
damping_factor = this->damping_factor_to_reach +
((this->freezed_damping_factor - this->damping_factor_to_reach) -
(((this->freezed_damping_factor - this->damping_factor_to_reach) / 2) -
((this->freezed_damping_factor - this->damping_factor_to_reach) / 2) *
qCos(M_PI * this->damping_step))); // cosine functio between to reach and freezed
this->last_damping_factor = damping_factor;
if(damping_factor <= this->damping_factor_to_reach)
{
this->smooth_damping = false;
this->damping_step = 0;
this->freezed_damping_factor = 0;
} // Reset
}
this->damping_step += 0.01; // Increase the "X"
}
I've never used the HOOPS engine, but do you have any way to get the closest object to the camera? You could scale your speed with this value, so your camera gets slower close to objects.
Even better would be to take the closest point on bounding-box instead of center of object. This would improve the behaviour close to big objects like long walls/floor.
Another solution I'd try would be to raycast through the view center to look for the first object and use the distance the same way. In this approach you'll not be slowed down by objects behind you. You may also add additional raycast points, like in 1/4 of screen and blend resulting values, so you have more constant speed scale.
What I understand from your question is that you want a way to steer camera through large scenes, like an airport and still be able to move slowly close to the objects. I don't think there's some 'universal' way of doing it. All will depend on your Engine/API features and specific needs. If all those solutions doesn't work, maybe you should try with paper and pen ;) .
You said that m_speed is dependent on scene extent, I guess this dependency is linear (by linear I mean if you are measuring the scene extend with something called sExtent, m_speed equals c*sExtent that c is some constant coefficient).
So to make m_speed dependent on scene extent but avoid huge m_speed for large scale scenes , I suggest to make dependency of m_speed to sExtent non-linear, like logarithmic dependency:
m_speed = c*log(sExtent+1)
This way your m_speed will be bigger if scene is bigger, but not in the same ratio. you also can use radical to create non-linear dependency. below you can compare these functions:

interpolate between rotation matrices

i have two rotation matrices that describe arbitrary rotations. (4x4 opengl compatible)
now i want to interpolate between them, so that it follows a radial path from one rotation to the other. think of a camera on a tripod looking one way and then rotating.
if i interpolate every component i get a squeezing result, so i think i need to interpolate only certain components of the matrix. but which ones?
You have to use SLERP for the rotational parts of the matrices, and linear for the other parts. The best way is to turn your matrices into quaternions and use the (simpler) quaternion SLERP: http://en.wikipedia.org/wiki/Slerp.
I suggest reading Graphic Gems II or III,specifically the sections about decomposing matrices into simpler transformations. Here's Spencer W. Thomas' source for this chapter:
http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c
Of course, I suggest you learn how to do this yourself. It's really not that hard, just a lot of annoying algebra. And finally, here's a great paper on how to turn a matrix into a quaternion, and back, by Id software: http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf
Edit: This is the formula pretty much everyone cites, it's from a 1985 SIGGRAPH paper.
Where:
- qm = interpolated quaternion
- qa = quaternion a (first quaternion to be interpolated between)
- qb = quaternion b (second quaternion to be interpolated between)
- t = a scalar between 0.0 (at qa) and 1.0 (at qb)
- θ is half the angle between qa and qb
Code:
quat slerp(quat qa, quat qb, double t) {
// quaternion to return
quat qm = new quat();
// Calculate angle between them.
double cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
// if qa=qb or qa=-qb then theta = 0 and we can return qa
if (abs(cosHalfTheta) >= 1.0){
qm.w = qa.w;qm.x = qa.x;qm.y = qa.y;qm.z = qa.z;
return qm;
}
// Calculate temporary values.
double halfTheta = acos(cosHalfTheta);
double sinHalfTheta = sqrt(1.0 - cosHalfTheta*cosHalfTheta);
// if theta = 180 degrees then result is not fully defined
// we could rotate around any axis normal to qa or qb
if (fabs(sinHalfTheta) < 0.001){ // fabs is floating point absolute
qm.w = (qa.w * 0.5 + qb.w * 0.5);
qm.x = (qa.x * 0.5 + qb.x * 0.5);
qm.y = (qa.y * 0.5 + qb.y * 0.5);
qm.z = (qa.z * 0.5 + qb.z * 0.5);
return qm;
}
double ratioA = sin((1 - t) * halfTheta) / sinHalfTheta;
double ratioB = sin(t * halfTheta) / sinHalfTheta;
//calculate Quaternion.
qm.w = (qa.w * ratioA + qb.w * ratioB);
qm.x = (qa.x * ratioA + qb.x * ratioB);
qm.y = (qa.y * ratioA + qb.y * ratioB);
qm.z = (qa.z * ratioA + qb.z * ratioB);
return qm;
}
From: http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
You need to convert the matrix into a different representation - quaternions work well for this, and interpolating quaternions is a well-defined operation.

What are some algorithms that will allow me to simulate planetary physics?

I'm interested in doing a "Solar System" simulator that will allow me to simulate the rotational and gravitational forces of planets and stars.
I'd like to be able to say, simulate our solar system, and simulate it across varying speeds (ie, watch Earth and other planets rotate around the sun across days, years, etc). I'd like to be able to add planets and change planets mass, etc, to see how it would effect the system.
Does anyone have any resources that would point me in the right direction for writing this sort of simulator?
Are there any existing physics engines which are designed for this purpose?
It's everything here and in general, everything that Jean Meeus has written.
You need to know and understand Newton's Law of Universal Gravitation and Kepler's Laws of Planetary Motion. These two are simple and I'm sure you've heard about them, if not studied them in high school. Finally, if you want your simulator to be as accurate as possible, you should familiarize yourself with the n-Body problem.
You should start out simple. Try making a Sun object and an Earth object that revolves around it. That should give you a very solid start and it's fairly easy to expand from there. A planet object would look something like:
Class Planet {
float x;
float y;
float z; // If you want to work in 3D
double velocity;
int mass;
}
Just remember that F = MA and the rest just just boring math :P
This is a great tutorial on N-body problems in general.
http://www.artcompsci.org/#msa
It's written using Ruby but pretty easy to map into other languages etc. It covers some of the common integration approaches; Forward-Euler, Leapfrog and Hermite.
You might want to take a look at Celestia, a free space simulator. I believe that you can use it to create fictitious solar systems and it is open source.
All you need to implement is proper differential equation (Keplers law) and using Runge-Kutta. (at lest this worked for me, but there are probably better methods)
There are loads of such simulators online.
Here is one simple one implemented in 500lines of c code. (montion algorhitm is much less)
http://astro.berkeley.edu/~dperley/programs/ssms.html.
Also check this:
http://en.wikipedia.org/wiki/Kepler_problem
http://en.wikipedia.org/wiki/Two-body_problem
http://en.wikipedia.org/wiki/N-body_problem
In physics this is known as the N-Body Problem. It is famous because you can not solve this by hand for a system with more than three planets. Luckily, you can get approximate solutions with a computer very easily.
A nice paper on writing this code from the ground up can be found here.
However, I feel a word of warning is important here. You may not get the results you expect. If you want to see how:
the mass of a planet affects its orbital speed around the Sun, cool. You will see that.
the different planets interact with each other, you will be bummed.
The problem is this.
Yeah, modern astronomers are concerned with how Saturn's mass changes the Earth's orbit around the Sun. But this is a VERY minor effect. If you are going to plot the path of a planet around the Sun, it will hardly matter that there are other planets in the Solar System. The Sun is so big it will drown out all other gravity. The only exceptions to this are:
If your planets have very elliptical orbits. This will cause the planets to potentially get closer together, so they interact more.
If your planets are almost the exact same distance from the Sun. They will interact more.
If you make your planets so comically large they compete with the Sun for gravity in the outer Solar System.
To be clear, yes, you will be able to calculate some interactions between planets. But no, these interactions will not be significant to the naked eye if you create a realistic Solar System.
Try it though, and find out!
Check out nMod, a n-body modeling toolkit written in C++ and using OpenGL. It has a pretty well populated solar system model that comes with it and it should be easy to modify. Also, he has a pretty good wiki about n-body simulation in general. The same guy who created this is also making a new program called Moody, but it doesn't appear to be as far along.
In addition, if you are going to do n-body simulations with more than just a few objects, you should really look at the fast multipole method (also called the fast multipole algorithm). It can the reduce number of computations from O(N^2) to O(N) to really speed up your simulation. It is also one of the top ten most successful algorithms of the 20th century, according to the author of this article.
Algorithms to simulate planetary physics.
Here is an implementation of the Keppler parts, in my Android app. The main parts are on my web site for you can download the whole source: http://www.barrythomas.co.uk/keppler.html
This is my method for drawing the planet at the 'next' position in the orbit. Think of the steps like stepping round a circle, one degree at a time, on a circle which has the same period as the planet you are trying to track. Outside of this method I use a global double as the step counter - called dTime, which contains a number of degrees of rotation.
The key parameters passed to the method are, dEccentricty, dScalar (a scaling factor so the orbit all fits on the display), dYear (the duration of the orbit in Earth years) and to orient the orbit so that perihelion is at the right place on the dial, so to speak, dLongPeri - the Longitude of Perihelion.
drawPlanet:
public void drawPlanet (double dEccentricity, double dScalar, double dYear, Canvas canvas, Paint paint,
String sName, Bitmap bmp, double dLongPeri)
{
double dE, dr, dv, dSatX, dSatY, dSatXCorrected, dSatYCorrected;
float fX, fY;
int iSunXOffset = getWidth() / 2;
int iSunYOffset = getHeight() / 2;
// get the value of E from the angle travelled in this 'tick'
dE = getE (dTime * (1 / dYear), dEccentricity);
// get r: the length of 'radius' vector
dr = getRfromE (dE, dEccentricity, dScalar);
// calculate v - the true anomaly
dv = 2 * Math.atan (
Math.sqrt((1 + dEccentricity) / (1 - dEccentricity))
*
Math.tan(dE / 2)
);
// get X and Y coords based on the origin
dSatX = dr / Math.sin(Math.PI / 2) * Math.sin(dv);
dSatY = Math.sin((Math.PI / 2) - dv) * (dSatX / Math.sin(dv));
// now correct for Longitude of Perihelion for this planet
dSatXCorrected = dSatX * (float)Math.cos (Math.toRadians(dLongPeri)) -
dSatY * (float)Math.sin(Math.toRadians(dLongPeri));
dSatYCorrected = dSatX * (float)Math.sin (Math.toRadians(dLongPeri)) +
dSatY * (float)Math.cos(Math.toRadians(dLongPeri));
// offset the origin to nearer the centre of the display
fX = (float)dSatXCorrected + (float)iSunXOffset;
fY = (float)dSatYCorrected + (float)iSunYOffset;
if (bDrawOrbits)
{
// draw the path of the orbit travelled
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
// get the size of the rect which encloses the elliptical orbit
dE = getE (0.0, dEccentricity);
dr = getRfromE (dE, dEccentricity, dScalar);
rectOval.bottom = (float)dr;
dE = getE (180.0, dEccentricity);
dr = getRfromE (dE, dEccentricity, dScalar);
rectOval.top = (float)(0 - dr);
// calculate minor axis from major axis and eccentricity
// http://www.1728.org/ellipse.htm
double dMajor = rectOval.bottom - rectOval.top;
double dMinor = Math.sqrt(1 - (dEccentricity * dEccentricity)) * dMajor;
rectOval.left = 0 - (float)(dMinor / 2);
rectOval.right = (float)(dMinor / 2);
rectOval.left += (float)iSunXOffset;
rectOval.right += (float)iSunXOffset;
rectOval.top += (float)iSunYOffset;
rectOval.bottom += (float)iSunYOffset;
// now correct for Longitude of Perihelion for this orbit's path
canvas.save();
canvas.rotate((float)dLongPeri, (float)iSunXOffset, (float)iSunYOffset);
canvas.drawOval(rectOval, paint);
canvas.restore();
}
int iBitmapHeight = bmp.getHeight();
canvas.drawBitmap(bmp, fX - (iBitmapHeight / 2), fY - (iBitmapHeight / 2), null);
// draw planet label
myPaint.setColor(Color.WHITE);
paint.setTextSize(30);
canvas.drawText(sName, fX+20, fY-20, paint);
}
The method above calls two further methods which provide values of E (the mean anomaly) and r, the length of the vector at the end of which the planet is found.
getE:
public double getE (double dTime, double dEccentricity)
{
// we are passed the degree count in degrees (duh)
// and the eccentricity value
// the method returns E
double dM1, dD, dE0, dE = 0; // return value E = the mean anomaly
double dM; // local value of M in radians
dM = Math.toRadians (dTime);
int iSign = 1;
if (dM > 0) iSign = 1; else iSign = -1;
dM = Math.abs(dM) / (2 * Math.PI); // Meeus, p 206, line 110
dM = (dM - (long)dM) * (2 * Math.PI) * iSign; // line 120
if (dM < 0)
dM = dM + (2 * Math.PI); // line 130
iSign = 1;
if (dM > Math.PI) iSign = -1; // line 150
if (dM > Math.PI) dM = 2 * Math.PI - dM; // line 160
dE0 = Math.PI / 2; // line 170
dD = Math.PI / 4; // line 170
for (int i = 0; i < 33; i++) // line 180
{
dM1 = dE0 - dEccentricity * Math.sin(dE0); // line 190
dE0 = dE0 + dD * Math.signum((float)(dM - dM1));
dD = dD / 2;
}
dE = dE0 * iSign;
return dE;
}
getRfromE:
public double getRfromE (double dE, double dEccentricty, double dScalar)
{
return Math.min(getWidth(), getHeight()) / 2 * dScalar * (1 - (dEccentricty * Math.cos(dE)));
}
It looks like it is very hard and requires strong knowledge of physics but in fact it is very easy, you need to know only 2 formulas and basic understanding of vectors:
Attractional force (or gravitational force) between planet1 and planet2 with mass m1 and m2 and distance between them d: Fg = G*m1*m2/d^2; Fg = m*a. G is a constant, find it by substituting random values so that acceleration "a" will not be too small and not too big approximately "0.01" or "0.1".
If you have total vector force which is acting on a current planet at that instant of time, you can find instant acceleration a=(total Force)/(mass of current planet). And if you have current acceleration and current velocity and current position, you can find new velocity and new position
If you want to look it real you can use following supereasy algorythm (pseudocode):
int n; // # of planets
Vector2D planetPosition[n];
Vector2D planetVelocity[n]; // initially set by (0, 0)
double planetMass[n];
while (true){
for (int i = 0; i < n; i++){
Vector2D totalForce = (0, 0); // acting on planet i
for (int j = 0; j < n; j++){
if (j == i)
continue; // force between some planet and itself is 0
Fg = G * planetMass[i] * planetMass[j] / distance(i, j) ^ 2;
// Fg is a scalar value representing magnitude of force acting
// between planet[i] and planet[j]
// vectorFg is a vector form of force Fg
// (planetPosition[j] - planetPosition[i]) is a vector value
// (planetPosition[j]-planetPosition[i])/(planetPosition[j]-plantetPosition[i]).magnitude() is a
// unit vector with direction from planet[i] to planet[j]
vectorFg = Fg * (planetPosition[j] - planetPosition[i]) /
(planetPosition[j] - planetPosition[i]).magnitude();
totalForce += vectorFg;
}
Vector2D acceleration = totalForce / planetMass[i];
planetVelocity[i] += acceleration;
}
// it is important to separate two for's, if you want to know why ask in the comments
for (int i = 0; i < n; i++)
planetPosition[i] += planetVelocity[i];
sleep 17 ms;
draw planets;
}
If you're simulating physics, I highly recommend Box2D.
It's a great physics simulator, and will really cut down the amount of boiler plate you'll need, with physics simulating.
Fundamentals of Astrodynamics by Bate, Muller, and White is still required reading at my alma mater for undergrad Aerospace engineers. This tends to cover the orbital mechanics of bodies in Earth orbit...but that is likely the level of physics and math you will need to start your understanding.
+1 for #Stefano Borini's suggestion for "everything that Jean Meeus has written."
Dear Friend here is the graphics code that simulate solar system
Kindly refer through it
/*Arpana*/
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<math.h>
#include<dos.h>
void main()
{
int i=0,j=260,k=30,l=150,m=90;
int n=230,o=10,p=280,q=220;
float pi=3.1424,a,b,c,d,e,f,g,h,z;
int gd=DETECT,gm;
initgraph(&gd,&gm,"c:\tc\bgi");
outtextxy(0,10,"SOLAR SYSTEM-Appu");
outtextxy(500,10,"press any key...");
circle(320,240,20); /* sun */
setfillstyle(1,4);
floodfill(320,240,15);
outtextxy(310,237,"sun");
circle(260,240,8);
setfillstyle(1,2);
floodfill(258,240,15);
floodfill(262,240,15);
outtextxy(240,220,"mercury");
circle(320,300,12);
setfillstyle(1,1);
floodfill(320,298,15);
floodfill(320,302,15);
outtextxy(335,300,"venus");
circle(320,160,10);
setfillstyle(1,5);
floodfill(320,161,15);
floodfill(320,159,15);
outtextxy(332,150, "earth");
circle(453,300,11);
setfillstyle(1,6);
floodfill(445,300,15);
floodfill(448,309,15);
outtextxy(458,280,"mars");
circle(520,240,14);
setfillstyle(1,7);
floodfill(519,240,15);
floodfill(521,240,15);
outtextxy(500,257,"jupiter");
circle(169,122,12);
setfillstyle(1,12);
floodfill(159,125,15);
floodfill(175,125,15);
outtextxy(130,137,"saturn");
circle(320,420,9);
setfillstyle(1,13);
floodfill(320,417,15);
floodfill(320,423,15);
outtextxy(310,400,"urenus");
circle(40,240,9);
setfillstyle(1,10);
floodfill(38,240,15);
floodfill(42,240,15);
outtextxy(25,220,"neptune");
circle(150,420,7);
setfillstyle(1,14);
floodfill(150,419,15);
floodfill(149,422,15);
outtextxy(120,430,"pluto");
getch();
while(!kbhit()) /*animation*/
{
a=(pi/180)*i;
b=(pi/180)*j;
c=(pi/180)*k;
d=(pi/180)*l;
e=(pi/180)*m;
f=(pi/180)*n;
g=(pi/180)*o;
h=(pi/180)*p;
z=(pi/180)*q;
cleardevice();
circle(320,240,20);
setfillstyle(1,4);
floodfill(320,240,15);
outtextxy(310,237,"sun");
circle(320+60*sin(a),240-35*cos(a),8);
setfillstyle(1,2);
pieslice(320+60*sin(a),240-35*cos(a),0,360,8);
circle(320+100*sin(b),240-60*cos(b),12);
setfillstyle(1,1);
pieslice(320+100*sin(b),240-60*cos(b),0,360,12);
circle(320+130*sin(c),240-80*cos(c),10);
setfillstyle(1,5);
pieslice(320+130*sin(c),240-80*cos(c),0,360,10);
circle(320+170*sin(d),240-100*cos(d),11);
setfillstyle(1,6);
pieslice(320+170*sin(d),240-100*cos(d),0,360,11);
circle(320+200*sin(e),240-130*cos(e),14);
setfillstyle(1,7);
pieslice(320+200*sin(e),240-130*cos(e),0,360,14);
circle(320+230*sin(f),240-155*cos(f),12);
setfillstyle(1,12);
pieslice(320+230*sin(f),240-155*cos(f),0,360,12);
circle(320+260*sin(g),240-180*cos(g),9);
setfillstyle(1,13);
pieslice(320+260*sin(g),240-180*cos(g),0,360,9);
circle(320+280*sin(h),240-200*cos(h),9);
setfillstyle(1,10);
pieslice(320+280*sin(h),240-200*cos(h),0,360,9);
circle(320+300*sin(z),240-220*cos(z),7);
setfillstyle(1,14);
pieslice(320+300*sin(z),240-220*cos(z),0,360,7);
delay(20);
i++;
j++;
k++;
l++;
m++;
n++;
o++;
p++;
q+=2;
}
getch();
}

Resources