#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;
}
}