HUD элемент с обработкой сообщений из собственной энтити
В данном учебнике будет рассмотрен процесс создания собственного HUD элемента для вывода простого текстового сообщения.
Сообщение будет отправлятся при помощи простой энтити на стороне сервера при помощи HUD-сообщения.
Также будет создана консольная переменная и комманда отвечающая за отображение элемента и присвоена новая клавиша для включения/выключения отображения данного элемента.
1. Создаем класс на стороне клиента
Для начала определимся с названием HUD элемента — пусть для данного учебника он будет HudMyTest, при создании собственного класса следуя общепринятой логике называем его добавляя букву C.
Создаем новый файл HudMyTest.cpp:
//Класс HUD элемента HudMyTest

#include «cbase.h»
#include «hud.h»
#include «hudelement.h»
#include «hud_macros.h»

#include <vgui_controls/Panel.h>
#include <vgui_controls/Frame.h>
#include <vgui/IScheme.h>
#include <vgui_controls/Label.h>
#include «iclientmode.h»

using namespace vgui;

// memdbgon must be the last include file in a .cpp file!!!
#include «tier0/memdbgon.h»

//Объявление класса
class CHudMyTest: public CHudElement, public vgui::Panel
{
DECLARE_CLASS_SIMPLE (CHudMyTest, vgui::Panel);
public:
CHudMyTest (const char *pElementName); //конструктор
void Init (void); //вызывается сразу после создания элемента
void VidInit (void); //тоже что и Init только вызывается один раз при загрузке карты
void Reset (); //вызывается при сбросе HUD
void Paint (void); //данный метод вызывается в каждом фрейме, для отрисовки элемента на экране
void OnThink (void); //также вызывается в каждом фрейме, для обновления информации
void MsgFunc_MyTxtMessage (bf_read &msg);
private:
vgui::Label *m_pTxtLabel; //Ярлык с названием элемента
vgui::HScheme scheme; //Объект схемы для использования информации из схем
char m_pText[1024];
//C_BasePlayer *player; //указатель на объект игрока
};

//Регистрация класса для HUD элемента
DECLARE_HUDELEMENT (CHudMyTest);
//Регистрация приемника сообщений
DECLARE_HUD_MESSAGE (CHudMyTest, MyTxtMessage);

