Вторник, 26.01.2021, 06:27

logo

Пользовательский поиск

Меню сайта
Категории раздела
Разное [15]
Tutorials
Создание карт [13]
Создание моделей [2]
Кодинг [14]
Создание карт CS [197]
Учебник cs-mapper
Свойства entity HL-CS [117]
Форма входа
Логин:
Пароль:
Наш сервер CS 1.6
Поиск
Наш опрос
Ваш возраст
Всего ответов: 229
Атмосфера
Друзья сайта


Главная » Статьи » HL Development » Кодинг


Изменение скина у модели оружия

Изменение скина у модели оружия

Если вы играли в HL:Invasion, то наверное заметили, что некоторые пушки там имеют интересные свойства.
Например экранчик у ракетницы при наводе на цель сменяет надпись с "No target" на "Locking in progress", а затем и вовсе на "Target locked". А так называемый "supergun" при выстрелах постепенно меняет свой цилиндр со светло-синего на ярко желтый. Как вы уже наверное догадались, это достигается сменой скинов у модели оружия. Умело используя эту фишку можно добиться очень интересных и впечатляющих эффектов. И я уверен, многие начинающие кодеры хотели бы ее заюзать.

Ну что же давайте попробуем это сделать. Как все знают смена боди достигается простой вставкой строчки:

 
    pev->body = 1;

 


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

 
    pev->skin = 1;

 


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

Итак, приступим.

Менять скин мы будем в клиенте, поскольку на сервере это сделать не получиться.

Для того чтобы поменять скин клиент должен собсно знать номер скина, а следовательно, он должен как-то получить эту информацию.
Для передачи информации в клиент у нас есть два способа - EVENT и MESSAGE. На ум сразу приходит, что сделать передачу эвентом намного проще - задекларировал эвент, прекешил его и передал - всего навсего три строчки на сервере. Да и принять его на клиенте - пара пустяков - пропишем его в hl_events.cpp и в ev_hldm.cpp и готово. Но эвент, передает кучу бесполезной информации - свое имя, положение игрока, флаги. А нам-то всего навсего надо передать один-единственный байтик - номер скина. Поэтому я решил остановиться на варианте с MESSAGE.

1.Подготовка MESSAGE на сервере.

Как известно MESSAGE (сообщение) для начала нужно задекларировать, для вызова из других функций. Для этого откроем player.h и добавим туда строчку нашего мессаджа, где нибудь в самом конце.

 

extern int    gmsgSetSkin;

 


Теперь нам нужно создать сам мессадж - откроем player.cpp и найдем строчку LinkUserMessages и чуть выше добавим:

 

int gmsgSetSkin = 0;

 


Теперь опустимся в саму функцию LinkUserMessages и в самом ее конце, перед закрывающей скобкой зарегистриуем наше сообщение.

 

    gmsgSetSkin = REG_USER_MSG("SetSkin", 1);

 


Теперь клиент готов к приему нашего мессаджа :)

2.Прием MESSAGE на клиенте.

Для начала стоит сказать, что мессаджи инициализируются вместе с худом, следовательно большую часть работы нам предстоит проделать именно в hud.cpp. Но сперва мессагу, равно как и ее переменную нужно задекларировать. Откроем hud.h и в объявлении класса CHUD, в секции public: добавим новую переменную


    int m_iSkin;

 


Теперь спустимся по файлу до комментария // user messages и добавим туда еще одну мессагу.



    void _cdecl MsgFunc_SetSkin( const char *pszName, int iSize, void *pbuf );

 


Это перед комментом // Screen information.
Теперь нам собсно нужно активировать сообщение при его приеме. Добавьте в файл hud.cpp эту функцию (к остальным мессаджам, хотя положение этой функции в файле не имеет значения).


int __MsgFunc_SetSkin(const char *pszName, int iSize, void *pbuf)
{
    gHUD.MsgFunc_SetSkin( pszName, iSize, pbuf );
    return 1;
}

 


Ну и осталось задекларировать сообщение на клиенте - чтобы клиент знал, что оно существует и мог его корректно принять. Найдите в hud.cpp функцию void CHud :: Init( void ) и добавьте там вот эту строчку.


    HOOK_MESSAGE( SetSkin );

 


