Есть ли способ написать метод для вызова ‘AddForce’ либо для жесткого тела, либо для параметра Rigidbody2D?

#c# #unity3d #3d #2d #rigid-bodies

#c# #unity3d #3D #2d #жестких тел

Вопрос:

Я пытаюсь создать класс, который работает как с 2D, так и с 3D жесткими телами в Unity. Все работает нормально, пока я не перейду к методу ‘AddForce’, где я получаю InvalidCastException, поскольку я либо преобразую 2D в 3D, либо наоборот. Для тех из вас, кто не знает, как Rigidbody, так и Rigidbody2D имеют метод ‘AddForce’.

Я изучил динамический тип (скорее не использовать, поскольку он не будет работать на ios), дженерики и интерфейсы, но все еще не могу прийти к решению. Был бы признателен за любую помощь. Спасибо.

 public class Scroller : MonoBehaviour {

    ScrollController _scrollController;
    Object _rb;

    public enum SCROLL_MODE {
        TRANSLATION,
        PHYSICS_2D = 2,
        PHYSICS_3D = 3
    }

    public SCROLL_MODE scrollMode = SCROLL_MODE.TRANSLATION;

    // Start is called before the first frame update
    void Start()    {
        _scrollController = ScrollController.Instance;

        switch (scrollMode) {
            case SCROLL_MODE.TRANSLATION:
                break;
            case SCROLL_MODE.PHYSICS_2D:
                _rb = GetComponent<Rigidbody2D>();
                break;
            case SCROLL_MODE.PHYSICS_3D:
                _rb = GetComponent<Rigidbody>();
                break;
        }

        if (!_scrollController)
            logFatalError("Error: There is no ScrollController within the scene.");
    }

    void Update() {
        if (scrollMode == SCROLL_MODE.TRANSLATION)
            transform.Translate(_scrollController.scrollDirection * _scrollController.scrollSpeed * Time.deltaTime);
    }

    void FixedUpdate() {
        if (scrollMode == SCROLL_MODE.PHYSICS_2D || scrollMode == SCROLL_MODE.PHYSICS_3D) {
            if (!_rb) {
                logFatalError("Error: "   gameObject.name   " has no Rigidbody"   scrollMode.ToString("d")   "D");
                return;
            }

            applyScrollForce(_rb);
        }
    }

    void applyScrollForce(Object rb) {
        ((Rigidbody)rb).AddForce(_scrollController.scrollDirection * _scrollController.scrollSpeed * Time.fixedDeltaTime);
    }

    void logFatalError(string msg) {
        Debug.Log(msg);

        enabled = false;
    }
}
  

Комментарии:

1. Вернитесь к законам Ньютона: F = ma. В двух 2D масса отсутствует. Итак, как вы можете добавить силу? В 2D вы просто предполагаете, что масса является постоянной. Итак, когда вы переходите от 2D к 3D, вы просто делаете Z = 0. При переходе от 3D к 2D вам нужно найти центр тяжести, чтобы вы могли придать своему объекту однородную массу и удалить элемент Z из ускорения.

Ответ №1:

Обобщения не помогут, потому что на удивление нет общего родительского класса с AddForce. Rigidbody и Rigidbody2D оба наследуются от Component .

Я вижу, что у вас есть два варианта:

Во-первых, и это самое простое, используйте только Rigidbody и используйте ограничения, чтобы сохранить его в 2D, когда это необходимо.

В случае, когда это не вариант, подойдет простой оператор ‘if’:

 void applyScrollForce(Object rb) {
    var force = _scrollController.scrollDirection * _scrollController.scrollSpeed * Time.fixedDeltaTime;
    if(rb.GetType() == typeof(Rigidbody))
        ((Rigidbody)rb).AddForce(force);
    else if(rb.GetType() == typeof(Rigidbody2D))
        ((Rigidbody2D)rb).AddForce(force);
}

  

Естественно, вы, вероятно, захотите кэшировать тип вместо проверки и приведения каждого кадра.

Ответ №2:

Хотя и Rigibody, и Rigidbody2D имеют методы AddForce, мало того, что их сигнатуры отличаются, но между Rigidbody и Rigidbody2D нет никакой связи.

Вы можете проверить документацию и увидеть, что они оба наследуются от класса Component, но на этом их сходство заканчивается.

Вы могли switch бы выполнить команду для базового компонента, чтобы выяснить, с каким из двух вы имеете дело. switch Оператор для двух элементов немного излишен, но он аккуратный и не слишком тяжелый для производительности. Также происходит намного меньше кастинга.

 Component _c = null;

void Start ( )
{
    _scrollController = ScrollController.Instance;

    switch ( scrollMode )
    {
        case SCROLL_MODE.PHYSICS_2D:
            _c = GetComponent<Rigidbody2D> ( );
            break;
        case SCROLL_MODE.PHYSICS_3D:
            _c = GetComponent<Rigidbody> ( );
            break;
    }

    if ( !_scrollController )
        logFatalError ( "Error: There is no ScrollController within the scene." );
}


void applyScrollForce ( )
{
    if ( _c == null )
    {
        Debug.LogWarning ( "The Component is null." );
        return;
    }

    var force = _scrollController.scrollDirection * _scrollController.scrollSpeed * Time.fixedDeltaTime;
    switch ( _c )
    {
        case Rigidbody rb:
            rb.AddForce ( force );
            break;

        case Rigidbody2D rb2D:
            rb2D.AddForce ( force );
            break;

        default:
            Debug.LogError ( $"Component {_c.name} is neither a Rigidbody or Rigidbody2D."  );
            return;
    }
}