Заставьте один трехмерный объект вращаться вокруг другого, просто используя силы

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

гравитационный_вектор = координата центра планеты - положение объекта

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

ЕСЛИ число_расстояния>радиус, ТО гравитационный_вектор = - гравитационный_вектор --> инвертировать силы, если объект проходит орбиту сферы в ядро ​​планеты

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

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


person wagfeliz    schedule 30.06.2015    source источник


Ответы (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;
        }
    }

Полный код находится здесь.

person Evil Toad    schedule 30.06.2015