Ru/Authoring a Logical Entity: Difference between revisions
KindDragon (talk | contribs) No edit summary |
KindDragon (talk | contribs) No edit summary |
||
Line 2: | Line 2: | ||
[[Category:Программирование]] | [[Category:Программирование]] | ||
После создания логической энтити в предыдущем примере, теперь создадим энтить которая может двигаться, создавать коллизии с остальными объектами, и которая имеет визуальную компоненту (в данном случае, модель). В этом примере мы создадим энтить которая отображается используя модель, и перемещаются по миру случайным образом. | |||
=Создаем CPP файл для новой энтити= | =Создаем CPP файл для новой энтити= | ||
[[Image:Add existing item.gif|Добавляем исходный файл в проект server.dll по правому щелчку.]] | [[Image:Add existing item.gif|Добавляем исходный файл в проект server.dll по правому щелчку.]] | ||
* Создаем файл называемый <code> | * Создаем файл называемый <code>sdk_modelentity.cpp</code>. Этот файл должен быть внутри пакпки dlls которая находить в папке с вашим исходным кодом. Например, если вы установили код в <code>C:\MyMod\src</code>, тогда вы должны создать файл называемый <code>C:\MyMod\src\dlls\sdk_logicalentity.cpp</code>. | ||
* Далее копируем [[ | * Далее копируем [[Model Entity |этот код]] и вставляем его в новый файл. | ||
* В последнею очередь добавляем этот файл в ваш проект server.dll. Если вы открыли <code>game_sdk.sln</code> solution, тогда вы можете щелкнуть правой кнопкой на проекте hl в окне Solution Explorer и выбрать Add, затем Add Existing Item. | * В последнею очередь добавляем этот файл в ваш проект server.dll. Если вы открыли <code>game_sdk.sln</code> solution, тогда вы можете щелкнуть правой кнопкой на проекте hl в окне Solution Explorer и выбрать Add, затем Add Existing Item. | ||
=Рассмотрение кода= | =Рассмотрение кода= | ||
==Определение класса== | ==Определение класса== | ||
<pre> | <pre> | ||
class | class CMyModelEntity : public CBaseAnimating | ||
{ | { | ||
public: | public: | ||
DECLARE_CLASS( CMyModelEntity, CBaseAnimating ); | |||
DECLARE_DATADESC(); | |||
void Spawn( void ); | |||
void Precache( void ); | |||
void MoveThink( void ); | |||
// Input function | |||
void InputToggle( inputdata_t &inputData ); | |||
private: | |||
bool m_bActive; | |||
float m_flNextChangeTime; | |||
}; | }; | ||
</pre> | </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 из Hammer с нашей input function | |||
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ), | |||
// Объявляет think функцию | |||
DEFINE_THINKFUNC( MoveThink ), | |||
END_DATADESC() | |||
</pre> | |||
Подобно нашей логической энтити, мы должны объявить переменные используемые энтитью так чтоб движок знал их смысл. Важно отметить что функция <code>MoveThink()</code> должна быть объявлена как энтить с think-функцией таблице описания данных используя макрос <code>DEFINE_THINKFUNC</code>. Смотрите [[Описание данных|таблицу описания данных]] для дополнительной информации. | |||
==Создаем Precache() функцию== | |||
<pre> | <pre> | ||
#define ENTITY_MODEL "models/gibs/airboat_broken_engine.mdl" | |||
void CMyModelEntity::Precache( void ) | |||
{ | |||
PrecacheModel( ENTITY_MODEL ); | |||
} | |||
</pre> | </pre> | ||
Здесь мы | <code>Precache()</code> функция выполняет кеширование всех нужных файлов. Для дополнительной информации по теме смотрите [[Кэширование файлов|кеширование файлов]]. Здесь мы также определяем модель которая будет использоваться для отображения энтити в мире. | ||
В данном примере мы вызываем <code>PrecacheModel()</code> для кеширование нашей модели. Без этого шага, модель энтити не появиться в мире и движок будет жаловаться на отсутствующее кэширование. | |||
== | ==Создаем Spawn() функцию== | ||
<pre> | <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> данной энтити. Функция <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> | <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> | </pre> | ||
Хотя много кода написано в этой функции, но её действие очень просто описывается: как только проходит случайный интервал времени, энтить выбирает новое, случайное направление и скорость для путешествия. Она также обновляет угл направления лица к направлению его путешествия. | |||
Вызов <code>SetNextThink()</code> важен для этой функции, потому что он говорит энтити когда вследующий раз думать. Здесь устанавливается думать снова через 1/20-ую секунды в будущем. Большинству энтитям только нужно думать с частотой 1/10 секунды, взависимости от их поведения. Важно заметить необновив следующее время срабатывание функции приведет к тому что энтить перестает думать (что иногда желательно). | |||
==Создаем функцию | ==Создаем InputToggle() функцию== | ||
Для данной энтити мы используем ввод(input) для переключения ее передвижения как включенного/выключенного. Для этого, мы объявляем input-функцию подобной из предыдущего урока. | |||
<pre> | <pre> | ||
void | 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> | </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> | <pre> | ||
@PointClass base(Targetname) = | @PointClass base(Targetname) studio("models/gibs/airboat_broken_engine.mdl")= my_model_entity : "Tutorial model entity." | ||
[ | [ | ||
input Toggle(void) : "Toggle movement." | |||
input | |||
] | ] | ||
</pre> | </pre> | ||
Если ваш .FGD не пустой, убедитесь что добавили строку <code>@include "base.fgd"</code>, которая даст вам некоторые нужные функции Хаммера. | Если ваш .FGD не пустой, убедитесь что добавили строку <code>@include "base.fgd"</code>, которая даст вам некоторые нужные функции Хаммера. (Это соответствует полному преобразованию. Для мода основанного на существующем содержимом, включайте подходящие FGD вместо базового; к примеру, для модов [[HL2]], включите <code>halflife2.fgd</code> вместо <code>base.fgd</code>.) | ||
{{otherlang:ru}} | {{otherlang:ru}} | ||
{{otherlang:ru:en|Authoring a | {{otherlang:ru:en|Authoring a Model Entity}} |
Revision as of 03:40, 2 September 2006
После создания логической энтити в предыдущем примере, теперь создадим энтить которая может двигаться, создавать коллизии с остальными объектами, и которая имеет визуальную компоненту (в данном случае, модель). В этом примере мы создадим энтить которая отображается используя модель, и перемещаются по миру случайным образом.
Создаем CPP файл для новой энтити
- Создаем файл называемый
sdk_modelentity.cpp
. Этот файл должен быть внутри пакпки dlls которая находить в папке с вашим исходным кодом. Например, если вы установили код вC:\MyMod\src
, тогда вы должны создать файл называемыйC:\MyMod\src\dlls\sdk_logicalentity.cpp
. - Далее копируем этот код и вставляем его в новый файл.
- В последнею очередь добавляем этот файл в ваш проект server.dll. Если вы открыли
game_sdk.sln
solution, тогда вы можете щелкнуть правой кнопкой на проекте hl в окне Solution Explorer и выбрать Add, затем Add Existing Item.
Рассмотрение кода
Определение класса
class CMyModelEntity : public CBaseAnimating { public: DECLARE_CLASS( CMyModelEntity, CBaseAnimating ); DECLARE_DATADESC(); void Spawn( void ); void Precache( void ); void MoveThink( void ); // Input function void InputToggle( inputdata_t &inputData ); private: bool m_bActive; float m_flNextChangeTime; };
Мы наследуем нашу энтить от класса CBaseAnimating
. Это позволяет использовать модели и анимацию. Также новыми для этой энтити являются функции Spawn()
и Precache()
.
Определяем описание данных для данного класса
LINK_ENTITY_TO_CLASS( my_model_entity, CMyModelEntity ); //Начинаем описание наших данных для этого класса BEGIN_DATADESC( CMyModelEntity ) // Сохраняем/востанавливаем ваше состояние активности DEFINE_FIELD( m_bActive, FIELD_BOOLEAN ), DEFINE_FIELD( m_flNextChangeTime, FIELD_TIME ), // Связываем имя нашего input из Hammer с нашей input function DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ), // Объявляет think функцию DEFINE_THINKFUNC( MoveThink ), END_DATADESC()
Подобно нашей логической энтити, мы должны объявить переменные используемые энтитью так чтоб движок знал их смысл. Важно отметить что функция MoveThink()
должна быть объявлена как энтить с think-функцией таблице описания данных используя макрос DEFINE_THINKFUNC
. Смотрите таблицу описания данных для дополнительной информации.
Создаем Precache() функцию
#define ENTITY_MODEL "models/gibs/airboat_broken_engine.mdl" void CMyModelEntity::Precache( void ) { PrecacheModel( ENTITY_MODEL ); }
Precache()
функция выполняет кеширование всех нужных файлов. Для дополнительной информации по теме смотрите кеширование файлов. Здесь мы также определяем модель которая будет использоваться для отображения энтити в мире.
В данном примере мы вызываем PrecacheModel()
для кеширование нашей модели. Без этого шага, модель энтити не появиться в мире и движок будет жаловаться на отсутствующее кэширование.
Создаем Spawn() функцию
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; }
Функция Spawn()
вызывается после создания энтити. Эта функция может считаться игровым конструктором энтити. Здесь энтить может установить ее начальное состояние, включая то что модель использует, ее способы движения и твердость. Важно отметить что функция Spawn()
вызывается немедленно после размещения энтити в памяти и поскольку это происходит в самом начале карты, нет гарантии что все остальные энтити к этому моменту были успешно созданы. В связи с этим, любой код связывающий данную энтить с поиском или связью с другими именованными энтитями должен производиться в функции Activate()
данной энтити. Функция Activate()
вызывается когда все энтити создались и произвели запуски их Spawn() функций. Поиск энтитей перед функцией Activate() зависит от порядка создания энтитей и является ненадежным.
В приведенном ниже примере, сначала вызывается функция Precache()
для того чтобы удостовериться что все файлы были корректно кэшированы. После чего, используется функцияSetModel()
для установки модели определенной до этого.
Далее, устанавливается твердость энтити с помощью функции SetSolid()
. Здесь доступны несколько допустимых типов твердости:
SOLID_NOT |
Отсутствует. |
SOLID_BSP |
Использует BSP дерево для определения твердости (используется для браш-моделей) |
SOLID_BBOX |
Использует ограничительный бокс углового центрирования. |
SOLID_CUSTOM |
Энтить определяет ее сеобственные функции для проверки колизий. |
SOLID_VPHYSICS |
Использует объект vcollide для проверки коллизий. |
В данном примере, мы создаем энтить использующую ограничительный бокс. Функция UTIL_SetSize()
позволяет установить размер ограничительного бокса. Здесь мы устанавливаем куб размером 40x40x40.
Создаем MoveThink() функцию
Энтити способны обновлять внутренее состояние и принимать решения с помощью функции think, которая вызывается с частотой указанной энтитью. Ниже мы создаем think-функцию которая вызывается 20 раз в секунду. Эта функции используется для случайного обновления передвижения и направления в мире.
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 ); }
Хотя много кода написано в этой функции, но её действие очень просто описывается: как только проходит случайный интервал времени, энтить выбирает новое, случайное направление и скорость для путешествия. Она также обновляет угл направления лица к направлению его путешествия.
Вызов SetNextThink()
важен для этой функции, потому что он говорит энтити когда вследующий раз думать. Здесь устанавливается думать снова через 1/20-ую секунды в будущем. Большинству энтитям только нужно думать с частотой 1/10 секунды, взависимости от их поведения. Важно заметить необновив следующее время срабатывание функции приведет к тому что энтить перестает думать (что иногда желательно).
Создаем InputToggle() функцию
Для данной энтити мы используем ввод(input) для переключения ее передвижения как включенного/выключенного. Для этого, мы объявляем input-функцию подобной из предыдущего урока.
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; } }
Для начала "работы" энтити используется функция SetThink()
в соединении с функцией SetNextThink()
. Она сообщает энтити использовать функцию MoveThink()
и вызовется через 1/20 секунды в будущем. Важно отметить что энтить может иметь любое количество think-функций и использовать SetThink()
функцию для выбора между ними. Каждая энтить может иметь несколько think-функций выполняющихся в одно и то же время используя SetContextThink()
скрытый в другом документе.
Также мы определяем тип движения энтити MOVETYPE_FLY
. Это позволяет энтити двигаться в заданном направлении без гравитации.
Во второй части энтити этой функции мы останавливаем энтить от движения. think-функция устанавливается в NULL
для остановки think-процесса. Её тип движения также устанавливается MOVETYPE_NONE
чтобы удержать его от движения.
Создание FGD записи
Для использования энтити в Хаммере, нам нужно создать запись в нашем FGD файле. Хаммер будет использовать эти данные для того чтобы понять различные ключевые значения и функции которые предоставляет энтитя. Смотрите документ FGD формата для дополнительной информации о FGD файлах.
Запись FGD энтити легко отображает модель в хамере и позволяет отправлят input "Toggle" ему.
@PointClass base(Targetname) studio("models/gibs/airboat_broken_engine.mdl")= my_model_entity : "Tutorial model entity." [ input Toggle(void) : "Toggle movement." ]
Если ваш .FGD не пустой, убедитесь что добавили строку @include "base.fgd"
, которая даст вам некоторые нужные функции Хаммера. (Это соответствует полному преобразованию. Для мода основанного на существующем содержимом, включайте подходящие FGD вместо базового; к примеру, для модов HL2, включите halflife2.fgd
вместо base.fgd
.)