Сделайте один 3d-объект, чтобы "вращаться" по другому, просто используя силы

У меня есть один 3D-объект A и B в одном игровом движке. Объект А является планетой, имеет бесконечную массу и не двигается. У меня есть константа радиуса, которая определяет фиксированную сферу орбиты (сферу, где я хочу, чтобы объект b находился на ее краю). А объект B подвержен случайным силам от столкновений других объектов, поэтому на него уже действуют силы. Как сделать так, чтобы объект B имел одинаковое расстояние от объекта B (оставалось в радиусе в сфере), просто используя силы? Я знаю, что есть некоторые сложные вычисления по уравнениям Якоби, но я пытаюсь избежать этого. В настоящее время я занимаюсь:

gravity_vector = planetcentercoordinate - objectBposition

distance_number = size (gravity_vector) -> просто расстояние двух объектов

ЕСЛИ distance_number>radius THEN gravity_vector = - gravity_vector -> инвертировать силы, если объект проходит сферу орбиты в ядре планеты

сила = гравитация_вектор

Если я просто сделаю это, объект пойдет в направлении сферы орбиты как намерение, но он просто слишком сильно подпрыгивает... Есть еще один простой способ сделать это или, возможно, коррекция силы, если расстояние меньше?

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;
        }
    }

Полный код здесь, а результат здесь.

Другие вопросы по тегам