在我的libgdx测试游戏中,我最初创建了两个圆形对象(恒星),下面我将详细介绍它们。然而,我的目标是在2d中模拟重力,较小的物体朝着较大物体的中心运行(就像地球绕太阳运行一样),但越来越靠近较大物体的中心。
因此,我创建了以下内容:
恒星1:更小,10px半径,10质量,动态(可以移动),初始位置-160x90,速度(0,0),加速器(0,0)
恒星2:更大,30像素半径,30质量,静止(不能移动),初始位置0x0,速度(0,0),加速器(0,0)
这里还有一个截图,只需要一张图片:
我将在下面给出我到目前为止所做工作的完整代码,在此之前我想提到我有两种方法,stellartest1和stellartest2。
首先,我试着给x和y加上一些额外的值,比如1000f,只是为了看到一些实际的东西,比如:
velocity.x += 1000f * acceleration.x * deltaTime;
velocity.y += 1000f * acceleration.x * deltaTime;
结果是-较小的物体向较大物体的中心移动,但一旦它到达较大物体的中心,较小的物体就会被逐出到相反的一边。更不用说1000f在这个坐标系的大小中不是正确的值,但我关心的是以下计算:
acceleration.x = gravityForce * (diffX / distance)
acceleration.y = gravityForce * (diffY / distance)
代码stellartest1:
public class StellarTest1 extends AbstractTest {
private Stellar stellar2, stellar1;
public StellarTest1(Game game) {
super(game);
}
@Override
public void create() {
game.getCartesianGrid().setEnabled(true);
// smaller stellar
float startX = -160;
float startY = 90;
float radius = 10;
float mass = 10;
stellar1 = new Stellar(
startX, startY,
radius, mass,
new Color(102, 188, 217, 100f)
);
// bigger stellar
startX = 0;
startY = 0;
radius = 30;
mass = 30;
stellar2 = new Stellar(
startX, startY,
radius, mass,
new Color(252, 236, 3, 100f)
);
stellar2.updatable = false; // bigger object will not update, in other words no motion
stellar2.setOther(stellar1);
stellar1.setOther(stellar2);
}
@Override
public void update(float deltaTime) {
if (!updatable) {
return;
}
stellar2.update(deltaTime);
stellar1.update(deltaTime);
}
@Override
public void draw() {
if (!drawable) {
return;
}
stellar2.draw();
stellar1.draw();
}
private class Stellar {
Circle circle;
Vector2 velocity;
Vector2 direction;
Vector2 acceleration;
float mass, radius;
boolean updatable;
Stellar other;
public Stellar(
float startX, float startY,
float radius, float mass,
Color color) {
this.radius = radius;
this.velocity = new Vector2(0, 0);
this.acceleration = new Vector2(0, 0);
this.mass = mass;
this.radius = radius;
circle = new Circle(game,
color,
startX, startY,
radius);
this.updatable = true;
}
public void update(float deltaTime) {
if (!updatable) {
return;
}
float diffX = other.circle.x - circle.x;
float diffY = other.circle.y - circle.y;
float G = 2f;
float mass = G * (other.mass - this.mass);
float distance = (float) Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2));
float gravityForce = (float) (mass / Math.pow(distance, 2));
acceleration.x = gravityForce * (diffX / distance);
acceleration.y = gravityForce * (diffY / distance);
velocity.x += 1000f * acceleration.x * deltaTime;
velocity.y += 1000f * acceleration.y * deltaTime;
circle.x += velocity.x * deltaTime;
circle.y += velocity.y * deltaTime;
}
public void draw() {
game.getShapeRenderer().begin(ShapeRenderer.ShapeType.Filled);
circle.draw();
game.getShapeRenderer().end();
}
public void setOther(Stellar other) {
this.other = other;
}
}
}
第二个stellartest2,在本例中,您将看到相同的代码,除了我在这里使用Angular (单位:度):
float angleInDegrees = MathUtils.atan2(diffY, diffX) * MathUtils.radiansToDegrees;
...
acceleration.x = gravityForce * MathUtils.cos(angleInDegrees * deltaTime);
acceleration.y = gravityForce * MathUtils.sin(angleInDegrees * deltaTime);
在这个测试中,我不需要增加一些额外的速度来移动更小的物体。我还实现了较小的物体将作出一个坚实的曲线,但不会得到拖拽在中心。相反,一段时间后它会被驱逐出去。然而,我仍然面临这样一个问题:较小的物体不断地向中心弯曲。然而,我好奇的是,在这里是否有必要使用cos和sin,也许stellartest1是正确的方法。
代码stellartest2:
public class Stellar2Test extends AbstractTest {
private Stellar stellar1, stellar2;
public Stellar2Test(Game game) {
super(game);
}
@Override
public void create() {
game.getCartesianGrid().setEnabled(true);
float startX = -160;
float startY = -90;
float radius = 10;
float mass = 30;
stellar2 = new Stellar(
startX, startY,
radius, mass,
new Color(102, 188, 217, 100f)
);
startX = 0;
startY = 0;
radius = 30;
mass = 30;
stellar1 = new Stellar(
startX, startY,
radius, mass,
new Color(252, 236, 3, 100f)
);
stellar1.updatable = false;
stellar1.setOther(stellar2);
stellar2.setOther(stellar1);
}
@Override
public void update(float deltaTime) {
if (!updatable) {
return;
}
stellar1.update(deltaTime);
stellar2.update(deltaTime);
}
@Override
public void draw() {
if (!drawable) {
return;
}
stellar1.draw();
stellar2.draw();
}
private class Stellar {
Circle circle;
Vector2 velocity;
Vector2 acceleration;
float mass, radius;
boolean updatable;
Stellar other;
public Stellar(
float startX, float startY,
float radius, float mass,
Color color) {
this.radius = radius;
this.velocity = new Vector2(0, 0);
this.acceleration = new Vector2(0, 0);
this.mass = mass;
this.radius = radius;
circle = new Circle(game,
color,
startX, startY,
radius);
this.updatable = true;
}
public void update(float deltaTime) {
if (!updatable) {
return;
}
float diffX = other.circle.x - circle.x;
float diffY = other.circle.y - circle.y;
float angleInDegrees = MathUtils.atan2(diffY, diffX) * MathUtils.radiansToDegrees;
float G = 2;
float mass = (G * (other.mass * this.mass));
float distance = (float) Math.sqrt(Math.pow(diffX, 2) + Math.pow(diffY, 2));
float gravityForce = mass / distance;
acceleration.x = gravityForce * MathUtils.cos(angleInDegrees * deltaTime);
acceleration.y = gravityForce * MathUtils.sin(angleInDegrees * deltaTime);
velocity.x += acceleration.x * deltaTime;
velocity.y += acceleration.y * deltaTime;
circle.x += velocity.x * deltaTime;
circle.y += velocity.y * deltaTime;
}
public void draw() {
game.getShapeRenderer().begin(ShapeRenderer.ShapeType.Filled);
circle.draw();
game.getShapeRenderer().end();
}
public void setOther(Stellar other) {
this.other = other;
}
}
}
1条答案
按热度按时间cx6n0qe31#
您在stellartest1中的更新方法在概念上对我来说很好(我假设
1000f
这个系数是调整引力常数(大物体的质量)的方法。然而,如果你想要轨道有一些额外的衰减,你需要在加速度中加入一些虚拟的速度相关阻力项。没有必要使用stellartest2,因为当cos和sin的计算速度较慢且成本较高时,您应该会得到一个可比较的结果,而stellartest1中相同的分量是以纯代数的方式(乘法和除法)计算的,这要快得多。但是要实现一些有趣的轨道,你不仅需要两个小物体初始位置的坐标,还需要两个小物体初始速度的坐标!如果不指定初始速度或者假设它为零,你就不会得到一个很好的曲线轨道。你需要选择初始速度。另外,轨道不应该离大物体的中心太远,因为牛顿引力场在大物体的中心有一个奇点,所以小物体离这个奇点越近,轨道看起来越糟糕(数值上的误差会不成比例地扩大),你会把较小的天体从较大天体的中心射出也就不足为奇了。
一般来说,有一种方法可以选择一个速度,使较小的物体在预定轨道参数的椭圆轨道上运动:半长轴的长度
a
,轨道偏心率e
,Angularomega
半长轴和水平x轴之间的夹角f
(称为真异常)在从大到小物体的位置矢量和半长轴之间。