Перейти к основному содержимому
Живая игра

Эта страница ещё не переведена — показана английская версия.

Collision

Привяжите трансформ к карте препятствий и объявите, что происходит при контакте. Модуль Collision работает внутри симуляции платформы. Вы объявляете тела, слои и реакции, а на контакты подписываетесь.

Когда это нужно

  • Движущиеся сущности (entity) должны разрешать контакты на сервере — скользить, останавливаться, отскакивать, — и писать для этого свою процедуру отклонения не хочется.
  • Геймплей реагирует на касание: предметы подбираются при пересечении, а зоны-триггеры запускают машину состояний сущности.
  • Модулю Locomotion и снарядам нужна непрерывная (swept) проверка столкновений по набору препятствий карты.
  • Для превью размещения или прицеливания нужно спрашивать «поместится ли это здесь?» и искать пересечения объёмов.
  • Не нужен, если в игре ничего физически не сталкивается. Для геймплея по схеме «запрос — ответ» над записями хватит обычного модуля Data & Subscriptions.

Кто что делает

АкторЧто делает на этой странице
room-ownerобъявляет тела, слои и реакции; запрашивает пересечения и контакты

К каким комнатам это относится

Модуль работает там, где шаги симуляции считает платформа, — в комнатах (room), объявленных с Host = "Backend". Если симуляцией владеет ваш собственный игровой сервер (а PlayServ служит метасервером), перемещение, столкновения и предсказание остаются на стороне движка. Тогда эта страница описывает вариант с хостингом на платформе, а не обязательное требование.

Коротко

Форма, слой и реакция на контакт объявляются прямо на теле. Отдельного объявления пар слоёв где-то в стороне нет:

Капсула Body на танке, слой vehicles: скользит вдоль стен, проходит сквозь подбираемые предметы, а с ящиками решает при каждом контакте
[Entity("tank")]
public class Tank
{
    [Sync] public Vector3 Position;

    [Body(Shape.Capsule, Radius = 0.6f, Layer = "vehicles")]
    [CollidesWith("walls", Response.Slide)]
    [CollidesWith("pickups", Response.Pass)]        // reported, motion passes through
    public Body Body;
}
@Entity('tank')
export class Tank {
  @Sync() position!: Vector3;

  @Body({ shape: 'capsule', radius: 0.6, layer: 'vehicles' })
  @CollidesWith('walls', Response.Slide)
  @CollidesWith('pickups', Response.Pass)        // reported, motion passes through
  body: Body;
}
@entity("tank")
class Tank:
    position: Vector3 = sync()

    body = collision.body(shape="capsule", radius=0.6, layer="vehicles",
                           collides_with=[
                               ("walls", Response.SLIDE),
                               ("pickups", Response.PASS),   # reported, motion passes through
                           ])
Скоро — Go

Как объявлять через атрибуты в Go, пока не решено (O-1). Примеры появятся, когда выберут способ записи.

// the declaration rides inside the engine's own reflection macros, in the specifier position —
// UHT reads it from the header text, and the member is a reflected property at the same time
UCLASS(PSEntity = "tank")
class UTank : public UObject
{
    GENERATED_BODY()

    UPROPERTY(PSSync)
    FVector3f Position;

    // walls slide, pickups report the contact and let motion pass through —
    // multi-entry values are one quoted list (a specifier value is a single token)
    UPROPERTY(PSBody = (Shape = "Capsule", Radius = "0.6", Layer = "vehicles"),
              PSCollidesWith = "walls:Slide, pickups:Pass")
    FPSBody Body;
};
// declarations compile into the same pushed model — playserv push from the UE project or CI
Unity C# is the same C# API here — те же атрибуты компилируются в Unity на базовой версии 2021.3 — синтаксиса C# 12 здесь нет
[Entity("tank")]
public class Tank
{
    [Sync] public Vector3 Position;

    [Body(Shape.Capsule, Radius = 0.6f, Layer = "vehicles")]
    [CollidesWith("walls", Response.Slide)]
    [CollidesWith("pickups", Response.Pass)]        // reported, motion passes through
    public Body Body;
}

Контакт — это событие (event), и модули на него подписываются. Хука на контакт нет: к моменту, когда контакт возник, шаг его уже разрешил, и отклонять больше нечего. Если студии нужны другие правила, она переопределяет реализацию проверок допустимости и пути (см. Extensibility), а реакция по-прежнему задаётся объявлением.

Модель

Что объявляет тело.

