~3 мин чтения

Физика — Bodies, Collision, Jolt

StaticBody3D, RigidBody3D, CharacterBody3D, Area3D — и почему с 4.6 физика стала быстрее.

Иллюстрация: Физика — Bodies, Collision, Jolt

С Godot 4.6 физикой по умолчанию для 3D стал Jolt — высокопроизводительный движок, используемый в Death Stranding 2 и других AAA-играх. Старый Godot Physics остался как опция и продолжает быть default для 2D.

Это значит: предсказуемая, масштабируемая 3D-физика из коробки. Никаких сторонних движков интегрировать не нужно.

Четыре класса тел

Узлы-наследники CollisionObject3D, образующие физический объект:

УзелКогда
StaticBody3DНе движется. Стены, пол, статичная архитектура.
AnimatableBody3DДвигается через анимацию или скрипт. Толкает RigidBody3D. Аналог Unity Kinematic Rigidbody.
RigidBody3DПолная динамика — гравитация, силы, импульсы, столкновения с реакцией.
CharacterBody3DКинематика для персонажа: вы задаёте velocity, движок двигает с учётом коллизий. Единственный узел с move_and_slide().

Также:

  • Area3D — невидимая область с триггерами body_entered/area_entered. Аналог Unity Collider с isTrigger=true.
  • PhysicalBone3D — для рэгдоллов внутри Skeleton3D.
  • SoftBody3D — мягкие тела (ткань, флаги, простые желейные объекты). Использует mesh-based soft-body simulation; работает и с Godot Physics, и с Jolt (с некоторыми ограничениями).

CollisionShape3D — форма для физики

В отличие от Unity, где collider — это компонент на том же GameObject, в Godot CollisionShape3D — это отдельный дочерний узел. У него свойство shape: Shape3D — ресурс, описывающий форму:

RigidBody3D (Player)
├── MeshInstance3D (визуальный mesh)
└── CollisionShape3D
    └── shape: CapsuleShape3D (height=2, radius=0.4)

Виды Shape3D:

  • BoxShape3D, SphereShape3D, CapsuleShape3D, CylinderShape3D — примитивы. Дёшево.
  • ConvexPolygonShape3D — выпуклый mesh. Для динамических объектов сложной формы.
  • ConcavePolygonShape3D — произвольный mesh (триангуляция). Только для статики.
  • HeightMapShape3D — рельеф из 2D-карты высот.
Один body может иметь несколько CollisionShape3D

Просто добавьте несколько дочерних CollisionShape3D — все станут shape’ами этого тела. Удобно для составных коллайдеров (например, машина: корпус + бампер).

CharacterBody3D — главный для платформера/FPS

CharacterBody3D хранит velocity: Vector3 и метод move_and_slide(), который пытается переместить тело на velocity * delta с учётом столкновений: останавливается, скользит вдоль стен, опускается по уклонам, поднимается на ступеньки.

extends CharacterBody3D

@export var speed: float = 5.0
@export var jump_velocity: float = 6.0

func _physics_process(delta: float) -> void:
    # Гравитация — из настроек проекта (Project Settings → Physics → 3D → Default Gravity)
    # get_gravity() возвращает Vector3(0, -9.8, 0) по умолчанию
    if not is_on_floor():
        velocity += get_gravity() * delta

    # Прыжок
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = jump_velocity

    # Горизонтальное движение
    var input_dir := Input.get_vector("move_left", "move_right", "move_forward", "move_back")
    var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
    if direction:
        velocity.x = direction.x * speed
        velocity.z = direction.z * speed
    else:
        velocity.x = move_toward(velocity.x, 0, speed)
        velocity.z = move_toward(velocity.z, 0, speed)

    move_and_slide()

