Ball Mechanics - это лучший подход? - PullRequest
       18

Ball Mechanics - это лучший подход?

1 голос
/ 24 сентября 2019

Добрый день,

Я бы хотел запрограммировать постоянно движущийся шар (object3), передаваемый между двумя неподвижными объектами (object1, object2), с возможностью установки максимальноговысота Y траектории прохода динамически.

Object3 bounces between Object1 and Object2 automatically, despite a variable height factor.

Как вы думаете, что является лучшим способом программирования физики шаров для этой концепции?

Я рассмотрел использование addForce для сферы по умолчанию с твердым телом.Похоже, должно быть уравнение, которое выражает траекторию прохода object3 от object1 'sx до object2' x ... при известном, заданном speed, с известным, заданным mass, и известная гравитационная среда.

Однако, в настоящее время у меня есть Vector3.Lerp, интерполирующий шар между двумя объектами на каждом FixedUpdate() с t, выраженным как:

`(Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f;`

Это работает и все, но сПри таком подходе, кажется, нет четкого способа добавить height к траектории движения мяча.Я рассмотрел добавление height к значению Y в object2 до тех пор, пока мяч не достигнет половины пути, а затем вернул его в исходное положение Y ... но он просто чувствует себя неправильно!Мысли?

Спасибо!

1 Ответ

2 голосов
/ 24 сентября 2019

Хорошо, поэтому, если я правильно вас понимаю, в данный момент вы делаете

privte void FixedUpdate()
{
    var factor = (Mathf.Sin(speed * Time.time) + 1.0f) / 2.0f;
    object1.MovePosition(Vector3.Lerp(object2.position, object3.position, factor));
}

, который перемещает пинг-понг шара между позициями object1 и object2, но только в плоскости.

Предполагая, что на данный момент объекты будут перемещаться только в плоскости XZ и никогда не будут иметь различную позицию Y , чтобы получить кривую с высотой, которую можно рассматривать отдельно: - интерполировать между обеими позициями, как и раньше - отдельно вычислять позицию Yс синусом или любой другой функцией математической кривой - для реалистичной физики, вероятно, скорее парабола на самом деле

Может выглядеть так

public class Example : MonoBehaviour
{
    public Rigidbody object1;
    public Transform object2;
    public Transform object3;

    // adjust in the Inspector
    public float speed = 1;
    public float Amplitude = 0;

    // Just for debug
    [Range(0, 1)] [SerializeField] private float linearFactor;
    [SerializeField] private float yPosition;

    private void FixedUpdate()
    {
        // This always returns a value between 0 and 1 
        // and linearly pingpongs forth and back
        linearFactor = Mathf.PingPong(Time.time * speed, 1);
        // * Mathf.PI => gives now a value 0 - PI
        // so sinus returns correctly 0 - 1 (no need for +1 and /2 anymore)
        // then simply multiply by the desired amplitude
        var sinus = Mathf.Sin(linearFactor * Mathf.PI);
        yPosition = sinus * Amplitude;

        // As before interpolate between the positions
        // later we will ignore/replace the Y component
        var position = Vector3.Lerp(object2.position, object3.position, linearFactor);

        object1.MovePosition(new Vector3(position.x, yPosition, position.z));
    }
}

enter image description here


При желании вы также можете попробовать добавить некоторый сброс в направлении Y, чтобы сделать вертикальное движение более реалистичным (замедление при достижении пика).Я попробовал немного, используя инвертированный SmoothStep как

// just for debug
[Range(0, 1)] [SerializeField] private float dampedSinusFactor;
[Range(0, 1)] [SerializeField] private float linearFactor;
[SerializeField] private float yPosition;

private void FixedUpdate()
{
    // Use two different factros:
    // - a linear one for movement in XZ
    // - a smoothed one for movement in Y (in order to slow down when reaching the peak ;) )
    linearFactor = Mathf.PingPong(Time.time * speed, 1);
    dampedSinusFactor = InvertSmoothStep(linearFactor);

    // * Mathf.PI => gives now a value 0 - PI
    // so sinus returns correctly 0 - 1 ()
    // then simply multiply by the desired amplitude
    var sinus = Mathf.Sin(dampedSinusFactor * Mathf.PI);
    yPosition = sinus * Amplitude;

    // later we will ignore/replace the Y component
    var position = Vector3.Lerp(object2.position, object3.position, linearFactor);

    object1.position = new Vector3(position.x, yPosition, position.z);
}

// source: https://stackoverflow.com/a/34576808/7111561
private float InvertSmoothStep(float x)
{
    return x + (x - (x * x * (3.0f - 2.0f * x)));
}

Однако для медленных движений это выглядит немного странно.Но вы можете придумать любую другую математическую кривую, которая приводит к ожидаемому поведению для x=[0,1];)

enter image description here

...