Что объявляетсяЧто это
shapeпримитив из закрытого набора — сфера, капсула, параллелепипед — с объявленными размерами. Произвольного меша нет: ограничение то же и по той же причине, что и у серверной модели мира карты
где живёт телона аспекте, вместе с трансформом. Аспект — единица политики, и судьба у тела и трансформа общая
как проверяется путьstepwise — проверяется конечная позиция шага, это быстро. swept — проверяется отрезок между позициями, это дороже, зато в пределах шага тело не может проскочить сквозь препятствие. Способ объявляется, а не выбирается реализацией по скорости
в каких областях участвуетвнутри каких объёмов тело учитывается
связь с художественной модельюне обязательна: тело — это упрощение, и расхождение с художественной моделью допустимо в объявленных пределах

Быстрое тело со stepwise пролетает сквозь тонкие препятствия

stepwise проверяет только точку, где заканчивается шаг, поэтому быстрое тело может проскочить тонкое препятствие насквозь. swept проверяет отрезок между позициями и исключает такие проскоки в пределах шага. Может ли снаряд пролететь сквозь стену — свойство вашей игры, и объявляете его вы.

Реакция объявляется на пару «вид проходимости препятствия × тип тела» и выбирается из закрытого набора:

РеакцияЧто означает
stopдвижение прекращается в последней допустимой позиции
slideдвижение продолжается вдоль препятствия — на ту составляющую, которая допустима
bounceнаправление отражается, а скорость умножается на объявленный коэффициент
dampдвижение продолжается, а скорость умножается на объявленную долю
passпрепятствие не влияет на движение, но контакт всё равно можно наблюдать
исчезнутьсущность прекращает существование — например, снаряд, попавший в стену

Коэффициенты — это объявленные значения, а не результат расчёта по массам и материалам: ни масс, ни материалов в этом контракте нет.

Что верно для любой проверки.

ВсегдаЧто это
каждая параполучает реакцию. Пропущенная пара — это ошибка объявления (declaration): её отклонят при деплое, а не обнаружат посреди боя
таблица реакцийдоступна клиенту для чтения. Это та же таблица, по которой считает авторитетная сторона, поэтому клиент и сервер с одним объявлением одинаково ответят на один и тот же контакт
воспроизводимость на одной авторитетной стороне, но не между платформамиодинаковый ввод в одинаковом порядке даёт одинаковый результат в пределах одного процесса и одной сборки. Побитово одинаковых результатов на разных платформах и сборках не обещается
одновременностьобъявляется: если два движущихся тела сталкиваются внутри одного шага, порядок их разрешения объявлен и детерминирован. Основанием для него не могут быть порядок обхода хранилища, порядок прихода ввода или случайность
один контакт — один фактконтакт двух тел обе стороны видят как один факт с одним идентификатором, а не как два независимых события
точки расширения — на шаге, а не на контактедо шага трансформ можно изменить, после шага — только наблюдать. Переопределённые проверки допустимости и пути должны быть доступны и клиенту
модульсам ничего не двигает. Он отвечает, допустима ли позиция и какая будет реакция, а применяет это перемещение
контакт — это событиепоэтому модули подписываются на него, а не связываются напрямую. Машина состояний ловушки привязывает переход ко входу в зону-триггер, выпадающие предметы подбираются при пересечении, а снаряды находят попадания через swept-проверку этого модуля

Ошибки

  • «Недопустимо» — это ответ, а не ошибка, и в нём указано, какая из трёх причин сработала: позиция за границами, занята статическим препятствием или занята телом другой сущности. Клиент реагирует на них по-разному: развернуться, объехать или подождать.
  • Ошибки объявления всплывают при деплое, а не на первом контакте. Тело формы вне закрытого набора, тело на аспекте без трансформа и пара без объявленной реакции отклоняются при деплое.
  • Если сущность или место не найдены, ответ — not found, и повторять запрос бессмысленно.
  • Если превышена частота проверок, ответ приходит в категории ограничения частоты со сроком, до которого повторять бессмысленно.

Ограничения

Конкретные числа появятся вместе с главой об ограничениях платформы, а поведение на каждом пределе зафиксировано уже сейчас.

  • Тела в комнате: объявление ещё одного тела отклоняется как конфликт. Чтобы освободить место, существующие тела никогда не удаляются.
  • Контакты за шаг: лишние никогда не отбрасываются молча. Либо шаг отклоняется, либо порядок отсечения объявлен.
  • Размер тела относительно шага сетки карты: отклоняется при деплое, потому что тело меньше шага карты высот проваливается сквозь рельеф.
  • Области, в которых одновременно может находиться тело: превышение отклоняется при деплое.
  • Частота проверок на актора: ограничение частоты со сроком.
  • Тела в ответе на вопрос «кто в этой области»: список обрезается в объявленном порядке, и флаг обрезки обязателен.