Содержание: 1.Вступление. 2.Подготовка Редактора Объектов и работа с Менеджером Импорта. 3.Расстановка требуемых объектов на карте. 4.Написание API для облегченной работы. 5.Инициализация системы. 6.Работа с событиями.
1.Вступление
Увлеченной разработкой FSGUI системы выбора героев, я решил написать статью, что бы каждый новичок мог сделать такую необычную вещь в своей карте. Перед тем как начать писать сие «чудо», я два раза сделал систему выбора, третий раз я пишу ее вместе с вами и прикреплю Demo Map к данной статье, что бы вам было легче разобраться. Я решил писать систему на родном Jass2, без всяких надстроек (даже с udg_).Что бы хоть как-то разобраться в том, что я буду рассказывать, вам потребуется знание Jass,желательно на среднем уровне.
2. Подготовка Редактора Объектов и работа с Менеджером Импорта.
FSGUI – представляет из себя графический интерфейс, непосредственно в любом месте игровой области. Обычно такие системы используют Разрушаемые Объекты и Юнитов либо Trackable. В данной статье я расскажу про способ, основанный на Trackable. Trackable - специальный объект ассоцированый с моделью, отображаемой в игре. При наведении(или при щелчке) мыши на модель Trackable, можно производить определенные действия. Основная проблема работы с Trackables состоит в том что мы не можем их перемещать, удалять или скрывать. (все верно но мы можем вынести их в отдельную область и при необходимости переносить туда камеру. примечание - Avatar). Trackables работают в мультиплеере. (с) KaTTana И так,начнем. Для начала нам понадобятся модели рамок, кнопок и модель Trackable. Благо я их прекрепил в конце статьи,так что вам не придется их искать. Мы взяли модель для Trackable 4x4,т.к такой размер будет иметь наша иконка героя. Импортируем это все в нашу карту. Убираем как обычно war3mapImported\ со всех импортированных файлов. Далее заходим в Редактор Объектов – Разрушаемые Объекты Создаем нестандартный Разрушаемый Объект ,я взял за основу Блокираторы пути. Назовем созданный объект - Border. Это и будет наша рамка. Скопируем его 8 раз(Левая, Правая, Нижняя, Верхняя, Левая Верхняя, Правая Верхняя, Левая Нижняя, Правая Нижняя) Выстроим настройки так, как показано ниже на картинке: [spoiler="Картинка 1"][/spoiler] Примечание: В файле модели указываем для каждого вида рамки свою. Пример: верхняя рамка - borderU.mdl В поле Графика – Заменяемый файл текстур - мы ставим текстуру, которая будет наложена на наши рамки. Я выбрал стандартную границу Альянса.
3. Расстановка требуемых объектов на карте.
Проведя такие манипуляции с оставшимися объектами, мы должны выделить место на карте, где будет происходить наш выбор. Это место лучше «закрасить» тайлсетом – Бездна. Когда место выбрано и объекты настроены, мы можем приступать к созданию самого интерфейса, в котором будет происходить выбор. У меня получилось так: [spoiler="Картинка 2"][/spoiler]
Далее, мы должны создать объекты с иконками наших будущих героев. [spoiler="Картинка 3"][/spoiler] В поле Графика – Заменяемый файл текстур - мы ставим иконку нашего героя. Примечание: В поле файл модели мы ставим Button.mdl! Смотрите, не ошибитесь! После создание можно поставить его на карту и посмотреть что получилось. [spoiler="Картинка 4"][/spoiler] Все работает? Отлично! Можно удалить портреты, ведь они будут создаваться триггерно.
4.Написание API для облегченной работы
Ну а сейчас мы перейдем к самой интересной части этой статьи, а именно к кодингу! Для начала создадим переменную типа хэш-таблица и назовем ее Hash. Затем напишем вот такую ф-ию – NewTrackable .
[code=jass]function NewTrackable takes string path,real x,real y,player owner,integer herot returns trackable local trackable tr if GetLocalPlayer() != owner then // Если игрок,котороый сидит за компьютером set path=" "//не является тем, для кого trackable был создан,то для него этот trackable будет без модели. endif// set tr=CreateTrackable(path,x,y,0.)//создает trackable по заданам параметрав в точке х,y call SaveReal(udg_Hash,GetHandleId(tr),0,x) // сохраняем координату x нашего trackable call SaveReal(udg_Hash,GetHandleId(tr),1,y) // сохраняем координату y нашего trackable call SaveInteger(udg_Hash,GetHandleId(tr),2,GetPlayerId(owner)) // сохраняем владельца нашего trackable call SaveInteger(udg_Hash,GetHandleId(tr),3,herot) // сохраняем rawcode героя привязанного к нашему trackable return tr //возвращает созданный trackable endfunction[/code]
Данная ф-ия создаст Trackable в точке х и у с нужной нам моделью, для нужного нам игрока, а также привяжет rawcode героя к этому Trackable . Следующим шагом нам нужно написать ф-ии, которая позволит нам узнать х и у Trackable, его владельца и rawcode героя.
[code=jass]function GetTrackableX takes trackable tr returns real// Данная ф-ия возвращает координату х нужного нам Trackable return LoadReal(udg_Hash,GetHandleId(tr),0) endfunction
function GetTrackableY takes trackable tr returns real // Данная ф-ия возвращает координату у нужного нам Trackable return LoadReal(udg_Hash,GetHandleId(tr),1) endfunction
function GetTrackableOwner takes trackable tr returns player // Данная ф-ия возвращает владельца нужного нам Trackable return Player(LoadInteger(udg_Hash,GetHandleId(tr),2)) endfunction function GetTrackableHero takes trackable tr returns integer // Данная ф-ия возвращает rawcode героя нужного нам Trackable return LoadInteger(udg_Hash,GetHandleId(tr),3) endfunction[/code]
Теперь мы можем создать Trackable и получить всю информацию о нем. Дальше, нам нужна ф-ия которая создаст Trackables для нужных нам игроков (ведь у нас их будет 12) , а также добавит два события:
[code=jass]native TriggerRegisterTrackableTrackEvent takes trigger whichTrigger, trackable t returns event[/code] И [code=jass]native TriggerRegisterTrackableHitEvent takes trigger whichTrigger, trackable t returns event[/code]
Первое событие срабатывает, когда наводят мышкой на Trackable ,а второе когда поэтому Trackable совершают клик. Теперь приступим к написанию ф-ии Create Track .
[code=jass] function CreateTrack takes string path,real x, real y,integer herot,integer pl,trigger track,trigger hit returns nothing local trackable tr local integer i = 0 loop exitwhen i == pl//количество игроков (от 0 до 11) для которых мы создадим trackable if GetPlayerSlotState(Player(i)) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(Player(i)) == MAP_CONTROL_USER then// проверка на играющих игроков под контролем человека set tr = NewTrackable(path,x,y,Player(i),herot) //Создание trackable для каждого из них call TriggerRegisterTrackableTrackEvent(track,tr) //Добавление к trackable событие наведение в нужный нам триггер call TriggerRegisterTrackableHitEvent(hit,tr) //Добавление к trackable событие клика в нужный нам триггер endif set i = i + 1 endloop endfunction[/code]
Теперь мы можем создавать Trackable для всех играющих игроков. На этом написание API завершено!
5.Инициализация системы
Создадим триггер с название InitPick. Добавим ему событие Время – Прошло 0 секунд Это позволит инициализировать нашу систему сразу при старте карты. Следующим шагом мы должны создать переменную, которая будет хранить наших героев. Зададим ей имя HeroH, тип целочисленная массив. Так как у нас пока что один герой то только его и занесем,а также иницализруем хэштаблицу:
[code=jass]function Trig_InitPick_Actions takes nothing returns nothing set udg_Hash=InitHashtable() set udg_HeroH[0]='Edem' endfunction
function InitTrig_InitPick takes nothing returns nothing set gg_trg_InitPick = CreateTrigger() call TriggerRegisterTimerEvent( gg_trg_InitPick,.01,false) call TriggerAddAction( gg_trg_InitPick, function Trig_InitPick_Actions ) endfunction [/code]
Далее, создадим область, где будет происходить наш выбор. Назовем ее PickHero. Что бы игрок видел, что там происходит, нужно разблокировать для него модификатор видимости. Так же, нам потребуется переменная типа логическая массив с название CamT. Она поможет нам определить нужно, закреплять камеру для игрока или нет.
[code=jass]function Trig_InitPick_Actions takes nothing returns nothing local integer i=0 set udg_Hash=InitHashtable() set udg_HeroH[0]='Edem' loop exitwhen i>11 call FogModifierStart(CreateFogModifierRect(Player(i),FOG_OF_WAR_VISIBLE,gg_rct_HeroPick,true,false)) set udg_CamT[i]=true set i=i+1 endloop set i=0 endfunction
function InitTrig_InitPick takes nothing returns nothing set gg_trg_InitPick = CreateTrigger() call TriggerRegisterTimerEvent( gg_trg_InitPick,.01,false) call TriggerAddAction( gg_trg_InitPick, function Trig_InitPick_Actions ) endfunction [/code]
Я установил i=0 потому что дальше нам понадобится еще один цикл. Ну а пока создадим камеру, которая будет направлена на наш выбор героев. Назовем нашу камеру CAMERA и настроим так, как показано на рисунке (мне кажется, что такие параметры более удобны): [spoiler="Картинка 5"][/spoiler] Дальше, нам понадобится триггер,который будет крепить эту камеру для игрока чья переменная udg_CamT == true
Назовем наш триггер Camera. Он будет каждые 0.01 секунды крепить кмеру CAMERA для игроков.
[code=jass]function Trig_Camera_Actions takes nothing returns nothing local integer i=0 loop exitwhen i>11 if GetLocalPlayer() == Player(i) and udg_CamT[i] then//Крепит камеру если за компьютером сидит нужный нам игрок и его переменная CamT==true call CameraSetupApplyForceDuration(gg_cam_CAMERA,true,.10) endif set i=i+1 endloop endfunction
function InitTrig_Camera takes nothing returns nothing set gg_trg_Camera = CreateTrigger( ) call TriggerRegisterTimerEvent( gg_trg_Camera,.01,true) call TriggerAddAction( gg_trg_Camera, function Trig_Camera_Actions ) endfunction
[/code]
Примечание: Конечно можно использовать таймер,но я думаю новичкам так будет понятней. Далее вернемся к нашему триггеру InitPick. Нам ведь нужно создать: 1)Иконки героев 2)Trackable для этих иконок Начнем с иконок. Создадим в триггере целочисленный массив IconHero и запишем в него rawcode наших Разрушаемых Объектов:
[code=jass]function Trig_InitPick_Actions takes nothing returns nothing local integer i=0 local integer array IconHero set udg_Hash=InitHashtable() set udg_HeroH[0]='Edem' set IconHero[0]='B008' loop exitwhen i>11 call FogModifierStart(CreateFogModifierRect(Player(i),FOG_OF_WAR_VISIBLE,gg_rct_HeroPick,true,false)) set udg_CamT[i]=true set i=i+1 endloop set i=0 endfunction
function InitTrig_InitPick takes nothing returns nothing set gg_trg_InitPick = CreateTrigger() call TriggerRegisterTimerEvent( gg_trg_InitPick,.01,false) call TriggerAddAction( gg_trg_InitPick, function Trig_InitPick_Actions ) endfunction[/code]
Примечание: Индексы у массивов HeroH и IconHero должны быть одинаковы! Далее, нам нужно создать эти иконки в самой игре, для этого нужно узнать координаты точки, откуда начнется создание. На картинке курсор не виден,поэтому я примерно обозначил его красной точкой. [spoiler="Картинка 6"][/spoiler] Мы получили координаты (x,y,z) X=-1160 Y=2455 Z= нам не нужен В зависимости от того как у нас расположена область выбора, нужно определить какая величина изменяется при движении мышки вправо. У меня это Х. Теперь нужно будет создать Иконку героя и Trackable для нее в этой позиции.
[code=jass]function Trig_InitPick_Actions takes nothing returns nothing local integer i=0 local integer array IconHero local real x=-1160 local real y=2455 set udg_Hash=InitHashtable() set udg_HeroH[0]='Edem' set IconHero[0]='B008' loop exitwhen i>11 call FogModifierStart(CreateFogModifierRect(Player(i),FOG_OF_WAR_VISIBLE,gg_rct_HeroPick,true,false)) set udg_CamT[i]=true set i=i+1 endloop set i=0 loop exitwhen i>0 call SaveDestructableHandle(udg_Hash,udg_HeroH[i],6,CreateDestructable(IconHero[i],x+65*i,y,0,1.,0)) //Создаст декорацию в тчоке x+65*i call SaveBoolean(udg_Hash,udg_HeroH[i],5,true)//Сохраняем на rawcode героя логическую что бы определит взяли этого героя или нет. call CreateTrack("4x4Trackable.MDX",x+65*i,y,udg_HeroH[i],11,gg_trg_Track,gg_trg_Click) // Создаем трекаблы и добавляем события в триггеры set i=i+1 endloop endfunction
function InitTrig_InitPick takes nothing returns nothing set gg_trg_InitPick = CreateTrigger() call TriggerRegisterTimerEvent( gg_trg_InitPick,.01,false) call TriggerAddAction( gg_trg_InitPick, function Trig_InitPick_Actions ) endfunction [/code]
Вы спросите, почему x+65*i? Отвечаю, за каждый виток цикла, мы создаем иконку и Trackable в позиции -1160+65*i. 65 – примерная ширина иконки, а умножаем, на i что бы следующие иконки ни лепились, а шли ровно. Как вы видите, мы сохраняем декорацию, для того что бы при выборе героя удалить. [code=jass]call SaveBoolean(udg_Hash,udg_HeroH[i],5,true)[/code] - Сохраняем на rawcode героя логическую, что бы определит, взяли этого героя или нет. С инициализацией выбора мы закончили! Можете запустить карту и посмотреть, что получилось, если все правильно, то должно быть что-то вроде этого: [spoiler="Картинка 7"][/spoiler]
6.Работа с событиями
Как вы успели заметить, то в ф-ии [code=jass]call CreateTrack("4x4Trackable.MDX",x+65*i,y,udg_HeroH[i],11,gg_trg_Track,gg_trg_Click)[/code] Я указал два триггера gg_trg_Track и gg_trg_Click. Вот как выглядят эти триггеры:
function InitTrig_Track takes nothing returns nothing set gg_trg_Track = CreateTrigger() call TriggerAddAction( gg_trg_Track, function Trig_Track_Actions ) endfunction [/code]
Начнем с триггера gg_trg_Track. Мы можем получить реагирующий Trackable с помощью GetTriggeringTrackable() Что мы и сделаем сейчас. Также мы можем поулчить: GetTrackableOwner(tr) – владелец Trackable, GetTrackableHero(tr) – равкод привязанного героя.
[code=jass]function Trig_Track_Actions takes nothing returns nothing local trackable tr=GetTriggeringTrackable() //реагирующая трекабля local player p=GetTrackableOwner(tr) //владелец трекабли local integer id=GetPlayerId(p) //Id игрока который навел local integer herot=GetTrackableHero(tr) // Получаем равкод героя в переменной udg_HeroH endfunction
function InitTrig_Track takes nothing returns nothing set gg_trg_Track = CreateTrigger() call TriggerAddAction( gg_trg_Track, function Trig_Track_Actions ) endfunction [/code]
Далее с помощью модели "BTNselection.mdx" мы создадим эффект выбора
[code=jass]function Trig_Track_Actions takes nothing returns nothing local trackable tr=GetTriggeringTrackable() //реагирующая трекабля local player p=GetTrackableOwner(tr) //владелец трекабли local integer id=GetPlayerId(p) //Id игрока который навел local integer herot=GetTrackableHero(tr) // Получаем равкод героя в переменной udg_HeroH local string s = " " if udg_CamT[id] and LoadBoolean(udg_Hash,herot,5) then // если udg_CamT==trueи нашего героя еще не взяли то call DestroyEffect(LoadEffectHandle(udg_Hash,herot,7)) //удалить загруженный спецэфект if GetLocalPlayer() == p then // если игрок за компьютером равен игроку владельцу set s = "BTNselection.mdx"//установить s-модель эффекта на "BTNselection.mdx" endif call SaveEffectHandle(udg_Hash,herot,7,AddSpecialEffect(s,GetTrackableX(tr),GetTrackableY(tr)))//Сохранить тут же созаднный эффект в позиции трекабли endif set tr=null endfunction
function InitTrig_Track takes nothing returns nothing set gg_trg_Track = CreateTrigger() call TriggerAddAction( gg_trg_Track, function Trig_Track_Actions ) endfunction [/code]
Зачем разрушать загруженный эффект? Это что бы при повторном наведении,либо при наведении на другую иконку этот эффект удалялся. Если все верно получаем: [spoiler="Картинка 8"][/spoiler] Теперь нам нужно сделать сам выбор героя по щелчку. Триггер gg_trg_Click мало отличается от gg_trg_Track. Мы также получаем все данные об Trackable, но при клике(событии) мы удаляем загруженный эффект. Удаляем иконку героя. Сохраняем логическую на false. И создаем игроку героя, записав его в переменную - боевая единица массив Hero.
[code=jass]function Trig_Click_Actions takes nothing returns nothing local trackable tr=GetTriggeringTrackable() //реагирующая трекабля local player p=GetTrackableOwner(tr) //владелец трекабли local integer id=GetPlayerId(p) //Id игрока который навел local integer herot=GetTrackableHero(tr) // Получаем равкод героя в переменной udg_HeroH if udg_CamT[id] and LoadBoolean(udg_Hash,herot,5) then // если udg_CamT==trueи нашего героя еще не взяли то call DestroyEffect(LoadEffectHandle(udg_Hash,herot,7)) // уничтожаем эффект set udg_Hero[id]=CreateUnit(p,herot,GetStartLocationX(GetPlayerStartLocation(p)),GetStartLocationY(GetPlayerStartLocation(p)),0) //создаем героя игроку call SaveBoolean(udg_Hash,herot,5,false) // сохраняем на равкод героя false call RemoveDestructable(LoadDestructableHandle(udg_Hash,herot,6)) //удаляем декорацию героя set udg_CamT[id]=false// устанавливаем игроку CamT на false,что бы отпустить камеру и не реагировать на Trackable call DisplayTextToPlayer(GetLocalPlayer(),0.,0.,GetPlayerName(p)+"|r has choose "+GetUnitName(udg_Hero[id])+".") //Выводим надпись о выборе endif set tr=null endfunction
function InitTrig_Click takes nothing returns nothing set gg_trg_Click = CreateTrigger() call TriggerAddAction( gg_trg_Click, function Trig_Click_Actions ) endfunction[/code]
Если все верно, то при клике на иконку выберется ваш персонаж и его иконка удалится. [spoiler="Картинка 9"][/spoiler]
P.S Все что я не учел по вашему мнению, пишите. Будет дополняться. Могут быть смешные ошибки - хочу спать. P.P.S Следющая статья - "Полноэкранный Магазин на FSGUI" P.P.P.S Моя первая статья
Ty3uK, это тоже рукописный. У [DUОS]'а немного по-другому.
Quote (Dreii)
DestroyEffect(LoadEffectHandle(udg_Hash,herot,7)) // уничтожаем эффект udg_Hero[id]=CreateUnit(p,herot,GetStartLocationX(GetPlayerStartLocation(p)),GetStartLocationY(GetPlayerStartLocation(p)),0) //создаем героя игроку SaveBoolean(udg_Hash,herot,5,false) // сохраняем на равкод героя false RemoveDestructable(LoadDestructableHandle(udg_Hash,herot,6)) //удаляем декорацию героя udg_CamT[id]=false // устанавливаем игроку CamT на false,что бы отпустить камеру и не реагировать на Trackable DisplayTextToPlayer(GetLocalPlayer(),0.,0.,GetPlayerName(p)+"|r has choose "+GetUnitName(udg_Hero[id])+".") //Выводим надпись о выборе
А кто-то говорил, что будет писать на чистом JASS2.
Добавлено (31 Март 2012, 12:24:49) --------------------------------------------- SirNikolas, как тру кодер скажи,код приемлим?
Добавлено (31 Март 2012, 12:35:26) --------------------------------------------- Обнвоил первый пос. перезалил демо карту Теперь все на чистеньком джассике двоечке
Добавлено (31 Март 2012, 12:49:42) ---------------------------------------------
Quote (Dreii)
P.S Все что я не учел по вашему мнению, пишите. Будет дополняться. Могут быть смешные ошибки - хочу спать. P.S.S Следющая статья - "Полноэкранный Магазин на FSGUI" P.S.S.S Моя первая статья