Физические энтити на стороне клиента и сервера
Обзор
Основным преимуществом движка Source является физическая имитация твердых тел. Эта симуляция имплементирует основную механику и физику Ньютона такие как гравитация, траэктория, трение, столкновения, прыжки и плавание. Модели поддерживают эту имитация предоставляя информацию о их модели коллизий, типе материалов, весе и т.д. В режиме однопользовательской игры все физические энтити контроллируются и имитируются сервером (физика на стороне сервера) и коннектится с клиентом. В режиме многопользовательской игры мелкие объекты подобные жестянкм или бутылкам которые не влияют на геймплей полностью имитируются на стороне клиента и поэтому не синхронизируется между клиентами. Это необходимо в связи с тем что движение физических энтитей создает значительный сетевой траффик с того момента как они изменяют их позицию и базовую ориентацию в кажом фрейме. Сообщение по сети этих изменений может почти полнотсью захлебнуть все соединения как только начнут двигаться множество физ. объектов (взрывы, т.д.). Физ. объекты на стороне клиента не влияют на движение игрока и значительно меньше чем сам игрок, так что игрок не может спрятаться за ними. Во время разрушения бьющихся объектов, они разбиваются на меньшие фрагменты имитирующиеся на стороне клиента. Добавление физических энтитей
Для маппера довольно просто помещать физические энтити в Хаммере. Для однопользовательских карт класс энтити physics_prop должен быть использован для создания контроллируемых серверной стороной энтитей. Игрок выполняет корректную коллизию с этими энтитями, может проходить сквозь них, двигать их с разных сторон или поднимать их. К сожалению этот класс не может использоваться в многопользователськой игре так как взаимодействие игрока с физическими энтитями не спекулируются на стооне клиента и может вызвать неестественное, отрывчастое движение. Поэтому должен быть использован специальный класс энтити prop_physics_multiplayer, который имплементирует более упрощенное поведение коллизии (COLLISION_GROUP_PUSHAWAY). Многопользовательские физ. энтити только могут толкаться, но нельзя ходить сквозь них или поднимать. Если они больше игрока, он просто отталкивается. Становятся ли многопользовательские физ. энтити серверными или имитируются на стороне клиента, определяется в объекте модели.
Физические свойства модели определяются в ее .QC файле с помощью 3 секций: $surfaceprop, $collisionmodel, $keyvalues. Первая секция $surfaceprop устанавливает свойства поверхности модели как описано в текстовом файле scriptssurfaceproperties.txt. Тут описываются свойства типа трения, эластичностьзвуки коллизий. Следующая секция $collisionmodel устанавливает модель коллизий и вес объекта. Для простмотра модели коллизий для энтитей в игре включите консольную переменную "vcollide_wireframe 1". Третяя секция "prop_data" включенная в $keyvalues. Сдесь описываются свойства объекта например кол-во здоровья, разбиваемость модели и физический режим. Ниже приводится пример:
$surfaceprop "cardboard" // object surface properties
$collisionmodel "mymodel.smd" { $Mass 40 // Масса в килограммах $concave }
$keyvalues { "prop_data" { "base" "Cardboard.Medium" // базовый материал
определенный в propdata.txt "health" "40" // перезапись свойств материала "physicsmode" "1" // устанока произвольного режима физики } }
Режим физики в объекте определяет серверная или клиентская физика будет у этой энтити. Существует 2 серверных режима и один клиентский, описаны они в props_shared.h:
#define PHYSICS_MULTIPLAYER_AUTODETECT 0 // режим автоопределения
основанный на массе и размере #define PHYSICS_MULTIPLAYER_SOLID 1 // серверный, монолитный
(создает коллизии с игроком) #define PHYSICS_MULTIPLAYER_NON_SOLID 2 // серверный, не
монолитный #define PHYSICS_MULTIPLAYER_CLIENTSIDE 3 // клиентский, не
монолитный>
Если свойство физического режима не установлено в propdata.txt или в QC file, режим физики может быть получен из функции GetAutoMultiplayerPhysicsMode() основанный на размере и весе модели. Модель становиться с серверной физикой, если ее меньше определенной границы (устанавливается консольной переменной sv_pushaway_clientside_size).
Группы коллизий
По нескольким определенным причинам нет необходимости чтоб все динамические физ. энтити вызывали коллизии между собой. Это может быть по разным причинам геймплея, но больше это результат производительности. Особенно создание множеством мелких, быстро движущихся кусков осколков могут значительно снизить производительность. Для визуального эффекта бющихся осколков или взрывающихся частице-подобных объектов достаточно их коллизии с статическими предметами мира, но не самих с собой или других динамических объектов. Для имплементации специального поведения коллизий движок Source позволяет определять группы коллизий и указывать должны элменты этих групп сталкиваться или нет. Каждая энтить принадлежит только одной группе одновременно, устанавливается это функцией SetCollisionGroup(). Новые группы и новые правила могут быть просто добавлены. Физические подсистемы запрашивают виртуальную функцию bool CGameRules::ShouldCollide(int group0, int group1) для определения должна ли вызываться проверка коллизии между двумя объектами. Изначально определены группы:
COLLISION_GROUP_NONE | По умолчанию, сталкивается с статическими и динамическими объектами | COLLISION_GROUP_DEBRIS | Сталкивается только с миром и статическими вещами | COLLISION_GROUP_DEBRIS_TRIGGER | Тоже что и предыдущее, но переключает триггеры | COLLISION_GROUP_INTERACTIVE_DEBRIS | Сталкивается со всем за исключением других интерактивных осколков или
осколков | COLLISION_GROUP_INTERACTIVE | Сталкивается со всем за исключением интерактивных осколков или осколков | COLLISION_GROUP_PLAYER | Сталкивается с игроком | COLLISION_GROUP_BREAKABLE_GLASS | Специальная группа для стеклянных осколков | COLLISION_GROUP_VEHICLE | Группа коллизии для управляемого транспорта | COLLISION_GROUP_PLAYER_MOVEMENT | Для однопользовательского режима то же чо Collision_Group_Player; Для многопользовательского - это отфильтровывает других игроков и CBaseObjects
| COLLISION_GROUP_NPC | Базовая группа NPC | COLLISION_GROUP_IN_VEHICLE | Любая энтить внутри транспорта | COLLISION_GROUP_WEAPON | Для любого огружия требующего определения коллизий | COLLISION_GROUP_VEHICLE_CLIP | Клип браш для транспорта, для ограничения движения транспорта | COLLISION_GROUP_PROJECTILE | Пули | COLLISION_GROUP_DOOR_BLOCKER | Блокировка энтитей не допустимых к движению рядом с дверями | COLLISION_GROUP_PASSABLE_DOOR | Двери с которыми не может сталкиваться игрок | COLLISION_GROUP_DISSOLVING | Вещи проникают друг в друга | COLLISION_GROUP_PUSHAWAY | Немонолитные на стороне клиента и сервера, отталкивают игрока |
ДополнениеСписок допустимых комманд в секции $collisionmodel
модели: $mass | Установка массы модели вручную | $automass | Указывает физической системе вычислять массу для модели, основанную на ее
свойствах поверхнсти и размерах | $inertia | Инерциальная величина | $damping | Линейное торможение | $rotdamping | Вращательное торможение | $drag | Изменяет плотность (сопротивление) воздуха | $concave | Физ. модель коллизий не одна выпуклая оболочка. Если это не установлено, создается одна сплошная выпуклая оболочка вокруг
данной геометрии. | $masscenter | Переопределяет центр масс в локальных координатах | $jointskip | Редко используется. Исключает джоинт в модели коллизий из использования. (например если
используется рендеринг модели рагдолла, и в ней есть кости которые не нужны) | $jointmerge | Соединяет прикрепление вертексов для двух джоинтов. | $rootbone | Наиболее главная кость обладающая коллизией. | $jointconstrain | Ограничения движения джоинтов | $jointinertia | Подобно $inertia, но отдельно для кости | $jointdamping | Подобно $damping, но отдельно для кости | $jointrotdamping | Подобно $rotdamping, но отдельно для кости | $jointmassbias | Масса автоматически распространяется в объеме, это позволяет сместить ее к
костям | $noselfcollisions | Отключить всю коллизию между костями в данной моделиl, обычно для
производительности. | $jointcollide | Если указаны какието из $jointcollide, только этои джоинты подвергаются
коллизии между собой | $animatedfriction | Используется для изменения размера фрикции на джоинтах во времени. |
Список доступных записей для определений в propdata.txt: base | Указывает базовый опорный класс от которого происходит наследование
(базовые типы перечисляются в propdata.txt) | blockLOS | Переопределяет какая из опор может блокировать линию видимости для NPC | AIWalkable | Переопределяет какой из AI примет эту опору как проходимую. | dmg.bullets | Повреждения от пуль создаются на этой опоре. | dmg.club | Повреждения от ударов создаются на этой опоре. | dmg.explosive | Повреждения от взрывов создаются на этой опоре. | health | Количество здоровья которое нужно убрать для разрушения. | explosive_damage | Эта опора создает взрывное повреждение. | explosive_radius | Радиус взрыва создаваемый этой опорой когда она разрушается. | breakable_model | Тип разбиваемых осколков на которые может развалиться эта опора | breakable_count | Число осколков на которе распадается эта опора. | allowstatic | Позволяет этой опоре быть статической или физически имитируемой. | physicsmode | Устанавливает поведение сетевой физики (1 - полная, 2 - не монолитная, 3 - на
стороне клиента) | |