Source Engine никогда не постареет. Во всяком случае умирать он еще не собирается.
В предыдущей части урока мы научились базовой работе с VPC и печати сообщений в консоль разработчика.
В этой части урока мы разберем систему энтити, научимся создавать классы и создадим нашу первую логическую сущность.
Опять термины
Сущность или Энтити(entity) — основной объект на уровне.
Система I/O — система, предназначенная для "общения" сущностей друг с другом.
Инпут(input) — команда, меняющая поведение сущности. Бывает вызвана игроком через консоль или аутпутом.
Аутпут(output) — событие, вызываемое при изменении состояния сущности.
А вообще, как это работает?
Любой уровень в Source — набор сущностей.
На каждом уровне присутствует как минимум одна сущность, называемая worldspawn
. Эта сущность по факту — весь "твердый" мир, а именно:
- Примитивы a.k.a. браши — кубы, шары, арки, etc.
- Так называемые displacements (диспы,
диспенсеры) — примитивы на стероидах, позволяющие создавать более детализированные ландшафты или (Новые карты в CS:GO используют это!) здания. Не поддаются оптимизации, а поэтому желательно прикрывать их "снизу" примитивами. - Статичные модели (
prop_static
). В отличие от тех жеprop_dynamic
, сущностями как таковыми не являются.
Остальные же сущности (включая игроков!) имеют свои собственные свойства и поведение.
Все сущности можно разделить вот так:
- Точечные — это такие сущности, которые расположены в мире в определенной точке.
- Брашевые — это такие сущности, которые состоят из примитивов.
ВАЖНО/Hammer: Не превращайте диспы в брашевые сущности!!!
Логическая энтити
Логические сущности — самые простые из всех, так как не имеют визуального компонента и коллизии. Самые простые и самые полезные!
Например, сущность logic_auto
через несколько аутпутов обрабатывает события запуска карты в различных режимах.
logic_5 — код
Давайте создадим простую сущность, которая при каждом пятом вызове инпута будет печатать цветное сообщение в консоль.
-
В проекте серверной части игры создайте файл с названием
logic_5.cpp
.
То есть, файл будет лежать по пути:src/game/server/logic_5.cpp
. -
Включите необходимые заголовки в наш файл:
// cbase.h - прекомпилированный заголовок. // Он включает в себя всё необходимое для базового программирования под сурс. #include "cbase.h" // memdbgon.h - заголовок с переопределениями операторов new и delete // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h"
-
Создайте класс
CLogicFive
наследующийCLogicEntity
:class CLogicFive : public CLogicEntity { DECLARE_CLASS( CLogicFive, CLogicEntity ); public: // ... private: // ... };
Погодите-ка! Что за DECLARE_CLASS()? Это специальный макрос, предназначенный для облегчения работы при множественном наследовании. Он определяет два типа —
ThisClass
для текущего класса иBaseClass
для базового класса (этот тип мы кстати видели в предыдущей части урока…). -
Добавьте определения под
public
:public: DECLARE_DATADESC(); void Input_Tick( inputdata_t &id );
Ну и что есть что?
DECLARE_DATADESC()
это макрос, объявляющий таблицу метаданных класса для движка.void Input_Tick( inputdata_t &id )
это функция, которая будет являть собой инпутtick
.
-
Добавьте счетчик тиков под
private
:private: int m_iTicks = 0;
-
Теперь нам необходимо как бы "прибить гвоздями" наш класс к имени сущности
logic_5
.
И в этом нам поможет (еще один!) макрос —LINK_ENTITY_TO_CLASS()
!
Добавляем его сразу после объявления класса:// ... int m_iTicks = 0; }; LINK_ENTITY_TO_CLASS( logic_5, CLogicFive );
-
Теперь нам необходимо определить таблицу метаданных, объявленную в шаге 4:
BEGIN_DATADESC( CLogicFive ) DEFINE_FIELD( m_iTicks, FIELD_INTEGER ), // наш счетчик тиков DEFINE_INPUTFUNC( FIELD_VOID, "tick", Input_Tick ), // наш инпут END_DATADESC();
BEGIN_DATADESC()
— макрос, раскрывающийся в начало таблицы метаданных для класса.DEFINE_FIELD()
— макрос, создающий в таблице поле. Любое поле, добавленное этим макросом в таблицу будет иметь своё место в файлах сохранения!DEFINE_INPUTFUNC()
— макрос, определяющий инпут. В нашем случае он ничего не возвращает (FIELD_VOID
), называетсяtick
и ссылается на методInput_Tick
.END_DATADESC()
— макрос, раскрывающийся в конец таблицы метаданных.
-
Из необходимого остается только реализовать метод
Input_Tick
:// обработчик инпута tick() void CLogicFive::Input_Tick( inputdata_t &id ) { m_iTicks++; if( m_iTicks % 5 == 0 ) // если новое количество тиков делится на пять, напечатать цветное сообщение! ConColorMsg( Color( 255, 255, 0 ), "logic_five: Another fifth tick!\n" ); }
-
[НЕОБЯЗАТЕЛЬНО] Добавьте наш файл в VPC скрипт:
// src/game/server/server_episodic.vpc // где-то внутри $Folder "Source Files" $File "$SRCDIR/game/server/logic_5.cpp
Затем, разумеется, перегенерируйте решение.
logic_5 — в игре
- Запустите игру и любую карту (
sdk_vehicles
илиdm_lockdown
, например) - Создайте нашу сущность консольной командой:
ent_create logic_5
- Пять раз вызовите инпут
tick
консольной командой:
ent_fire logic_5 tick
- После пятого вызова в консоли должно появиться желтое (или любого другого цвета если вы его поменяли) сообщение!
Заключение
Чему мы научились?
[Я надеюсь, что] из этой части урока вы узнали:
- Что такое сущности и каких видов они бывают
- Что такое система ввода-вывода у сущностей
- Как создавать свои логические сущности
Что будет дальше?
В третьей части я расскажу о основах редактора Valve Hammer Editor и структуре FGD файлов.
Это будет необходимо, так как частью позже я буду дополнять этот урок, добавляя нашей сущности вместо консольного сообщения аутпут.
Полезные ссылки
- Код из туториала
- Статья той же категории на VDC (Если честно, я даже кусок текста оттуда выдрал :D)
- Valve Developer Community и его раздел про SSDK
- Мой мод [SP] с многочисленными фиксами
ссылка на оригинал статьи https://habr.com/ru/post/511032/
Добавить комментарий