Ну вот собсно и все - наш мессадж полностью настроен и готов к передаче\приему информации :)

3.Команда смены скина на сервере.

Чтобы не изобретать лишний раз велосипед, давайте так и оставим pev->skin для смены скина - главное его достоинство, то что он входит в структуру entvars_t и для его сохранения нам не нужно ничего делать - он сохраниться автоматически (ведь вы же не хотите, чтобы ваш скин пропадал при save\load). Теперь давайте подумаем - откуда удобнее всего послать наш мессадж ? Из SendWeapponAnim ? Но скин - это вам не боди и его порой нужно изменять независимо от анимации - а иногда и вовсе, когда анимация стоит на месте. А какая функция у оружия все время вызвается ? правильно - WeaponIdle. Но пихать для каждого оружия три строчки мессаджа - согласитесь, это как-то муторно и неудобно. Гораздо удобнее просто использовать для этого уже существующюю функцию - например ResetEmptySound - она вызвается почти в любом оружии - кроме всяких там снарков, сатчелов, гранат - ну короче, кроме тех пушек, где не нужно проигрывание звука щелчка бойка. Но ессно добавить туда эту функцию - пара пустяков, а код оружия она не повлияет.

Откроем weapons.cpp и найдем функцию CBasePlayerWeapon :: ResetEmptySound и добавим после строчки: m_iPlayEmptySound = 1; наш мессадж:


    //update weapon skin from this
    MESSAGE_BEGIN( MSG_ONE, gmsgSetSkin, NULL, m_pPlayer->pev );
        WRITE_BYTE( pev->skin );                    // weaponmodel skin.
    MESSAGE_END();

 


Теперь, чтобы сменить скин достаточно прописать в коде оружия строчку


    pev->skin = 1;

 


В любой функции, где вам это нужно. :)

4.Смена скина на клиенте.

Ну вот мы и подобрались к самому главному - собсно к смене скина на клиенте. Откроем hud_msg.cpp и в самом конце добавим следующую функцию:


void CHud :: MsgFunc_SetSkin( const char *pszName, int iSize, void *pbuf )
{
    BEGIN_READ( pbuf, iSize );//начинаем читать мессадж
    gHUD.m_iSkin = READ_BYTE();//присваиваем переменной m_iSkin значение, полученное из мессаджа
    cl_entity_s *view = gEngfuncs.GetViewModel();//Получаем "имя" текущей пушки
    view->curstate.skin = gHUD.m_iSkin;//меняем ей скин :)
}

 


В принципе переменная m_iSkin не так уж и нужна - можно обойтись и без нее, но если вы захотите проверить текущий скин, например из эвента, то она вам очень даже пригодиться ;)

На этом все. Юзайте на здоровье :)

Дополнение 1.

Если вы подобно Xwiderу озабочены тем каждым байтом, который сервер посылает клиенту, и вам не нравиться, что мессага посылается несколько сот раз в секунду (хотя я не заметил, что бы траффик вообще изменился, в моменты бездействия) - можете для успокоения совести сделать проверку на изменение скина - для того чтобы, сообщение посылалось только в момент изменения скина.

Для этого в класс CBasePlayerWeapon добавим новую переменную(в weapons.h):


int m_iLastSkin;

 


А в секции сохранения - строчку, для сохранения этой переменной в функцию

CBasePlayerWeapon::m_SaveData[] =

    DEFINE_FIELD( CBasePlayerWeapon, m_iLastSkin, FIELD_INTEGER ),

 


А саму функцию посылки мессаджа немного доработаем следующим образом:


    if(m_iLastSkin != pev->skin)
    {
        //update weapon skin from this
        MESSAGE_BEGIN( MSG_ONE, gmsgSetSkin, NULL, m_pPlayer->pev );
            WRITE_BYTE( pev->skin );    // weaponmodel skin.
        MESSAGE_END();
        m_iLastSkin = pev->skin;
    }

 


Теперь компилируйте сервер и сравнивайте на сколько байт уменьшился траффик :p (если он вообще изменился).


g-cont 


Категория: Кодинг | Добавил: SuperStart (18.10.2010)
Просмотров: 2277 | Рейтинг: 0.0/0 |



Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Copyright www.akksimo.net © 2021