LibGDX: как умножить вектор на скаляр без изменения исходного вектора? (простая система гравитации в Java-игре)

В настоящее время я реализую простую систему гравитации в своей игре, используя LibGDX. Однако я обнаружил, что способ умножения векторов на векторы и векторов на скаляры немного отличается.

В Unity я бы реализовал гравитацию так:

    public Vector3 velocity;
    public Vector3 acceleration;

    private void FixedUpdate()
    {
        transform.position += velocity*Time.fixedDeltaTime;

        Vector3 force = Physics.gravity*GetComponent<Rigidbody>().mass;
        acceleration = force/GetComponent<Rigidbody>().mass;

        velocity = velocity + acceleration*Time.fixedDeltaTime;
    }
}

Умножение векторов очень прямолинейно.

В LibGDX я пытаюсь сделать следующее:

    import com.badlogic.gdx.math.Vector2;

    final protected Vector2 _gravity = new Vector2(0f, -9.82f);
    final protected float _mass = 1f;
    protected Vector2 _velocity;
    protected Vector2 _acceleration;

    public void Update(float deltaTime)
    {
        // Transform is a class containing a Vector2 called Position
        Transform.Position.add(_velocity.scl(deltaTime));

        Vector2 force = _gravity.scl(_mass);
        _acceleration = force.scl(1f/_mass);    
        _velocity = _velocity.add(_acceleration.scl(deltaTime));

        System.out.println(_velocity);
        // _velocity gets smaller and smaller and finally hits 0.
    }

Это не работает, так как метод scl() класса Vector2 напрямую изменяет сам вектор, что можно увидеть в классе Vector2 библиотеки LibGDX:

public Vector2 scl (float scalar) {
        x *= scalar;
        y *= scalar;
        return this;
    }

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

Как я могу это сделать? Или я совсем не прав? Есть ли в LibGDX более простой способ умножать векторы на скаляры с помощью оператора «*»?


person Wikzo    schedule 17.11.2015    source источник
comment
Причина, по которой вы не можете сделать это способом Unity, заключается в том, что в Java нет структур. :(   -  person Tenfour04    schedule 17.11.2015


Ответы (3)


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

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

final Vector2 force = new Vector2();
public void update(float delta) {
    ...
    force.set(_gravity).scl(mass);
    ...
}

Обратите внимание, что для таких операций, как position += velocity * time, вы можете использовать метод mulAdd.

position.mulAdd(velocity, deltaTime);
person Xoppa    schedule 17.11.2015

Vector2 force = _gravity.cpy().scl(_mass);

Метод cpy() возвращает копию вектора, поэтому вы в конечном итоге умножаете копию на _mass, а не на исходный вектор.

Небольшое преимущество этого решения по сравнению с использованием new Vector2() для создания копии заключается в том, что оно работает для любого векторного измерения без изменений.

person biziclop    schedule 17.11.2015

Вы можете попробовать продублировать вектор перед его масштабированием, например:

new Vector2(_gravity).scl(_mass);
person Anuken    schedule 17.11.2015