Физические энтити на клиенте и сервере

From Valve Developer Community
< Ru
Jump to navigation Jump to search
English (en)Русский (ru)Translate (Translate)
Underlinked - Logo.png
This article needs more Wikipedia icon links to other articles to help Wikipedia icon integrate it into the encyclopedia. Please help improve this article by adding links Wikipedia icon that are relevant to the context within the existing text.
January 2024

Обзор

Основным преимуществом движка Source является физическая имитация твердых тел. Эта имитация реализует основную механику и физику Ньютона такие как гравитация, траектория, трение, столкновения, прыжки и плавание. Модели поддерживают эту имитация предоставляя информацию о их модели коллизий, типе материалов, весе и т.д. В режиме однопользовательской игры все физические энтити контроллируются и имитируются сервером (физика на стороне сервера) и передаются клиенту. В режиме многопользовательской игры мелкие объекты подобные консервным банкам или бутылкам которые не влияют на геймплей, полностью имитируются на стороне клиента и поэтому не синхронизируется между клиентами. Это необходимо в связи с тем что движение физических энтитей создает значительный сетевой траффик с того момента как они изменяют их позицию и базовое направление в каждом кадре. Сообщение по сети этих изменений может почти полностью блокировать любое соединение как только начнут двигаться множество физизических объектов в одно время (взрывы и т.д.). Физ-ие объекты на стороне клиента не влияют на передвижение игрока и они всегда должны быть гораздо меньше чем сам игрок, так что игрок не может спрятаться за ними. Во время разрушения серверных бьющихся объектов, они разбиваются на меньшие фрагменты имитирующиеся на стороне клиента.

Добавление физических энтитей

Для маппера довольно просто помещать физические энтити в Хаммере. Для однопользовательских карт класс энтити physics_prop должен быть использован для создания контроллируемых серверной стороной энтитей. Игрок выполняет корректную коллизию с этими энтитями, может проходить сквозь них, двигать их с разных сторон или поднимать их. К сожалению этот класс не может использоваться в многопользовательской игре так как взаимодействие игрока с физическими энтитями не предсказывается на стороне клиента и может вызвать неестественное или задержанное движение. Поэтому должен быть использован специальный класс энтити prop_physics_multiplayer, который реализует более упрощенное поведение коллизии (COLLISION_GROUP_PUSHAWAY). Многопользовательские физ-ие энтити только могут толкаться, но нельзя ходить сквозь них или поднимать их. Если они больше, игрок просто отталкивается. Становятся ли многопользовательские физ-ие энтити серверными или имитируются на стороне клиента, определяется в объекте модели.

Физические свойства модели определяются в её .QC файле с помощью 3 секций: $surfaceprop, $collisionmodel, $keyvalues. Первая секция $surfaceprop устанавливает свойства поверхности модели как описано в текстовом файле \scripts\surfaceproperties.txt. Тут описываются свойства типа трения, эластичности и звука коллизий. Следующая секция $collisionmodel устанавливает модель коллизий и вес объекта. Для простмотра модели коллизий для энтитей в игре включите консольную переменную "vcollide_wireframe 1". Третья секция "prop_data" включенная в $keyvalues. Здесь описываются свойства объекта например кол-во здоровья, разбиваемость модели и физический режим описанные в (полном описание prop_data(en)). Ниже приводится пример:

$surfaceprop "cardboard" // свойства поверхности объекта

$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 Отключить все коллизии между костями в данной модели, обычно для производительности
$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 - на стороне клиента)