|
|
Line 1: |
Line 1: |
| [[Category:Russian]]
| |
| [[Category:Программирование]]
| |
|
| |
|
| После [[Создание логической энтити|создания логической энтити]] в предыдущем примере, теперь создадим энтить которая может двигаться, создавать коллизии с остальнымио бъектами, и которая имеет визуальную компоненту (в данном случае, модель). В этом примере мы создадим энтить которая отображается используя модель, и перемещаются по миру случайным образом.
| |
|
| |
| =Создаем CPP файл для новой энтити=
| |
| [[Image:Add existing item.gif|Добавляем исходный файл в проект server.dll по правому щелчку.]]
| |
|
| |
| * Создаем файл называемый <code>sdk_modelentity.cpp</code>. Этот файл должен быть внутри пакпки dlls которая находить в папке с вашим исходным кодом. Например, если вы установили код в <code>C:\MyMod\src</code>, тогда вы должны создать файл называемый <code>C:\MyMod\src\dlls\sdk_modelentity.cpp</code>.
| |
| * Далее копируем [[Model Entity |этот код]] и вставляем его в новый файл.
| |
| * В последнею очередь добавляем этот файл в ваш проект server.dll. Если вы открыли <code>game_sdk.sln</code> solution, тогда вы можете щелкнуть правой кнопкой на проекте hl в окне Solution Explorer и выбрать Add, затем Add Existing Item.
| |
|
| |
| =Рассмотрение кода=
| |
|
| |
| ==Создание определения класса==
| |
|
| |
| <pre>
| |
| class CMyModelEntity : public CBaseAnimating
| |
| {
| |
| public:
| |
| DECLARE_CLASS( CMyModelEntity, CBaseAnimating );
| |
| DECLARE_DATADESC();
| |
|
| |
| void Spawn( void );
| |
| void Precache( void );
| |
| void MoveThink( void );
| |
|
| |
| // Функция ввода
| |
| void InputToggle( inputdata_t &inputData );
| |
|
| |
| private:
| |
| bool m_bActive;
| |
| float m_flNextChangeTime;
| |
| };
| |
| </pre>
| |
|
| |
| Мы наследуем нашу энтить от класса <code>CBaseAnimating</code>. Это позволяет использовать модели и анимацию. Также новыми для этой энтити являются функции <code>Spawn()</code> и <code>Precache()</code>.
| |
|
| |
| ==Определяем описание данных==
| |
|
| |
| <pre>
| |
| LINK_ENTITY_TO_CLASS( my_model_entity, CMyModelEntity );
| |
|
| |
| // Начинаем описание наших данных для класса
| |
| BEGIN_DATADESC( CMyModelEntity )
| |
|
| |
| // Сохраняем/востанавливает наще активное состояние
| |
| DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ),
| |
| DEFINE_FIELD( m_flNextChangeTime, FIELD_TIME ),
| |
|
| |
| // Связываем наше имя input из Хаммера к нашей input функции
| |
| DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
| |
|
| |
| // Описываем нашу think функцию
| |
| DEFINE_THINKFUNC( MoveThink ),
| |
|
| |
| END_DATADESC()
| |
| </pre>
| |
|
| |
| Подобно нашей логической энтити, мы должны объявить переменные используемые энтитью так чтоб движок знал их смысл.
| |
| Важно отметить что функция <code>MoveThink()</code> должна быть объявлена как энтить с think-функцией таблице описания данных используя макрос <code>DEFINE_THINKFUNC</code>. Смотрите документ о [[Описание данных|таблице описания данных]] для дополнительной информации.
| |
|
| |
| ==Создаем Precache() функцию==
| |
| <pre>
| |
| #define ENTITY_MODEL "models/gibs/airboat_broken_engine.mdl"
| |
|
| |
| void CMyModelEntity::Precache( void )
| |
| {
| |
| PrecacheModel( ENTITY_MODEL );
| |
| }
| |
| </pre>
| |
|
| |
| <code>Precache()</code> функция выполняет кеширование всех нужных файлов. Для дополнительной информации по теме, смотрите [[Кэширование файлов]]. Здесь мы также определяем модель которая представляет нашу энтить в мире.
| |
|
| |
| В данном примере мы вызываем <code>PrecacheModel()</code> для кеширования модели. Без этого шага, модель энтити не появиться в мире и движок будет жаловаться на отсутствующее кэширование.
| |
|
| |
| ==Создаем Spawn() функцию==
| |
| <pre>
| |
| void CMyModelEntity::Spawn( void )
| |
| {
| |
| Precache();
| |
|
| |
| SetModel( ENTITY_MODEL );
| |
| SetSolid( SOLID_BBOX );
| |
| UTIL_SetSize( this, -Vector(20,20,20), Vector(20,20,20) );
| |
|
| |
| m_bActive = false;
| |
| }
| |
| </pre>
| |
|
| |
| Функция <code>Spawn()</code> вызывается после создания энтити. Эта функция может считаться игровым конструктором энтити. Здесь энтить может установить ее начальное состояние, включая то что модель использует, ее способы движения и твердость. Важно отметить что функция <code>Spawn()</code> вызывается немедленно после размещения энтити в памяти и поскольку это происходит в самом начале карты, нет гарантии что все остальные энтити к этому моменту были успешно созданы. В связи с этим, любой код связывающий данную энтить с поиском или связью с другими именованными энтитями должен производиться в функции <code>Activate()</code> данной энтити. Функция Activate()</code> вызывается когда все энтити создались и произвели запуски их Spawn() функций. Поиск энтитей перед функцией Activate() зависит от порядка создания энтитей и является ненадежным.
| |
|
| |
| В приведенном ниже примере, сначала вызывается функция <code>Precache()</code> для того чтобы удостовериться что все файлы будут корректно кэшированы. После чего, используется функция<code>SetModel()</code> для установки модели определенной до этого.
| |
|
| |
| Далее, устанавливается твердость энтити с помощью функции <code>SetSolid()</code>. Здесь доступны несколько допустимых типов твердости:
| |
|
| |
| {|
| |
| | <code>SOLID_NOT</code> || Отсутствует.
| |
| |-
| |
| | <code>SOLID_BSP</code> || Использует BSP дерево для определения твердости (используется для браш-моделей)
| |
| |-
| |
| | <code>SOLID_BBOX</code> || Используется выравненый по осям ограничительный бокс.
| |
| |-
| |
| | <code>SOLID_CUSTOM</code> || Энтить определяет ее собственные функции для проверки колизий.
| |
| |-
| |
| | <code>SOLID_VPHYSICS</code> || Использует объект vcollide для проверки коллизий.
| |
| |}
| |
|
| |
| В данном примере, мы создаем энтить использующую ограничительный бокс. Функция <code>UTIL_SetSize()</code> позволяет установить размер ограничительного бокса. Здесь мы устанавливаем куб размером 40x40x40.
| |
|
| |
| ==Создаем MoveThink() функцию==
| |
|
| |
| Энтити способны обновлять внутренее состояние и принимать решения с помощью функции <i>think</i>, которая вызывается с частотой указанной энтитью. Ниже мы создаем think-функцию которая вызывается 20 раз в секунду. Эта функции используется для случайного обновления передвижения и направления в мире.
| |
|
| |
| <pre>
| |
| void CMyModelEntity::MoveThink( void )
| |
| {
| |
| // Смотрим если мы должны снова изменить направление
| |
| if ( m_flNextChangeTime < gpGlobals->curtime )
| |
| {
| |
| // Случайно выбираем новое направление и скорость
| |
| Vector vecNewVelocity = RandomVector( -64.0f, 64.0f );
| |
| SetAbsVelocity( vecNewVelocity );
| |
|
| |
| // Случайно изменяем его снова через 1-3 секунд
| |
| m_flNextChangeTime = gpGlobals->curtime + random->RandomFloat(1.0f,3.0f);
| |
| }
| |
|
| |
| // Устанавливаем лицо по направлению движения
| |
| Vector velFacing = GetAbsVelocity();
| |
| QAngle angFacing;
| |
| VectorAngles( velFacing, angFacing );
| |
| SetAbsAngles( angFacing );
| |
|
| |
| // Думаем каждые 20Гц
| |
| SetNextThink( gpGlobals->curtime + 0.05f );
| |
| }
| |
| </pre>
| |
|
| |
| Эта функция содрежит много кода, но смысл его довольно прост: после прохождения случайного интервала времени, энтити выбирает новое, случайное направление и скорость путешествия. Он также обновляет углы чтобы лицо было направлено по направлению движения.
| |
|
| |
| Вызов функции <code>SetNextThink()</code> важен, потому что это говорит энтити когда думать в следующий раз. Здесь устанавливается вызвать think через 1/20 секунды. Для большинства энтитей только нужно думать с частотой 1/10 секунды, взависимости от из поведения. Важно заметить что если не обновить next think time для энтити это приведет к тому что она престанет думать (иногда это удобно).
| |
|
| |
| ==Создаем ToggleInput() функцию==
| |
|
| |
| Для данной энтити мы используем ввод(input) для переключения ее передвижения как включенного/выключенного. Для этого, мы объявляем input-функцию подобной из предыдущего урока.
| |
|
| |
| <pre>
| |
| void CMyModelEntity::InputToggle( inputdata_t &inputData )
| |
| {
| |
| // Переключаем наше состояние активности
| |
| if ( !m_bActive )
| |
| {
| |
| // Начинаем думать
| |
| SetThink( MoveThink );
| |
| SetNextThink( gpGlobals->curtime + 0.05f );
| |
|
| |
| // Начинаем летать
| |
| SetMoveType( MOVETYPE_FLY );
| |
| // Устанавливаем следующее время когда меняем скорость и направление
| |
| m_flNextChangeTime = gpGlobals->curtime;
| |
| m_bActive = true;
| |
| }
| |
| else
| |
| {
| |
| // Перестаем думать
| |
| SetThink( NULL );
| |
|
| |
| // Перестаем двигаться
| |
| SetAbsVelocity( vec3_origin );
| |
| SetMoveType( MOVETYPE_NONE );
| |
|
| |
| m_bActive = false;
| |
| }
| |
| }
| |
| </pre>
| |
|
| |
| Для начала "работы" энтити используется функция <code>SetThink()</code> в соединении с функцией <code>SetNextThink()</code>. Она сообщает энтити использовать функцию <code>MoveThink()</code> и вызывается через 1/20 секунды. Важно отметить что энтить может иметь любое количество think-функций и использовать <code>SetThink()</code> функцию для выбора между ними. Каждая энтить может иметь несколько think-функций выполняющихся в одно и то же время используя <code>SetContextThink()</code> описанной в другом документе.
| |
|
| |
| Также мы определяем тип движения энтити <code>MOVETYPE_FLY</code>. Это позволяет энтити двигаться в заданном направлении без гравитации.
| |
|
| |
| Во второй части энтити этой функции мы останавливаем энтить от движения. think-функция устанавливается в <code>NULL</code> для остановки think-процесса. Её тип движения также устанавлтвается <code>MOVETYPE_NONE</code> чтобы предотвратить движение.
| |
|
| |
| ==Создаем запись в FGD файле==
| |
|
| |
| Для использования энтити в Хаммере, мы должны создать запись в FGD файле. Хаммер будет использовать эти данные для того чтобы понять различные ключевые значения и функции которые предоставляет энтитя. Смотрите [[FGD |документ FGD формата]] для дополнительной информации о FGD файлах.
| |
|
| |
| Запись FGD для энтити просто отображает модель в хаммере и позволяет отправлять input "Toggle" ей.
| |
|
| |
| <pre>
| |
| @PointClass base(Targetname) studio("models/gibs/airboat_broken_engine.mdl")= my_model_entity : "Tutorial model entity."
| |
| [
| |
| input Toggle(void) : "Toggle movement."
| |
| ]
| |
| </pre>
| |
|
| |
| Если ваш .FGD не пустой, убедитесь что добавили строку @include "base.fgd", которая даст вам некоторые нужные функции Хаммера. (При полном преобразование. Мод основанный на существующем содержимом, включайте соответствующие FGD файлы; на пример для [[HL2]] мода, включите <code>halflife2.fgd</code> вместо <code>base.fgd</code>.)
| |
|
| |
| {{otherlang:ru}}
| |
| {{otherlang:ru:en|Authoring a Brush Entity}}
| |