RigidBody: силы, импульсы и безопасный сброс
Управление телом через физику: масса, контакты, _IntegrateForces, сон, Freeze и ориентация.
Выберите способ управления
RigidBody2D/3D вычисляет движение под действием сил и контактов. Для управляемого персонажа с правилами скорости/склонов часто удобнее CharacterBody. Не перемещайте динамический RigidBody присваиванием Position каждый _Process: отрисовка, интегратор и контакты начнут конкурировать за состояние.
| Задача | Метод |
|---|---|
| Разовый толчок | ApplyCentralImpulse один раз на событие |
| Непрерывная тяга | ApplyCentralForce каждый нужный физический шаг |
| Постоянный сохраняемый вклад | ConstantForce / AddConstantCentralForce; явно сбрасывайте его |
| Толчок/сила со смещением | ApplyImpulse/ApplyForce; смещение влияет на момент |
| Собственная интеграция или телепорт | _IntegrateForces и PhysicsDirectBodyState |
Сила уже интегрируется по времени; не умножайте её на delta перед ApplyCentralForce. Импульс тоже не умножается на delta и не прикладывается каждый кадр ради непрерывной тяги. Для свободного тела без сопротивления изменение скорости от центрального импульса равно impulse / mass: импульс 10 при массе 2 даёт 5 единиц/с. Контакты, ограничения и сопротивление могут изменить наблюдаемый результат.
Запустить тело и сброс
Чтобы увидеть пол, контакты и управление, используйте законченные уровни 2D и 3D. Для своего тела добавьте подходящий класс ниже, прикрепите к RigidBody2D или RigidBody3D и добавьте прямого ребёнка CollisionShape с ненулевой формой. RequestReset принимает мировую позицию. Сам запрос не меняет Transform немедленно: callback применяет его на физическом шаге и очищает скорости. Если тело заморожено, сначала снимите Freeze; запрос не является обходом режима симуляции.
LabBody2D.cs
using System;
using Reckfell;
public partial class LabBody2D : RigidBody2D
{
private Vector2? _resetPosition;
public int ResetCount { get; private set; }
public void RequestReset(Vector2 worldPosition)
{
if (!worldPosition.IsFinite()) throw new ArgumentOutOfRangeException(nameof(worldPosition));
_resetPosition = worldPosition;
Sleeping = false;
}
public override void _IntegrateForces(PhysicsDirectBodyState2D state)
{
if (_resetPosition is not Vector2 position) return;
state.Transform = new Transform2D(0, position);
state.LinearVelocity = Vector2.Zero;
state.AngularVelocity = 0;
_resetPosition = null;
ResetCount++;
}
}LabBody3D.cs
using System;
using Reckfell;
public partial class LabBody3D : RigidBody3D
{
private Vector3? _resetPosition;
public int ResetCount { get; private set; }
public void RequestReset(Vector3 worldPosition)
{
if (!worldPosition.IsFinite()) throw new ArgumentOutOfRangeException(nameof(worldPosition));
_resetPosition = worldPosition;
Sleeping = false;
}
public override void _IntegrateForces(PhysicsDirectBodyState3D state)
{
if (_resetPosition is not Vector3 position) return;
state.Transform = new Transform3D(Basis.Identity, position);
state.LinearVelocity = Vector3.Zero;
state.AngularVelocity = Vector3.Zero;
_resetPosition = null;
ResetCount++;
}
}Перед сбросом составного игрового объекта отдельно восстановите здоровье, таймеры и дочерние визуальные состояния. Пример сбрасывает только физическое состояние одного тела. У движущегося/повёрнутого родителя мировую позицию получите через ToGlobal. Не задавайте глобальный transform как локальный дочерний transform. ResetPhysicsInterpolation после телепорта решает визуальную интерполяцию отдельно; это не замена сброса скорости.
Контакты и состояние покоя
Для BodyEntered/BodyExited у RigidBody включите ContactMonitor и MaxContactsReported больше нуля. Лимит относится к контактам, а не обещанию такого же числа уникальных тел; одному телу могут соответствовать несколько точек. Обнаружение не означает, что нужно выключать тело прямо в callback — структурные изменения откладывайте.
Sleeping означает состояние сна симуляции, Freeze — выбранный режим заморозки. Они не равны Disabled у формы. Замороженная форма может оставаться препятствием. FreezeMode.Static и Kinematic различаются поведением при ручном перемещении; для регулярно движущейся платформы изучите AnimatableBody. Проверяйте результат на следующем физическом состоянии, а не в строке сразу после переключения режима.
CustomIntegrator отключает стандартную интеграцию сил для тела; это не способ отключить все контакты. Если он включён, рассчитывайте нужную гравитацию/силы через состояние либо осознанно вызывайте стандартную интеграцию. LockRotation запрещает обычное вращение, но не заменяет проверку геометрии и центра масс.
Повернуть к цели
Для физического поворота вычислите ошибку направления и управляйте угловой скоростью/моментом в физической фазе с ограничением скорости и коэффициентов. Непрерывный LookAt динамического тела принудительно меняет ориентацию и может ломать ожидаемую реакцию контактов. Если поворот нужен только рисунку, поверните отдельного визуального ребёнка. Отдельно учитывайте вырожденное направление, ось модели и кратчайший поворот; пример сброса намеренно восстанавливает единичную ориентацию, а не реализует сервопривод.
Если результат неожиданный
Не двигается — проверьте Freeze, Sleeping, блокировки осей, массу, фазу и фактическую силу. Нет сигнала — ContactMonitor, лимит контактов, фильтры и форма. Тело дрожит — нет ли параллельной записи Transform, стартового проникновения и крайних соотношений масс. Очень быстрый предмет проходит стену — проверьте толщину, шаг и CCD; большая масса сама по себе не исправляет дискретное обнаружение.