HUD Элементы

From Valve Developer Community
Jump to: navigation, search
Underlinked - Logo.png
This article needs more links to other articles to help integrate it into the encyclopedia. Please help improve this article by adding links that are relevant to the context within the existing text.
January 2024
English (en)русский (ru)
... Icon-Important.png

Часто в играх очень важным является передача информации игроку используя HUD (навигационный дисплей). Часто здесь отображается здоровье игрока, количество боеприпасов, или сообщение о текущей задаче. Обычно HUD содержит несколько различных элементов. Здесь будет описано как создавать эти элементы и использовать их для отображения информации пользователю.

Введение

HUD элементы используют библиотеку VGUI2 для рендеринга их состояния. Это позволяет им не только выглядеть и быть похожими на остальные VGUI элементам в игре, но также позволяет им использовать скриптовые, анимированные компоненты, значительно увеличивая их визуальное качество. Это требует наличия двух компонент на стороне клиента: объявление в коде и скриптовые файлы которые доступны клиенту для выполнения, скрипты - это файлы не входящие в код клиента.

Классы HUD элементов наследуются от базового класса CHudElement. Этот базовый класс работает с обновлением, отрисовкой и скрытием HUD элементов основанных на определенном игровом состоянии (HUD элемент может быть установлен или исчезнуть когда игрок умирает). Этот файл также интерпретирует файл HudLayout.res в папке /scripts вашего мода для определения позиций и поведений элементов. Большинсво элементов наследуются от базового класса vgui::Panel. Он предоставляет им примитивные панели на которых можно отрисовывать текст, формы или текстуры. Для более детальной информации по классу vgui::Panel, обратитесь к документации по VGUI2 предоставленной в данном SDK.

HUD Сообщения

Элементы используют простую систему для захвата сообщений отправленных из сервера. HUD элементы объявляют callback-функцию и связывают с ней соответствующее сообщение. Как только сообщение получено, callback-функция обычно читает какоето количество информации из сообщения и отображают или обновляют их визуальное состояние. К примеру - сообщение Damage отсылается сервером когда игрок получает повреждение. Сообщение кодируется количеством повреждения и расположением. HUD элемент Health получает сообщение и проигрывает анимации также выдавая ее числовое значение для отображения нового количества здоровья игрока.

Обработчик сообщения объявляется в HUD элементе следующим макросом:

DECLARE_HUD_MESSAGE( CMyHUDClass, MyHUDMessage );

Первый параметр указываает класс объявляющий обработчик сообщения, второй это данное сообщение. Макрос приводит имя сообщения к функции которая должна быть описана в классе HUD элемента. Поэтому, создаваемая callback-функция должна быть такой:

void MsgFunc_MyHUDMessage( bf_read &msg );

Прототип и тело функции должны содержать данное объявление. Класс bf_read это буффер данных с различными методами запросов. Он используется для передачи неформатированных данных между сервером и клиентом. Сервер использует класс bf_write для передачи данных.

HUD элемент должен также включать определение макроса HOOK_HUD_MESSAGEобычно вызываемый функцией Init() HUD элемента. Продолжая наш пример описанный выше, объявление будет такое:

HOOK_HUD_MESSAGE( CMyHUDClass, MyHUDMessage );

Данный макрос регистрирует сообщение и связывает его с callback-функцией описанной раньше. Ошибочное включение данного объявления приведет к ошибке когда сервером будет отослано сообщение.

Отправка сообщения из сервера

Для правильного приема сообщений клиентом, они должны быть объявлены и отправлены сервером. Это совершает функция Register() в синглетон-классе usermessages.

void CUserMessages::Register( const char *name, int size )
Эта функция создает описание сообщения и удерживает его на протяжении существования сессии. Когда сообщение отправляется, имя (name) указанное сдесь использется для идентификации сообщения как такого что было отправлено клиенту.

name

  • Текстовый идентификатор совпадающий с идентификатором описанным с помощью DECLARE_HUD_MESSAGE в HUD элементе.

size

  • Размер в байтах сообщения планируемого к отправке.
    Note.pngNote:Значение -1 подразумевается как размер переменной или неизвестно

Все сообщения должны быть объявлены в глобальной функции RegisterUserMessages(). Эта функция вызывается во время создания синглетон-класса. Не объявленные сообщения не будут удачно приняты клиентом и могут вызвать ошибку в случае попытки такой отправки.

Если были соблюдены все шаги, HUD элемент должен иметь работающую инфраструктуру для отправки и приема сообщений от сервера к клиенту. Для отправки сообщения, используются функции UserMessageBegin(), MessageEnd(), и другие поддерживаемые макросы описанные ниже.

Функция UserMessageBegin() определена как:

void UserMessageBegin( IRecipientFilter& filter, const char *messagename )
Эта функция создает пользовательское сообщение данного типа по имени (name), и приготавливается к получению данных от пользователя. Фильтр (filter) может быть любого типа IRecipientFilter type (CSingleUserRecipientFilter, CBroadcastRecipientFilter, и т.д.) как описано в ../dlls/recipientfilter.h.

