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 );
}
Следует обратить внимание что регистрация сообщения производится как на сервере (
sharedhl2_usermessages.cpp)
так и на клиенте (
clientusermessages.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.
Далее выбираем первый триггер
Trig1 и устанавливаем в закладке Outputs связь с
Mymsg1, так чтоб триггер реагировал на касание игрока, посилая output триггера в input энтити, как иллюстрирует рисунок ниже:
То же самое проделываем с второй парой
Trig2 и
Mymsg2
7. Финальные шаги
Компилируем DLL-ы client и server в Visual Studio (меню Build->Build Solution) и компилируем карту где мы размещали энтити.
Запускаем мод, запускаем данную карту, при нажатии клавиши
TAB должно переключаться отображение нового HUD элемента с надписью "Empty".
Подходим к первому месту где мы установили триггер связанный с первой энтитью (
Mymsg1),
как только сработает триггер увидем сменившуюся надпись "Hello from
First!", теперь подходим к труггому тригеру, видим новую надпись "Hello
from Second!".
Дальше вы уже самостоятельно сможите наращивать функциональность для
подобных серверных энтитей и добавлять в интерфейс мода собственные
элементы модифицировав под свои потребности.
Автор: DarkLight