Ru/Authoring a Model Entity: Difference between revisions

From Valve Developer Community
< Ru
Jump to navigation Jump to search
mNo edit summary
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}}

Revision as of 05:17, 2 September 2006