我在一个游戏引擎中有一个3d对象A和B.物体A是行星,具有无限质量,不移动。 我有一个半径常数,它定义了一个固定的轨道球体(我希望objectb位于它的边缘的球体)。 并且物体B受到来自其他物体的聚集的随机力的作用,因此已经存在作用于它的力。 如何使物体B与物体B保持相同的距离(保持球体的半径)? 我知道雅各比方程有一些复杂的计算,但我试图避免这种情况。 目前我在做:
gravity_vector = planetcentercoordinate - objectBposition
distance_number = size(gravity_vector) - >只是两个物体的距离
IF distance_number> radius THEN gravity_vector = - gravity_vector - >如果物体通过球体轨道进入行星核心,则反转力
force = gravity_vector
如果我这样做的话,物体会按照意图进入轨道球体的方向,但它只是反弹太多...... 还有另一种简单的方法可以做到这一点,或者如果距离较小可能会对力进行校正?
答案 0 :(得分:1)
Javascript中的一个例子(为简洁起见省略了一些部分):我有一个CelestialBody
函数(一个"类"),它返回一个表示空间中的物体的对象(行星,星球)等等......)
function CelestialBody(mass, velocity, mesh){
this.forceBetween = function(body){
var squareDistance = this.squareDistanceFrom(body);
var force = Constants.G * (this.mass * body.mass) / squareDistance;
return force;
};
this.addForceContribution = function(body){
var forceMagnitude = this.forceBetween(body);
var distance = this.distanceFrom(body);
var xDiff = body.getPosition().x - this.getPosition().x;
var yDiff = body.getPosition().y - this.getPosition().y;
var zDiff = body.getPosition().z - this.getPosition().z;
var xRatio = xDiff / distance;
var yRatio = yDiff / distance;
var zRatio = zDiff / distance;
var fx = forceMagnitude * xRatio;
var fy = forceMagnitude * yRatio;
var fz = forceMagnitude * zRatio;
var forceVector = new THREE.Vector3(fx, fy, fz);
this.acceleration.add(forceVector.divideScalar(this.mass));
};
this.updatePosition = function(delta){
if(!delta){
delta = Constants.DEFAULT_TIME_DELTA; // just to make debugging possible
}
this.velocity = this.velocity.add(this.acceleration.multiplyScalar(delta));
var tempVelocity = this.velocity.clone();
var nextPosition = this.getPosition().clone();
nextPosition.add( tempVelocity.multiplyScalar(delta) );
this.mesh.position.x = nextPosition.x;
this.mesh.position.y = nextPosition.y;
this.mesh.position.z = nextPosition.z;
this.acceleration = new THREE.Vector3(0, 0, 0);
};
}
在主游戏循环中,每一步,每个身体,我都会考虑任何其他身体的重力贡献并相应地更新位置:
for (var i = 0; i < celestialBodies.length; i++) {
for (var j = 0; j < celestialBodies.length; j++) {
if (celestialBodies[i] === celestialBodies[j]) {
continue;
}
celestialBodies[i].addForceContribution(celestialBodies[j]);
}
}
for (var i = 0; i < celestialBodies.length; i++) {
celestialBodies[i].updatePosition();
// check if the body is gone too far: if so, marks it for removal
if (celestialBodies[i].getPosition().distanceTo(new THREE.Vector3(0, 0, 0)) > Constants.REMOVAL_DISTANCE_THRESHOLD) {
celestialBodies[i].markedForRemoval = true;
}
}