Физика

Физический движок RobustToolbox основан на Box2D. Рекомендуется ознакомиться с документацией, если вы собираетесь работать с движком.

Основные изменения:

  • Семантика C#: версия RobustToolbox изначально была основана на порте Box2D Farseer.
  • Многопоточность: решатель контактных ограничений и генерация манифолдов выполняются параллельно внутри.
  • Broadphase: в значительной степени собственная разработка, подходящая под нужды SS14, хотя всё ещё использует структуру b2DynamicTree.
  • PhysicsComponent: была доработана, чтобы лучше соответствовать остальной части RobustToolbox, например шине событий и сетевому взаимодействию.

Сущность с физикой состоит из PhysicsComponent и FixturesComponent. JointsComponent также может присутствовать, но только когда у сущности есть физические соединения (joints). FixturesComponent хранит фикстуры, которые по сути являются под-телами внутри сущности, JointsComponent хранит соединения, а PhysicsComponent хранит всё остальное.

Как работает физический конвейер

  1. Запускаются все физические контроллеры. Это применяет любые внешние силы к физической симуляции, такие как ввод игрока для движения, трение тайлов сверху вниз и т. д.
  2. На этом этапе каждый физический мир (map) проходит шаг. Первая часть — найти все broadphase-контакты для всех сущностей, которые переместились или иным образом актуальны (через TouchProxies). Мы проверяем некоторые базовые детали, чтобы определить, могут ли 2 тела сталкиваться, например их слои / маски коллизий, через PreventCollideEvent, отключение соединениями и т. д.
  3. Теперь мы проверяем все наши контакты и определяем, какие из них больше не пересекаются на broadphase, и отсеиваем их.
  4. Теперь запускается narrowphase. Для всех всё ещё актуальных контактов мы определяем, пересекаются ли они на самом деле, что дорого. Это выполняется через ManifoldManager. Если пересечение начинается или прекращается, выдаётся StartCollideEvent / EndCollideEvent.
  5. Для всех бодрствующих тел на конкретном мире мы создаём так называемые острова. Проще всего представить это так: мы берём бодрствующее тело и затем ищем путь по всем его контактам и соединениям настолько, насколько можем. Затем мы повторяем этот процесс для следующего бодрствующего тела, пока не получим все нужные острова.
  6. Теперь все тела каждого острова решаются.
  7. После завершения решения мы применяем данные обратно в TransformComponent каждого тела и выдаём MoveEvents все сразу.

Команды

physics <overlay> предоставляет множество полезных оверлеев для отладки физики.

showchunkbb показывает все фикстуры сеток.

Непрерывное обнаружение столкновений (CCD)

Физический движок сейчас не поддерживает CCD, но, возможно, когда-нибудь в будущем, когда будет решено, что поддерживать.

Полезные CVars

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

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

sleepallowed Разрешено ли физическим телам спать. Не рекомендуется отключать.

PhysicsComponent

Он хранит все физические данные для конкретной сущности. Один из способов представить, как работают тела Box2D, — это то, что они состоят из более мелких тел, фикстур (например, одна фикстура для хитбокса руки, одна для торса и т. д.), а PhysicsComponent — это сущность в целом.

Mass: Общая масса тела. Она включает массу всех его фикстур.

InvMass: Обратная масса. Используется внутри решателя, так как это быстрее, чем использовать Mass.

Inertia: Какая сила требуется, чтобы повернуть тело.

InvI: Обратная инерция.

LocalCenter: Это центр масс тела. Он вычисляется на основе положения всех фикстур относительно тела при отсутствии поворота. physics com показывает это для сеток и для тел.

FixedRotation: Установка этого в true предотвращает изменение угловой скорости тела.

LinearDamping: Это процент (где 0.2 соответствует 20%), на который LinearVelocity тела уменьшается каждый тик.

AngularDamping: Это процент (где 0.2 соответствует 20%), на который AngularVelocity тела уменьшается каждый тик.

Restitution: Насколько тело «отскакивает» при столкновении. 1.0 соответствует полному отскоку, а 0.0 означает отсутствие отскока. Это смешивается между обоими телами в контакте.

Friction: Насколько велико трение, применяемое к контакту; оно также смешивается между двумя телами. Учтите, что это не соответствует трению сверху вниз, которое искусственно и не включает контакты.

