Question

I have used RK4 for physics in a small 2d game I made , but when it comes to gravity all the objects are being pulled to 0,0 how could I change this?(sorry for no comments not had time yet too comment it)

    #include "Gravity.h"

gravity::accelerationReturn gravity::acceleration(state & state , float time) //Returns a struct instead easier to put into a vector.
{
    accelerationReturn return1;
    const float k =9.8;
    const float b = 1;
    return1.Xaccel =  -k * state.pos.getX() - b* state.vel.getX();
    return1.Yaccel = -k * state.pos.getY() - b* state.vel.getY();
    return return1;
}


gravity::derivative gravity::evaluate(state  & initial, float time, float deltaTime,derivative & Derivative)
{
    state state;
    state.pos.setXY(initial.pos.getX() + Derivative.dpos.getX()*deltaTime,
        initial.pos.getY() - Derivative.dpos.getY()*deltaTime);

    state.vel.setXY(initial.vel.getX() + Derivative.dvel.getX() * deltaTime,
        initial.vel.getY() + Derivative.dvel.getY() * deltaTime);

        derivative output;
        output.dpos.setXY(state.vel.getX(),state.vel.getY());
        output.dvel.setXY(acceleration(state,time + deltaTime).Xaccel,
            acceleration(state,time + deltaTime).Yaccel);
        return output;

}

void gravity::integrate(state & State , float time, float deltaTime)
{

    derivative a = evaluate(State ,time,0.0f,derivative());
    derivative b = evaluate(State,time,deltaTime * 0.5f,a);
    derivative c = evaluate(State,time,deltaTime * 0.5f,b);
    derivative d = evaluate(State,time,deltaTime,c);

    Vector dpdt;
    Vector dvdt;
    dpdt.setXY((1.0f/10.0f * (a.dpos.getX() + 2.0f * (b.dpos.getX() + c.dpos.getX()) + d.dpos.getX())),
              (1.0f/10.0f * (a.dpos.getY() + 2.0f * (b.dpos.getY() + c.dpos.getY()) + d.dpos.getY())));
    dvdt.setXY((1.0f/10.0f * (a.dvel.getX() + 2.0f * (b.dvel.getX() + c.dvel.getX()) + d.dvel.getX())),
               ( 1.0f/10.0f * (a.dvel.getY() + 2.0f * (b.dvel.getY() + c.dvel.getY()) + d.dvel.getY())));


    State.pos.setXY ((State.pos.getX() + dpdt.getX() * deltaTime),(State.pos.getY() + dpdt.getY() * deltaTime));
    State.vel.setXY ((State.vel.getX() + dvdt.getX() * deltaTime),(State.vel.getY() + dvdt.getY() * deltaTime));

}

The cpp

#ifndef GRAVITY_H
#define GRAVITY_H

#include "2DVector.h"


class gravity :Vector 
{
private:



    float time; //current time
    float deltaTime; // previous time
public:
    struct accelerationReturn //for returning acceleration
    {
        float Xaccel;
        float Yaccel;
    };
    struct state //current state of object.
    { 
        Vector pos; //position
        Vector vel; //velocity
    };
    struct derivative
    {
        Vector dpos; // derivative of posistion is velocity.
        Vector dvel; // derivative of velocity is acceleration.
    };

    accelerationReturn acceleration (state &,float); //calculates the new acceleration
    derivative evaluate ( state & , float , float ,  derivative &); //gets derived values
    void integrate ( state &, float , float);




};
#endif

main

#include "Gravity.h"
#include <iostream>
#include "SFML\Graphics.hpp"
#include "SFML\System.hpp"

using namespace std;

int main()
{


    gravity grav;
    gravity::state marrio;
    marrio.pos.setXY(500,500); 


    sf::RenderWindow mwindow(sf::VideoMode(800, 800), "my window");
    sf::CircleShape shape(50);
    shape.setFillColor(sf::Color(100,250,250));

    sf::Time timeC;
    float time;
    float dTime = 0.01f;

    sf::Clock timePhysics;
    while(mwindow.isOpen())
    {

               timeC = timePhysics.getElapsedTime();
               time = timeC.asSeconds();
               grav.integrate(marrio,time,dTime);
               time += dTime;
               cout<< "pos     vel"<<endl<<marrio.pos.getX()<<" "<<marrio.pos.getY()<<" "<<
                marrio.vel.getX()<<" "<<marrio.vel.getY()<<endl;
                shape.setPosition(marrio.pos.getX(),marrio.pos.getY());



                mwindow.clear();
                mwindow.draw(shape);
                mwindow.display();
    }

    system("PAUSE");
    return 0;
}
Was it helpful?

Solution

There is a small problem with the physics you are doing in the first code block. If you are trying to model gravitational pull, you will want to compute your acceleration using Newton's Law of Gravitation. What you have currently, is Hooke's Law; a spring force, with linear drag. To immediately answer your question about how to move the center of attraction away from the point (0,0), you can simply change what you have to include an offset. Namely,

return1.Xaccel = -k * (state.pos.getX() - xOffset) - b* state.vel.getX();
return1.Yaccel = -k * (state.pos.getY() - yOffset) - b* state.vel.getY();

where xOffset and yOffset define the (x,y) position of your desired center of attraction. This would allow you to move your force source, but this still has not addressed the problem that your force is elastic, not gravitational (inverse-square law). To do this, you will want something that looks like the following

float dx = state.pos.getX() - xOffset; // again xOffset is the source location
float dy = state.pos.getY() - yOffset;
float distSqrd = dx*dx + dy*dy;
float dist = sqrt( distSqrd );
return1.Xaccel = -G * mass * dx / (distSqrd * dist);
return1.Yaccel = -G * mass * dy / (distSqrd * dist);

Notice that, in order to take the direction into account, I have multiplied the F = G*m1*m2/dist^2 by dx/dist and dy/dist. This is equivalent to cos(angle) and sin(angle) where angle is a quantity best left uncomputed (that would specify the direction of the force). mass would be the mass of the object that is attracting your particles(?), and the particle mass is left off since we are only computing acceleration. If you want to add the linear drag back into the acceleration, you can easily do that too, which will make orbits far more stable.

Do note that this code can be considerably cleaned up by using vectors. Let me know if any clarification is needed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top