Эта страница ещё не переведена — показана английская версия.
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, пока не решено (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[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, и повторять запрос бессмысленно.
- Если превышена частота проверок, ответ приходит в категории ограничения частоты со сроком, до которого повторять бессмысленно.
Ограничения
Конкретные числа появятся вместе с главой об ограничениях платформы, а поведение на каждом пределе зафиксировано уже сейчас.
- Тела в комнате: объявление ещё одного тела отклоняется как конфликт. Чтобы освободить место, существующие тела никогда не удаляются.
- Контакты за шаг: лишние никогда не отбрасываются молча. Либо шаг отклоняется, либо порядок отсечения объявлен.
- Размер тела отн осительно шага сетки карты: отклоняется при деплое, потому что тело меньше шага карты высот проваливается сквозь рельеф.
- Области, в которых одновременно может находиться тело: превышение отклоняется при деплое.
- Частота проверок на актора: ограничение частоты со сроком.
- Тела в ответе на вопрос «кто в этой области»: список обрезается в объявленном порядке, и флаг обрезки обязателен.