Полезные методы и свойства CharacterBody3D:

  • is_on_floor(), is_on_wall(), is_on_ceiling() — простые проверки контакта.
  • get_floor_normal() — нормаль пола, на котором стоим.
  • floor_max_angle — максимальный угол склона, считающегося полом (по умолчанию 45°).
  • floor_snap_length — на какую глубину “примагнитить” к полу при сходе по склону (избегает отскоков на спусках).
  • get_slide_collision_count() + get_slide_collision(i) — детали столкновений за этот тик.
Веб

Свой 3D без движка: считаете next_pos = pos + velocity * dt, ловите коллизии руками. Сложно и багги.

Unity

CharacterController.Move(motion)move_and_slide(). CharacterBody3D мощнее: автоматически скользит по стенам, поднимается на ступеньки, прижимается к склонам — всё настраивается флажками.

RigidBody3D — динамика

Для физических объектов, реагирующих на силы (мяч, ящик, dropped item):

extends RigidBody3D

func _ready() -> void:
    mass = 2.0
    linear_damp = 0.5

func explode_push(direction: Vector3, force: float) -> void:
    apply_central_impulse(direction * force)

Методы:

  • apply_force(force: Vector3, position: Vector3 = Vector3.ZERO) — постоянная сила (в _physics_process).
  • apply_central_force(force) — сила в центр массы.
  • apply_impulse(impulse, position) — мгновенный импульс.
  • apply_central_impulse(impulse) — мгновенный импульс в центр массы.
  • apply_torque_impulse(impulse) — крутящий момент.

Свойства:

  • mass: float — масса.
  • gravity_scale: float — множитель гравитации (0 = нет, 1 = нормально).
  • linear_damp / angular_damp — затухание.
  • freeze / freeze_mode — заморозить.
  • lock_rotation: bool — запретить вращение.
  • continuous_cd: CCDModeDISABLED / CAST_RAY / CAST_SHAPE — для быстрых тел против туннелирования.

Area3D — триггеры

Area3D — не физическое тело, но генерирует сигналы при пересечении с другими CollisionObject3D:

extends Area3D

func _ready() -> void:
    body_entered.connect(_on_body_entered)
    area_entered.connect(_on_area_entered)

func _on_body_entered(body: Node3D) -> void:
    if body.is_in_group("player"):
        print("Player picked up coin")
        queue_free()

func _on_area_entered(area: Area3D) -> void:
    print("Another area overlapped: ", area.name)

Сигналы Area3D:

  • body_entered(body) / body_exited(body) — физическое тело вошло/вышло.
  • area_entered(area) / area_exited(area) — другая Area3D.
  • body_shape_entered, area_shape_entered — детализированные с индексами shape’ов.

Collision Layers и Masks

У каждого CollisionObject3D два битфилда:

  • Collision Layer — на каких слоях находится этот объект.
  • Collision Mask — какие слои этот объект сканирует (с кем пересекается / реагирует).

Чтобы A замечал B: маска A должна содержать слой(и) B. Чтобы взаимодействие было двусторонним, маска B тоже должна содержать слой A.

Имена слоёв настраиваются в Project Settings → Layer Names → 3D Physics.

Layer ≠ Mask, как Unity Layer Collision Matrix

В Unity матрица слоёв двунаправленная. В Godot — два независимых битфилда на каждом объекте. Это даёт больше гибкости (например, “пуля видит врага, но не наоборот”), но требует осторожности.

Jolt vs Godot Physics

С 4.6 Jolt — default для новых проектов 3D. Существующие проекты автоматически не переключаются — выставьте в Project Settings → Physics → 3D → Physics Engine.

ПараметрGodot PhysicsJolt
Производительность с 1000+ теламиДеградируетСтабильна
Stacking (стопки ящиков)Может проседатьЛучше
CCD (continuous)ЕстьЕсть, лучше
Doubleside thin collidersИногда багиСтабильно
JointsБазовыеПолный набор

Если у вас уже работающий проект на Godot Physics — оставайтесь. Для нового — Jolt.

В следующей главе — камера и Phantom Camera.