FixturesComponent

Фикстуры описывают форму и материальные свойства сущностей для целей обнаружения столкновений и другого поведения. Они происходят от фикстур Box2D.

Фикстуры, которые не являются hard, не вызывают фактического столкновения, но всё равно вызывают событие столкновения. Это полезно для реализации таких вещей, как скользкость.

Каждая фикстура является членом любого числа слоёв коллизий (поле layer). Каждая фикстура также имеет любое число масок коллизий (поле mask). Сущность A сталкивается с сущностью B, если mask-и A пересекаются с layer-ами B. Список слоёв определён в Content.Shared/Physics/CollisionGroup.cs.

CollideOnAnchorComponent

Это компонент, связанный с производительностью. Он переключает (вкл. или выкл. через поле данных) коллизию тела при изменении его состояния закрепления.

CollisionWakeComponent

Это компонент, связанный с производительностью. Он отключает коллизию тела, когда оно спит и находится на сетке без прикреплённых соединений. Это в первую очередь нацелено на SS14.

VirtualControllers

Для применения непрерывных внешних сил к симуляции, то есть движения игрока, следует использовать VirtualControllers. Они запускаются в начале и в конце физического шага и позволяют вносить изменения в физические тела.

Если вам нужно применить разовые вещи, например одиночный импульс, вы можете просто вызвать методы вроде ApplyLinearImpulse напрямую.

Контакты

Они создаются всякий раз, когда 2 тела (конкретно 2 фикстуры) пересекаются на broadphase. Свойство Enabled устанавливается в true или false по мере пересечения их narrowphase. Если их broadphase больше не пересекаются, контакт возвращается в пул.

Соединения

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

События

Обратите внимание, что приведённые ниже события не вызываются рекурсивно по причинам производительности. Например, если ваша сущность стоит на месте относительно своего родителя, но родитель движется, MoveEvent не будет вызван.

MoveEvent: Вызывается всякий раз при изменении EntityCoordinates / LocalPosition сущности. Это также относится к изменениям родителя.

RotateEvent: Вызывается всякий раз при изменении LocalRotation сущности.

EntParentChangedMessage: Вызывается при изменении родителя transform сущности.

CollisionChangeEvent: Вызывается всякий раз при включении или отключении CanCollide для тела. Также вызывается при его спавне.

PreventCollideEvent: Вызывается всякий раз, когда 2 тела пытаются пересечься через broadphase. Это следует использовать только для блокировки столкновения 1 конкретной сущности, а не для блокировки столкновения 2 групп сущностей. Если вы хотите заблокировать 2 целые группы, используйте маски / слои коллизий.

Отладка

Ниже приведён список распространённых проблем и способы их решения:

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

В. Мой моб прижимается к чему-то твёрдому, а затем телепортируется сквозь. О. Это означает, что клиент считает тело жёстко-коллизионным, а сервер нет, и у вас mispredict.

В. Моего моба отбрасывает (rubberbanding) от чего-то твёрдого. О. Это означает, что сервер считает тело жёстко-коллизионным, а клиент нет, и у вас mispredict.

В. Я могу сдвинуться лишь немного, а затем меня возвращает на место О. Это тоже mispredict, когда клиент думает, что может двигаться, а сервер нет.

В. Мой ввод задерживается О. Это тоже mispredict, когда сервер думает, что клиент может двигаться, а клиент нет.

Глоссарий

Ограничения: Физическая симуляция применяет силы и тому подобное к телам без учёта того, должно ли тело проходить сквозь стену. Ограничения — это то, что не позволяет этому происходить. Box2D не использует этот термин, но контакты и соединения — всё это ограничения. Некоторые другие физические движки объединяют их под одним зонтиком и используют этот термин.

Физический остров: Мы решаем физику через острова, а не последовательно все тела, по причинам засыпания стопок. Если бы части стопки могли спать, пока остальные бодрствуют, то успокоение заняло бы много времени, если вообще произошло бы. Когда все тела должны заснуть одновременно, это делает систему гораздо стабильнее.

Засыпание: Физические тела перестают обрабатываться, то есть засыпают, через некоторое время по причинам производительности. Это поведение можно настроить (допуск по скорости и время до засыпания) или переключить через cvar.

Subpages