filter

  • Фильтр отправки сообщения правильным получателям.

messagename

  • Идентификатор для данного сообщения (какой был зарегистрирован до этого).

Следующие макросы предоставляют функциональность для записи данных в поток отправляемый клиенту. Они должны быть приняты и обработаны в порядке отправления. Макросы записываются так:

...

WRITE_BYTE( m_uchMyByte );
WRITE_VEC3COORD( m_vecMyOrigin );
WRITE_BOOL( m_bMyState );

...

Ниже приводится описание всех доступных макросов для отправки данных в поток:

WRITE_BYTE Один байт
WRITE_CHAR Один символ
WRITE_SHORT Одно короткое целое (short)
WRITE_WORD Одно слово (два байта)
WRITE_LONG Одно длинное целое
WRITE_FLOAT Одно с плавающей запятой
WRITE_ANGLE Беззнаковй 8-битный угол
WRITE_COORD Сжатое значение координат
WRITE_VEC3COORD Сжатое значение координат из типа Vector
WRITE_VEC3NORMAL Сжатое значение нормали из типа Vector
WRITE_ANGLES Сжатое угловое значение из типа Vector
WRITE_STRING Строка символов
WRITE_ENTITY Индекс энтити (короткое целое, short)
WRITE_BOOL Один бит (булевое значение)
WRITE_UBITLONG Значение беззнаковый длинный бит
WRITE_SBITLONG Значение знаковый длинный бит
WRITE_BITS Несколько битовых значений, которое передаются как параметр

За WRITE_ макросом, сообщение должно быть завершено функцией MessageEnd().

Получение сообщения клиентом

Как только сообщение было отправлено сервером, клиент принимает его через callback-функцию закрепленной за этим сообщением. Принимающей callback-функции передается переменная класса bf_read которая содержит данные полученные из сервера. Класс содержит специальные функции для чтения форматированных данных из потока. И опять же, данные должны быть считаны в том порядке в котором отправлялись.

Теперь, когда данные отправлены и получены между клиентом и сервером, функции отрисовки (как описано в документе по VGUI2) могут быть использованы для отрисовки любой информации которая будет нужна на основании полученных данных.

Чтобы поймать это сообщение на клиентской стороне вы должны обработать его в нем, добавление обработки сообщения требует чтобы экземпляр вашего класса не был уничтожен.

class CHudThingy : public CHudElement , public vgui::Panel
{

	DECLARE_CLASS_SIMPLE( CHudThingy, vgui::Panel ); // ЭТО ВАЖНО
	....
	void	MsgFunc_SayText(bf_read &msg) { // Делаем что-нибудь с сообщением};
}

DECLARE_HUD_MESSAGE( CHudThingy, SayText );
// Инициализиреум дополнительный чат
void CHudAdvancedChat::Init( void )
{
	...
	HOOK_HUD_MESSAGE( CHudThingy, SayText );
}

Код примера

Пример HUD элемента может быть найден в следующих файлах, поставляемых с примером приложения:

../cl_dll/sdk/sdk_hud_message.cpp

../dlls/sdk/sdk_env_message.cpp

../game_shared/sdk/sdk_usermessages.cpp

Отображение пользовательских сообщений в игре (кодирование серверных плагинов)

В этом случае эта функция может быть добавлена в ваш проект, она полностью снабжена коментариями.

void  YourPlugin::SayTextMsg(int PlayerIndexN, char const *Message)
{
	MRecipientFilter filter;
	if(PlayerIndexN == 0)
	{
		filter.AddAllPlayers(MaxClients); // мы бирем maxclients из ServerActivate Void
	}
	else
	{
		filter.AddRecipient(PlayerIndexN);//добавления игрока
	}

	bf_write *pWrite=engine->UserMessageBegin(&filter, 3);//3 для Say_Text

	if( !pWrite )
	{
		//TODO: Действие производимое когда что-то идет нетак
	}
	else
	{
		pWrite->WriteByte(PlayerIndexN);// Индекс игроков, чтобы отправить глобальное сообщение серверу сделайте его 0
		pWrite->WriteString(Message);//само сообщение
		pWrite->WriteByte(0);//0 для фразы, 1 для игнорирования
		engine->MessageEnd();//закончим
	}
} 

Использование:

void YourPlugin::ClientCommand(edict_t *pEntity)
{
	const char *pcmd = m_Engine->Cmd_Argv(0); 
	if ( !pEntity || pEntity->IsFree() ) 
	{
		//TODO
	}
	if ( FStrEq( pcmd, "ClientMsg" ) )
	{
		SayTextMsg( engine->IndexOfEdict(pEntity), "Hello World!")// только человек кто ввел команду видит это!
	}
	else if ( FStrEq( pcmd, "SayServer" ) )
	{	
		SayTextMsg( 0, "Hello World!")// все в игре видят это:)
	}

...

У вас должен быть модифицированный RecipientFilter, пожалуйста смотрите здесь для дополнительной информации.