KF SDK: муверы, двери, триггеры и лифты
Руководство по муверам в KF SDK, которое написал K-2 для форума killingfloor.ru в 2011 году: создание муверов, триггеры и система Event > Tag, свойства муверов и разбор готовых примеров от простой двери до лифта. Основы работы с редактором описаны в основах редактора карт и в руководстве по маппингу. На том же форуме DiaLight выкладывал видеогайды по дверям и триггерам.
Муверы — это объекты, которые двигаются прямо во время игры. В KF это двери, лифты, машины, скейтборды и прочее. Создаются они из статиков и имеют похожие свойства, но у них есть и ряд дополнительных возможностей.
Создание мувера
- Выберите в браузере Static Mesh меш будущего мувера (например, дверь). Мувер можно сделать и из Solid-брашей, предварительно конвертировав их в статик.
- Нажмите правой кнопкой на кнопку Add Mover Brush и выберите обычный Mover. Он появится внутри браша-строителя, так что их Pivot совпадут. На 2D-видах мувер обведён розовым контуром.
- Созданная дверь находится в закрытом положении. Переместите её на место и подгоните размер через
DrawScale3D. - Закрытое положение — это ключ 0 (начальное). Чтобы дверь могла открываться, задайте положение 1: правый клик по двери, Mover > Key 1, затем передвиньте или поверните её в открытое положение.
- Проверьте: правый клик, Mover > Key 0 — дверь должна вернуться в начальное положение.
Движение хранится как разница координат, поэтому если двигать дверь в начальном положении, вместе с ней сдвинется и её открытый вариант.
Если запустить такую дверь в игре, она будет открываться при прямом контакте с игроком и закрываться через некоторое время.
Важно выбирать меш именно в браузере мешей и сразу создавать мувер кнопкой Mover. Если сначала поставить статик на карту, выделить его и нажать Mover, появится мувер в виде пистолета: это меш по умолчанию, который берётся, когда в браузере ничего не выбрано (уточнение K-2 из комментариев).
Тип активации (InitialState)
Тип активации задаётся в свойствах мувера на вкладке Object, главный параметр здесь — InitialState. Актуальные значения:
| Значение | Поведение |
|---|---|
ConstantLoop | Объект движется постоянно и не требует активации |
TriggerToggle | Мувер меняет положение, только если его активировал Event. По умолчанию используется для всех дверей в Killing Floor |
TriggerOpenTimed | Мувер «открывается» по Event и через определённое время возвращается в исходное положение |
BumpOpenTimed | Мувер «открывается» при контакте с ним и «закрывается» через определённое время. По умолчанию используется для Mover |
StandOpenTimed | Мувер активируется, когда на него встают, и «закрывается» через определённое время |
Триггеры и система Event > Tag
Триггеры — это активаторы, работающие по простой схеме Event > Tag (событие > метка). По сути это «кнопки», которые создают событие (Event), активирующее всё, у чего стоит соответствующая метка (Tag). Запускать так можно не только муверы.
У триггеров и муверов в свойствах есть вкладка Events. В свойствах триггера в поле Event пишется название события (любое придуманное), а в свойствах мувера в поле Tag — та же метка.
Триггеры находятся в браузере акторов (Actor Class), во вкладке Triggers. Для дверей подходят два типа:
- KFUseTrigger во вкладке UseTrigger (для лифтов есть также KFElevatorTrigger);
- KFProxyTrigger во вкладке Trigger.
Чтобы поставить триггер на карту, выберите его класс в браузере Actor Class, затем щёлкните ПКМ в нужном месте карты и выберите Add <название класса> Here (так добавляется любой объект из Actor Class). Для двери: Triggers → UseTrigger → KFUseTrigger, ставите «голову орла» в центр двери и связываете: в мувере в Tag пишете метку (например 555), а в триггере ту же метку в Event (K-2 и Gaiver5, тема «Триггеры», форум killingfloor.ru).
KFUseTrigger
Используется для стандартных дверей KF (KFDoorMover) с типом активации TriggerToggle: двери открываются и закрываются по кнопке «использовать». Выглядит как птичья голова и ставится в центр двери, туда, где будет индикатор заварки.
За сварку отвечает именно триггер; кроме того, двери можно запереть на ключ. Основные параметры:
| Параметр | Назначение |
|---|---|
MaxWeldStrength | Сколько очков сварки нужно, чтобы заварить дверь на 100% |
ReFireDelay | Задержка в секундах до повторной активации триггера |
Message (вкладка Use Trigger) | Сообщение на экране, когда игрок стоит рядом и может активировать триггер. Если ввести Press USE key, будет выводиться стандартное сообщение, которое переводится на русский в русской локализации |
О том, что KFUseTrigger работает только с KFDoorMover, подробнее в руководстве по маппингу.
KFProxyTrigger
Активируется при каком-либо взаимодействии с ним, типов активации у него больше, но для завариваемых дверей он не подходит.
| Параметр | Назначение |
|---|---|
bInitiallyActive | Активен ли триггер изначально |
bTriggerOnceOnly | Если True, триггер срабатывает только один раз |
ClassProximityType | Класс, на контакт с которым реагирует триггер при TT_ClassProximity |
DamageTreshold | Урон, нужный для активации (только при активации выстрелом) |
Message | Сообщение в углу экрана при взаимодействии игрока с триггером |
RepeatTriggerTime | Время, через которое действие триггера повторяется; для этого триггера не актуально |
ReTriggerDelay | Задержка в секундах от активации до возможности повторной активации |
TriggerType | Тип активации триггера (см. ниже) |
Значения TriggerType:
| Значение | Когда срабатывает |
|---|---|
TT_PlayerProximity | При контакте с игроком |
TT_PawnProximity | При контакте с игроками, зомби и ботами |
TT_ClassProximity | При контакте с классом, указанным в ClassProximityType |
TT_AnyProximity | При контакте с любым материальным объектом |
TT_Shoot | При выстреле; триггер при этом становится осязаемым для пуль |
TT_HumanPlayerProximity, TT_LivePlayerProximity | При контакте с игроком-человеком и с живым игроком, что по сути одно и то же |
Свойства муверов
Муверы настраиваются довольно гибко и сами могут работать как триггеры, создавая события. Основные свойства, общие для всех муверов, на вкладке Mover:
| Параметр | Назначение |
|---|---|
bDamageTriggered | Если True, мувер активируется выстрелом или ударом по нему |
bTriggerOnceOnly | При True мувер активируется только один раз |
BumpEvent | Event, который мувер создаёт (как триггер) при соприкосновении с ним |
BumpType | На какое касание реагирует мувер: Player — игрок, Pawn — игрок или AI, Any — любой объект |
DamageTreshold | Минимальный урон по муверу для активации при bDamageTriggered = True |
DelayTime | Задержка перед началом движения |
EncroachDamage | Урон при столкновении мувера с чем-либо; игроку наносится вдвое меньше указанного |
KeyNum | Текущее положение; переключается и в выпадающем меню, но через этот параметр можно задать больше 8 положений |
MoverEncroachType | Реакция на столкновение с игроком или зомби (см. ниже) |
MoverGlideType | Тип ускорения: GlideByTime — мувер разгоняется постепенно, MoveByTime — скорость постоянная |
MoveTime | Время, за которое мувер проходит путь от одного ключа до другого |
NumKeys | Количество ключей-положений. По умолчанию 2, но можно задать много; каждый отрезок проходится за MoveTime |
PlayerBumpEvent | Как BumpEvent, но срабатывает только при контакте с игроком |
StayOpenTime | Сколько дверь остаётся открытой при типах активации ...OpenTimed |
Значения MoverEncroachType:
| Значение | Поведение |
|---|---|
ME_StopWhenEncroach | Движение останавливается |
ME_ReturnWhenEncroach | Мувер возвращается в предыдущее положение |
ME_CrushWhenEncroach | Мувер буквально убивает препятствие |
ME_IgnoreWhenEncroach | Мувер продолжает движение |
На вкладке MoverEvents задаются события, которые срабатывают на разных стадиях движения мувера, на вкладке MoverSounds — звуки, сопровождающие движение.
Про то, что обычные муверы ломают пути зомби и что у KFDoorMover плохо редактируется задержка, см. раздел известных ошибок в руководстве по маппингу.
Свойства KFDoorMover
Двери в KF создаются как KFDoorMover: их можно заварить, и в них ломятся зомби. Дополнительные свойства:
| Параметр | Назначение |
|---|---|
bBlockDamagingOfWeld | Если True, сварка неразрушима, и дверь можно открыть только сварочным аппаратом |
bDisallowWeld | При True дверь нельзя заварить |
bElevOuterDoorTop / bElevOuterDoorBottom | Является ли дверь верхней / нижней дверью лифта |
bKeyLocked | Заперта ли дверь на ключ |
bSmallArmsDamage | При True двери можно нанести урон не только гранатами |
bStartSealed | Будет ли дверь заварена в начале каждой волны |
bZombiesIgnore | Будут ли зомби игнорировать заваренную дверь |
StartSealedWeldPrc | На сколько процентов заварена дверь при bStartSealed |
ZombieDamageReductionFactor | Урон от зомби: чем больше значение, тем быстрее зомби её сломают |
Здесь же задаются звуки разрушения двери.
Примеры муверов
На первый взгляд всё выглядит сложно, но это не так. K-2 собрал тестовую карту KF-MoversExample с простыми примерами; ниже описаны муверы с неё.
Обычная завариваемая дверь
- Мувер: KFDoorMover
- Триггер: KFUseTrigger
- Создайте KFDoorMover с двумя ключами-положениями (0 и 1). В примере взят Static Mesh двери из KF-Offices с теми же звуками открытия и закрытия.
- Поставьте KFUseTrigger в центр двери.
- Задайте
Eventтриггера иTagдвери одинаковыми:Door1. - В свойствах триггера поставьте
MaxWeldStrength = 200. Остальные значения стандартные.
Двойная дверь, заваренная в начале каждой волны
- Муверы: 2x KFDoorMover
- Триггер: KFUseTrigger
- Создайте два отдельных мувера, у каждого свои ключи. В примере за основу взята двойная дверь из KF-BioticsLab.
- Задайте обоим одинаковые свойства и одинаковый
Tag. - Поставьте один KFUseTrigger с
Event, равным этому тегу. ЗдесьMaxWeldStrength = 500. - Чтобы дверь заваривалась в начале каждой волны, у обоих муверов поставьте
bStartSealed = True.
Дверь, запертая на ключ
- Мувер: KFDoorMover
- Триггер: KFUseTrigger
- Сделайте обычную дверь и в её свойствах поставьте
bKeyLocked = TrueиbDisallowWeld = True. - Сделайте
Tagдвери иEventтриггера одинаковыми. - Добавьте ключ: в браузере акторов Actor > Pickup > KFKeyPickUp.
- В свойствах ключа на вкладке Events задайте
Tag, такой же как у двери.
Из-за бага такую дверь можно взорвать обычными гранатами.
Дверь торговца
- Мувер: KFTraderDoor
- Триггер: нет (активируется через ShopVolume)
Такие муверы нельзя сломать, заварить или взорвать. Открываются и закрываются они как обычные муверы; в KF их обычно ставят в магазинах. Случайно выбранная зона магазина (ShopVolume) после уничтожения волны создаёт Event, как триггер, а по окончании времени закупки создаёт его повторно, закрывая дверь.
- Создайте KFTraderDoor с ключами 0 и 1 и задайте ей
Tag. - В свойствах ShopVolume на вкладке Events задайте
Event, совпадающий с тегом двери. У разных магазинов события должны быть разными.
Если дверь магазина не открывается в конце волны, почти всегда не прописан Event в ShopVolume (из ответа K-2 в комментариях). В крайнем случае откройте в редакторе любую карту с рабочим магазином и повторите её настройки.
Двойная автоматическая дверь
- Муверы: 2x Mover, тип активации
TriggerOpenTimed - Триггеры: 2x KFProxyTrigger, тип активации
TT_PlayerProximity
- Создайте двойную дверь, как обычно, но из Mover.
- Поставьте KFProxyTrigger по обе стороны двери с
Event, равным тегу дверей. Когда игрок «наступает» на триггер, Event открывает двери. Благодаря типу активации мувер нельзя активировать повторно, пока он не «закроется». - Несмотря на
TT_PlayerProximity, такой дверью могут пользоваться и зомби. Чтобы дверь не блокировала их пути, у муверов на вкладке Collision поставьтеbPathColliding = False.
Дверь, открывающаяся выстрелом по кнопке
- Муверы: 2x Mover (кнопка и дверь), тип активации
TriggerToggle - Триггер: KFProxyTrigger, тип активации
TT_Shoot
- Поставьте KFProxyTrigger с
Event = btиbTriggerOnceOnly = True, чтобы его можно было активировать только один раз. - Сделайте мувер-кнопку с
Tag = bt. - У кнопки на вкладке MoverEvents задайте
OpenedEvent = ShootDoor— это тег мувера-двери. Event срабатывает, когда кнопка «откроется». - Сделайте мувер-дверь с
Tag = ShootDoorиbPathColliding = False.
Выстрел по триггеру нажимает кнопку, а кнопка открывает дверь.
Секретная дверь, открывающаяся от урона
- Мувер: Mover, тип активации
TriggerOpenTimed - Триггер: KFProxyTrigger, тип активации
TT_PlayerProximity(здесь не имеет значения)
- Сделайте мувер из Solid-браша, конвертированного в статик.
- Поставьте
bDamageTriggered = True. - Задайте 3 ключа (0-2) и
NumKeys = 3.
После выстрела дверь сначала немного вдвигается внутрь, потом открывается, а через некоторое время закрывается.
Скейт, прыгающий через трамплин
- Мувер: Mover, тип активации
TriggerToggle - Триггер: нет (мувер активирует сам себя при контакте с игроком)
- Задайте муверу 9 ключей так, чтобы за одинаковое время он проходил одинаковое расстояние (не считая подъёма и спуска).
- Поставьте
PlayerBumpEvent, равный его жеTag: мувер запускается, когда до него дотрагивается игрок. - Чтобы при переходе между ключами не было торможения, поставьте
MoverGlideType = MoveByTime.
Со стороны выглядит немного кривовато, но это всё-таки обычный мувер.
Раздатчик
- Муверы: 4x Mover, тип активации
TriggerOpenTimed - Триггер: KFProxyTrigger, тип активации
TT_ClassProximity
- Внутри «приёмника» поставьте триггер, который реагирует на брошенные деньги:
ClassProximityType = Class'KFMod.CashPickup'. - Event триггера закрывает дверцы приёмника и одновременно открывает другие, за которыми появляется броня.
Заставить триггер реагировать на определённую сумму стандартными средствами нельзя: триггер реагирует на сам контакт с классом, а не на его свойства. Для этого понадобится свой класс актора со скриптом. Можно, например, сделать «пункт обмена» из нескольких триггеров, реагирующих на определённое брошенное оружие (из ответов K-2 в комментариях).
Подъёмник-платформа
- Мувер: Mover, тип активации
StandOpenTimed(срабатывает, когда на него встают)
Лифт можно сделать и как дверь, открывающуюся вертикально, но тогда им смогут пользоваться только игроки, и с этим связано много багов.
Лифт-платформа — простейший рабочий лифт, такие часто использовались в UT2004. От обычного мувера он отличается только специальными точками: выходами LiftExit и центром LiftCenter (браузер акторов, вкладка NavigationPoint).
- Создайте мувер-платформу с
InitialState = StandOpenTimed. - Поставьте LiftCenter в «центр» мувера, находящегося в положении 0. Точка двигается вместе с лифтом, на ней AI стоит во время движения. В свойствах LiftCenter, на одноимённой вкладке, укажите
Tagлифта. - Поставьте точки LiftExit — условные выходы, через которые боты уходят после остановки мувера. В их свойствах задайте
Tagлифта иSuggestedKeyFrame— при каком ключе-положении активен этот выход.
Обычный лифт на 2 этажа
- Муверы: KFElevator, 2x KFElevatorDoorMover, 4x KFTraderDoor
- Тип активации:
Elevator(лифт),TriggerToggle(двери) - Триггеры: 3x KFElevatorTrigger
Разработчики изначально задумывали лифты в KF, поэтому для них есть специальные муверы и триггеры. Но с лифтами было связано много багов, и ни на одной официальной карте их нет. Такой лифт можно вызывать, и у него есть двери, которые открываются и закрываются в зависимости от положения лифта.
- Создайте мувер KFElevator, задайте ему
Tagи ключи-положения. - В свойствах лифта, KFElevator > ElevatorFloorTags, задайте теги для каждого ключа, например
BottomFloorдля нижнего этажа иTopFloorдля верхнего. - Поставьте KFElevatorTrigger внутрь лифта (в начальном положении) и задайте ему
Tag, напримерElevatorLiftTrigger. Тот же тег впишите в свойствах лифта: вкладка KFElevator, полеElevatorCenterTrigger. Этим триггером лифт запускается изнутри. - На каждый этаж поставьте по KFElevatorTrigger с
Tag, заданным ранее вElevatorFloorTagsдля этого этажа. Этими триггерами лифт вызывают. - Добавьте точки LiftExit и LiftCenter, как у платформы, но в свойствах LiftCenter, кроме тега лифта, впишите ещё тег центрального триггера (KFElevatorTrigger внутри лифта).
- Двери. У KFElevatorDoorMover есть недостатки: их можно сломать или взорвать. Лучше использовать двери торговца, которые приводятся в действие KFElevatorDoorMover. Создайте верхнюю и нижнюю условные двери лифта как KFElevatorDoorMover и спрячьте их где-нибудь за картой, вне поля зрения игроков.
- Нижней условной двери на вкладке KFDoorMover поставьте
bElevOuterDoorBottom = True, верхней —bElevOuterDoorTop = True. - На вкладке MoverEvents каждой условной двери задайте события Closing и Opening, которые будут двигать настоящие нижние или верхние двери, например
BottomDoorsдля нижней иTopDoorsдля верхней. - Поставьте по паре KFTraderDoor на нижний и верхний этаж; каждой паре задайте
Tag, указанный в MoverEvents соответствующей условной двери.
Таким лифтом могут пользоваться и вызывать его не только игроки.
Уничтожитель
- Муверы: 11x Mover, тип активации: 10x
TriggerOpenTimed, рычаг —BumpOpenTimed - Триггер: нет (запускается мувером-рычагом)
На серьёзных картах, претендующих на белый список, такое лишнее, но собирается конструкция легко и выглядит очень зрелищно. В неё входят 3 пары крушителей, 2 циркулярные пилы, 2 держателя для пил и 1 рычаг.
- У пил и крушителей поставьте
MoverEncroachType = ME_CrushWhenEncroachи большойEncroachDamage. - Рычагу задайте Event, который запускает пилы с держателями и первую пару крушителей.
OpenedEventпервой пары крушителей запускает вторую пару, а та — третью: получается небольшая цепная реакция.- Чтобы пилы вращались независимо от активации, у них на вкладке Movement задайте
RotationRateпо оси Yaw и поставьтеbFixedRotationDir = True.
Через некоторое время все муверы возвращаются в исходное положение, и конструкцию можно запустить снова.
Муверы — интересная тема, и при наличии фантазии с ними можно сделать уникальные вещи. Игра таким разнообразием не балует, так что необычная идея обязательно запомнится игрокам.
Ответы K-2 из тем «Вопросы по картостроению» и «Непростые вопросы по МАППИНГУ»
По двум темам вопросов к мапперам на форуме killingfloor.ru.
Остальные значения InitialState (K-2 писал по памяти и предупреждал, что может ошибаться):
| Значение | Поведение |
|---|---|
LeadInOutLooper | При активации мувер циклично перемещается между ключами 0 и 1 и возвращается в положение 0 при повторной активации |
TriggerAdvance | Пока игрок находится в «активной зоне» триггера, мувер движется к конечному положению; если игрок выходит, движение останавливается и при повторном входе продолжается с той же точки |
TriggerControl | Пока игрок активирует триггер, мувер движется к конечному положению и остаётся в нём; если «контакт» прерывается, мувер возвращается в исходное положение, даже если не «открылся» до конца |
TriggerPound | Как TriggerControl, но по прошествии OtherTime закрывается; каждый отрезок проходится за MoveTime, поэтому полузакрывшийся мувер откроется за то же время, что и из исходного положения |
LoopMove | Как ConstantLoop, но требует постоянной активации от триггера |
Баррикада, которую нельзя заварить, но которая восстанавливается к каждой волне. Сделайте её как KFDoorMover и на вкладке KFDoorMover поставьте bDisallowWeld = True и bStartSealed = True, а в StartSealedWeldPrc впишите, на сколько процентов она будет заварена. Остальные параметры этой вкладки оставьте False. Оптимальные значения ZombieDamageReductionFactor — 0.75-0.95, по умолчанию 0.85. У автора вопроса баррикады получились неубиваемыми, пока он не поставил к ним триггеры.
KFGlassMover (разрушаемые машины и вертолёты, как на KF-Abandoned-Base-MacabreDay) — «неразмещаемый» класс, его нет в списке Add Mover Brush. Проще всего скопировать такой мувер с другой карты и отредактировать: StaticMesh меняется на вкладке Display. Огонь и обломки при ударах по нему, скорее всего, заданы кастомным Emitter-ом в полях GlassBits и BreakGlassBits.
Другая текстура у копии мувера. Опция Display > Texture > Use для мувера не срабатывает; текстуру дубликата меняйте на вкладке Skins (раздел Display свойств).
Зона срабатывания триггера. Огромными триггеры на картах делают, чтобы их было легче найти и отличить. Сама «активная зона» определяется коллизией и расширяется на соответствующей вкладке свойств. Чтобы видеть её, включите в окне редактора RadiiView (ПКМ по рамке > Actors > RadiiView).
Поштучный спавн зомби через ScriptedTrigger. KFProxyTrigger с RepeatTriggerTime, запускающий ScriptedTrigger-зомбогенератор, потом не остановить, а повтор через GOTOACTION «зацикливается» и тоже не отменяется. K-2 советовал сделать ProxyTrigger одноразовым (bTriggerOnceOnly) и поставить 2-4 ScriptedTrigger-а: каждому в последовательность добавить нужное число спавнов (1 зомби — 1 action), а между действиями SpawnActor — интервал в 1-2 секунды (Action_WAITFORTIMER). Много ScriptedTrigger-ов на карте практически не влияет ни на компиляцию, ни на производительность.
Тихий звук мувера. Импортированные звуки мувера слышно еле-еле, даже на максимальной громкости, а стандартные звучат нормально. По словам K-2, редактор при импорте автоматически конвертирует звуки в стерео; попробуйте импортировать моно-звуки, хотя 100% гарантии нет. Gaiver5 тоже не советовал стерео: моно работает в SDK оптимально, но немного тише.