Я использовал RK4 для физики в небольшой 2-мерной игре, которую я сделал, но когда дело доходит до гравитации, все объекты растягиваются до 0,0, как я могу это изменить? (Извините за отсутствие комментариев, еще не было времени, чтобы прокомментировать это)
#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));
}
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
главный
#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;
}
Есть небольшая проблема с физикой, которую вы делаете в первом блоке кода. Если вы пытаетесь смоделировать гравитационное притяжение, вам нужно рассчитать свое ускорение, используя закон тяготения Ньютона. В настоящее время у вас есть закон Гука; сила пружины, с линейным сопротивлением. Чтобы немедленно ответить на ваш вопрос о том, как отодвинуть центр притяжения от точки (0,0), вы можете просто изменить то, что вам нужно, чтобы включить смещение. А именно,
return1.Xaccel = -k * (state.pos.getX() - xOffset) - b* state.vel.getX();
return1.Yaccel = -k * (state.pos.getY() - yOffset) - b* state.vel.getY();
где xOffset
а также yOffset
определите (х, у) положение желаемого центра притяжения. Это позволило бы вам переместить источник силы, но это все еще не решило проблему, заключающуюся в том, что ваша сила упругая, а не гравитационная (закон обратных квадратов). Для этого вам понадобится что-то похожее на следующее
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);
Обратите внимание, что для того, чтобы принять во внимание направление, я умножил F = G*m1*m2/dist^2
от dx/dist
а также dy/dist
, Это эквивалентно cos(angle)
а также sin(angle)
где angle
это количество, которое лучше всего оставить не вычисленным (которое будет указывать направление силы). mass
будет масса объекта, который притягивает ваши частицы (?), а масса частицы не учитывается, так как мы только вычисляем ускорение. Если вы хотите добавить линейное сопротивление обратно в ускорение, вы можете легко это сделать, что сделает орбиты намного более стабильными.
Обратите внимание, что этот код может быть значительно очищен с помощью векторов. Дайте мне знать, если требуется какое-либо разъяснение.
Других решений пока нет …