//Имплементация конструктора
CHudMyTest::CHudMyTest (const char *pElementName): CHudElement (pElementName), vgui::Panel (NULL, «HudMyTest»)
{
//Установка бита отображения
SetHiddenBits (HIDEHUD_ALL);
//можно использовать комбинацию задающую условие при котором будет видимым наш элемент,
//например: HIDEHUD_NEEDSUIT | HIDEHUD_PLAYERDEAD устанавливает невидимость в случае отсутствия HEV-костюма и смерти игрока

//Загрузка и применение схемы для данного элемента
scheme = vgui::scheme ()→LoadSchemeFromFile («resource/ClientScheme.res», «ClientScheme»);
SetScheme (scheme);

//Установка родителя в иерархии экрана
vgui::Panel *pParent = g_pClientMode→GetViewport ();
SetParent (pParent);

//Создание ярлыка для отображения текста
m_pTxtLabel = vgui::SETUP_PANEL (new vgui::Label (this,"NameLabel»,»));

//Применение схемы к ярлыку
m_pTxtLabel→SetScheme (scheme);
//установка шрифта
m_pTxtLabel→SetFont (vgui::scheme ()→GetIScheme (scheme)→GetFont («Default»));

//Не использовать ввод с клавиатуры и мыши
m_pTxtLabel→SetKeyBoardInputEnabled (false);
m_pTxtLabel→SetMouseInputEnabled (false);

//Установка расположения и размера
m_pTxtLabel→SetPos (0,0);
m_pTxtLabel→SetSize (GetWide (), GetTall ());

//Не отображать фон и рамку
m_pTxtLabel→SetPaintBackgroundEnabled (false);
m_pTxtLabel→SetPaintBorderEnabled (false);

//Установка выравнивания текста, a_northwest означает влево-вверх
m_pTxtLabel→SetContentAlignment (vgui::Label::a_northwest);

//Прозрачный фон
SetPaintBackgroundEnabled (false);
SetBgColor (Color (0,0,0,0));
m_pTxtLabel→SetBgColor (Color (0,0,0,0));
}

//Имплементация других методов

void CHudMyTest::Init (void)
{
//Устанавливаем перехват сообщений
HOOK_HUD_MESSAGE (CHudMyTest, MyTxtMessage);
Reset ();
}

void CHudMyTest::VidInit (void)
{
Reset ();
}

void CHudMyTest::Reset (void)
{
//стираем содержимое текста
sprintf (m_pText, «Empty»);
}

void CHudMyTest::Paint (void)
{
//определяем требуется ли отображать элемент
ConVar *is_vis = cvar→FindVar («myhud_visible»);
if (!is_vis→GetBool ()) return;
//записать текст
m_pTxtLabel→SetText (m_pText);
//сделать видимым
m_pTxtLabel→SetVisible (true);
//реорганизовать размеры к новому тексту
m_pTxtLabel→SizeToContents ();
m_pTxtLabel→SetSize (GetWide (), GetTall ());
//установить цвет
m_pTxtLabel→SetFgColor (Color (255,255,240,255));
}

void CHudMyTest::OnThink (void)
{
//определяем требуется ли изменить видимость элемента
ConVar *is_vis = cvar→FindVar («myhud_visible»);
if (is_vis→GetBool ()) SetVisible (true);
else SetVisible (false);
}

void CHudMyTest::MsgFunc_MyTxtMessage (bf_read &msg)

{
sprintf (m_pText, msg. ReadAndAllocateString ());
}


//Создаем консольную переменную на стороне клиента для управления видимостью элемента
ConVar myhud_visible («myhud_visible», «0», FCVAR_NONE, «HudMyTest visibility», true, 0, true, 1);

//Создаем консольную комманду на стороне клиента для переключения видимости элемента
void CC_myhud_visible (void)
{
ConVar *is_vis = cvar→FindVar («myhud_visible»);
if (is_vis→GetBool ())
engine→ClientCmd («myhud_visible 0»);
else
engine→ClientCmd («myhud_visible 1»);
}
static ConCommand myhud («myhud», CC_myhud_visible, «parameter»);
Подключаем файл к проекту клиента client. 2. Редактируем scripts/HudLayout.res
В файле HudLayout.res (в директории scripts вашего мода) добавляем новую секцию с описанием нашего элемента
HudMyTest
{
«fieldName» «HudMyTest»
«visible» «1»
«enabled» «1»
«xpos» «15»
«ypos» «200»
«wide» «150»
«tall» «150»
«PaintBackgroundType» «0»
}
Если в директории scripts вашего мода нет файла HudLayout.res, вытащите его из source engine.gcf 3. Привязываем комманду к клавише
В файлах cfg/config.cfg и cfg/default_config.cfg добавте комманду
bind «TAB» «myhud»
Если таких файлов нет, вытащите из source engine.gcf. 4. Создаем класс энтити для сообщения Создадим файл MyTxtMessage.cpp и поместим в него класс CMyTxtMessage который будет отвечать за экземпляр энтити на сервере для отправки сообщения на HUD:
//Класс CMyTxtMessage
#include «cbase.h»

// memdbgon must be the last include file in a .cpp file!!!
#include «tier0/memdbgon.h»

//объявляем класс
class CMyTxtMessage: public CLogicalEntity
{
public:
DECLARE_CLASS (CMyTxtMessage, CLogicalEntity);
DECLARE_DATADESC ();
CMyTxtMessage (void) {};
//Input-функция для передачи данных (вызывается при помощи каких-нибудь output на карте)
void InputSendMessage (inputdata_t &data);
//Текстовая переменная
string_t m_strText; };

//объявление данных энтити в таблице данных движка
BEGIN_DATADESC (CMyTxtMessage)

DEFINE_KEYFIELD (m_strText, FIELD_STRING, «text»),

DEFINE_INPUTFUNC (FIELD_STRING, «SendMessage», InputSendMessage),

END_DATADESC ()

void CMyTxtMessage::InputSendMessage (inputdata_t &data)
{
//Мы хотим отправлять сообщение локальному игроку
CSingleUserRecipientFilter user (UTIL_PlayerByIndex (1));
user. MakeReliable ();

//Начало блока сообщения
UserMessageBegin (user, «MyTxtMessage»);

//Отправка текста клиенту
WRITE_STRING (STRING (m_strText));

//Конец блока сообщения
MessageEnd ();
}

//Связываем имя энтити для Hammer с классом энтити
LINK_ENTITY_TO_CLASS (my_txt_message, CMyTxtMessage);
Добавляем файл в проект сервера hl.
Теперь следует зарегистрировать HUD сообщение.
Для этого потребуется внести изменения в файлы client/usermessages.cpp и shared/hl2_usermessages.cpp добавим в обоих функциях RegisterUserMessages регистрацию сообщения «MyTxtMessage»
Должно получиться так:
void RegisterUserMessages (void)
{
usermessages→Register («Geiger», 1);
usermessages→Register («Train», 1);
usermessages→Register («HudText», -1);



usermessages→Register («TextMsg», -1);
}
Следует обратить внимание что регистрация сообщения производится как на сервере (shared\hl2_usermessages.cpp) так и на клиенте (client\usermessages.cpp)
5. Создаем запись для энтити в .FGD файле
Для того чтоб можно было добавить энтить на карте создаем запись в FGD файле вашего мода:
@PointClass base (Targetname) size (-8 -8 -8, 8 8 8) = my_txt_message: «My text message entity»
[
text (string): «Value»: «Hello mod»: «Message value»
input SendMessage (void): «Input Action»
output OnMessage (void): «Output Action»
]
Eсли у вас используется FGD от Half-Life 2, создайте новый пустой текстовый файл с расширением FGD куда поместите данную запись, затем подключите этот файл с помощью опции меню настройки текущего проекта в Hammer. 6. Размещаем энтити на карте
Если правильно была создана запись в FGD файле, теперь можно добавить на карту новые энтити через инструмент добавления точечных энтитей в Hammer.
Добавляем две энтити my_txt_message и в поле Name пишем разные имена — Mymsg1 и Mymsg2, затем создаем два триггера trigger_multiple и также называем по разному — Trig1 и Trig2, и не забудть закрасить триггеры текстурой tools/toolstrigger.
Должно плучиться нечто похожее на этот рисунок:
image1
В поле Value у Mymsg1 пишем текст «Hello from First!»:
image2
А для Mymsg2 пишем «Hello from Second!»
Далее выбираем первый триггер Trig1 и устанавливаем в закладке Outputs связь с Mymsg1, так чтоб триггер реагировал на касание игрока, посилая output триггера в input энтити, как иллюстрирует рисунок ниже:
image3
То же самое проделываем с второй парой Trig2 и Mymsg2
7. Финальные шаги
Компилируем DLL-ы client и server в Visual Studio (меню Build->Build Solution) и компилируем карту где мы размещали энтити.
Запускаем мод, запускаем данную карту, при нажатии клавиши TAB должно переключаться отображение нового HUD элемента с надписью «Empty».
Подходим к первому месту где мы установили триггер связанный с первой энтитью (Mymsg1), как только сработает триггер увидем сменившуюся надпись «Hello from First!», теперь подходим к труггому тригеру, видим новую надпись «Hello from Second!».
Дальше вы уже самостоятельно сможите наращивать функциональность для подобных серверных энтитей и добавлять в интерфейс мода собственные элементы модифицировав под свои потребности.
Автор: DarkLight.
21 июля 2005, 19:07