Подтвердить что ты не робот

Физический движок Javascript и симулированная бесконечная кривая

Я пытаюсь сделать Tiny Wings, как в javascript.

Я впервые увидел технику с использованием Box2D, я использую закрыть-веб-версию (из-за исправления утечек памяти).
Короче говоря, я взорву кривую на многоугольники, чтобы она выглядела так:

enter image description here

Я также пробовал с Chipmunk-js, и я использую форму сегмента, чтобы имитировать мое основание:

enter image description here

В обоих случаях я испытываю некоторые "сбои" или "удары" в общих точках между многоугольниками или сегментами, когда кружок катится.

Я спросил об этом для Chipmunk, и автор сказал, что он реализовал свойство радиуса для сегмента, чтобы уменьшить это поведение. Я пробовал, и это действительно трюк, но это не идеально. У меня все еще есть некоторые удары (я должен был установить 30px радиуса, чтобы получить положительный эффект).

"Удары" добавляются в общих точках между двумя полигонами:

bump bug

Используя illandril, предложили мне технику обрезки (он тестировал только с полигоном- полигональный контакт), чтобы избежать крушения на краю:

slope edging technique

Также попытался добавить параметр пули, предложенный Люком, и ничего не изменилось.

Здесь демо проблемы.
Вы можете попробовать изменить значение, чтобы проверить:

  • опция пули
  • размер края
  • количество итераций
  • физика

(тестируется только на последнем браузере Chrome)
Будьте терпеливы (или измените горизонтальную гравитацию), и вы увидите, что я имею в виду.
Здесь репо для заинтересованных.

4b9b3361

Ответ 1

Лучшее решение - это формы контуров с вершинными вершинами, но если это не доступно в используемой версии/порту, следующая лучшая вещь похожа на диаграмму в вашем вопросе под названием "обрезка", но удлиняет полигоны далее под землей с очень мелким уклоном, как в этой теме: http://www.box2d.org/forum/viewtopic.php?f=8&t=7917

Ответ 2

Сначала я подумал, что проблема может возникнуть в результате изменения наклона между двумя соседними сегментами, но поскольку на плоской поверхности полигонов у вас все еще есть шишки, я думаю, что проблема скорее попадает в угол многоугольника.

Я не знаю, можете ли вы установить два набора полигонов, перекрывая друг друга? Просто используйте те же вычисления интерполяции и создайте второй набор полигонов, как и в приведенной ниже диаграмме: у вас есть красный набор построенных многоугольников и добавьте зеленый набор, установив левые вершины зеленого многоугольника в середине красного многоугольника, и его правые вершины в середине следующего красного многоугольника.

! [Схема] [1]

Это должно работать на вогнутых кривых и... ну, вы все равно должны летать над выпуклыми.

Если это не работает, попробуйте установить большое количество полигонов для построения склона. Используйте десятую часть радиуса круга для ширины многоугольника, возможно, даже меньше. Это должно уменьшить разрывы наклона.

- Изменить

В Box2D.js строка 5082 (в это репо по крайней мере) у вас есть функция PreSolve (контакт, многообразие), которую вы можете переопределить проверьте, правильны ли многообразия (направления, в которых импульс снежного кома при столкновении с полигонами).

Для этого вам нужно будет восстановить вектор многообразия и сравнить его с нормалью кривой. Он должен выглядеть так (возможно, не совсем):

Box2D.Dynamics.b2ContactListener.prototype.PreSolve = function (contact, oldManifold) {
    // contact instanceof Box2D.Dynamics.Contacts.b2Contact == true
    var localManifold, worldManifold, xA, xB, man_vect, curve_vect, normal_vect, angle;
    localManifold = contact.GetManifold();

    if(localManifold.m_pointCount == 0)
        return; // or raise an exception

    worldManifold = new Box2D.Collision.b2WorldManifold();
    contact.GetWorldManifold( worldManifold );

    // deduce the impulse direction from the manifold points
    man_vect = worldManifold.m_normal.Copy();

    // we need two points close to & surrounding the collision to compute the normal vector
    // not sure this is the right order of magnitude
    xA = worldManifold.m_points[0].x - 0.1;
    xB = worldManifold.m_points[0].x + 0.1;

    man_vect.Normalize();

    // now we have the abscissas let get the ordinate of these points on the curve
    // the subtraction of these two points will give us a vector parallel to the curve

    var SmoothConfig;

    SmoothConfig = {
        params: {
            method: 'cubic',
            clip: 'mirror',
            cubicTension: 0,
            deepValidation: false
        },
        options: {
            averageLineLength: .5
        }
    }
    // get the points, smooth and smooth config stuff here
    smooth = Smooth(global_points,SmoothConfig);

    curve_vect = new Box2D.Common.Math.b2Vec2(xB, smooth(xB)[1]);
    curve_vect.Subtract(new Box2D.Common.Math.b2Vec2(xA, smooth(xA)[1]));

    // now turn it to have a normal vector, turned upwards
    normal_vect = new Box2D.Common.Math.b2Vec2(-curve_vect.y, curve_vect.x);
    if(normal_vect.y > 0)
        normal_vect.NegativeSelf();
    normal_vect.Normalize();
    worldManifold.m_normal = normal_vect.Copy();

    // and finally compute the angle between the two vectors
    angle = Box2D.Common.Math.b2Math.Dot(man_vect, normal_vect);

    $('#angle').text("" + Math.round(Math.acos(angle)*36000/Math.PI)/100 + "°");
    // here try to  raise an exception if the angle is too big (maybe after a few ms)
    // with different thresholds on the angle value to see if the bumps correspond
    // to a manifold that not normal enough to your curve 
};

Ответ 3

Я бы сказал, что проблема решена в Box2D 2.2.0, см. ее руководство, раздел 4.5 "Edge Shapes"

Вещь это функция версии 2.2.0, а также вещь chainhape, а box2dweb фактически портируется с 2.2. 1a - не знаю о box2dweb-закрытии.

Все, что я пробовал, изменяя Box2D.Collision.b2Collision.CollidePolygonAndCircle, привело к неустойчивому поведению. По крайней мере, часть времени (например, шаровая накатка в случайных направлениях, но только при медленном ее движении).