[Статья] Создание MUI спеллов - Часть 1
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 17:46:41 | Сообщение # 1 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Доброго всем времени суток. Сегодня речь пойдет о такой вещи, как MUI, мы изучим, что это за такой страшный зверь и на что его ловить. Буду стараться писать понятным всем языком, дабы ни у кого не было сложностей. Итак, начнем!
Часть 1 Начну я, пожалуй, с небольшого лирического отступления. Примеры я буду давать на классическом Jass 2 от близзард (без надстроек типа cJass и vJassнапару с ZINC). Теперь изучим суть MUI. MUI - это возможность одновременного каста одного и того же заклинания разными боевыми единицами (суть состоит в отсутствии перезаписи значений переменных, как это может быть с глобальными переменными). Это достигается за счет сохранения нужных локальных переменных в хэш (по правде, можно и не заносить некоторые ссылки в переменные и сохранять их сразу, но об этом позже). Пока у вас не разбежались глаза, я подкину нам практической работы. Давайте создадим способность, которая у нас будет работать триггерно. Для этого мы создадим способность на основе заклинания "Канал" (можно брать и любые другие, но лучший вариант: Канал для активных заклинаний и Бонус аттрибутов для пассивных). Настройке способности я внимания уделять не буду. Следующий шаг - редактор триггеров. Открываем. Давайте создадим переменную типа хэштаблица (hashtable) с незамысловатым названием hash. Создали? Отлично. Далее нам надо инициализировать ее, для этого в наш триггер инициализации надо вставить такую строчку Code set udg_hash = InitHashtable() После этого действия мы сможем сохранять значения в хэш. Первая часть закончена!
Часть 2 Давайте создадим новый триггер и назовем его... Kill Unit. Незамысловато, но точно отражает суть того, на чем мы будем учиться. Думаю, что все уже поняли - мы будем создавать заклинание, которое будет убивать цель. В качестве события выбираем "Юнит привел способность в действие" (A unit Starts the effect of an ability), добавляем первое же условие (оно нужно для упрощения работы далее) и переводим триггер в текст при помощи "Правка - Перевести в текст" (Edit - Convert to Custom Text).
Лирическое отступление номер два: я не буду парить вам мозг о красоте кода и манере скриптописания, для этого вам стоит почитать статью Ajaccio, я стараюсь делать код читабельным, но не нагружать лишними символами, поэтому я рьярно избавляюсь от стандартного комментария между действиями и инициализацией, а так же от пробелов в функциях инициализации. В итоге мой "девственный" код превращается в это: Code function Trig_Kill_Unit_Conditions takes nothing returns boolean endfunction
function Trig_Kill_Unit_Actions takes nothing returns nothing endfunction
function InitTrig_Kill_Unit takes nothing returns nothing set gg_trg_Kill_Unit = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_Kill_Unit, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition(gg_trg_Kill_Unit, Condition(function Trig_Kill_Unit_Conditions)) call TriggerAddAction(gg_trg_Kill_Unit, function Trig_Kill_Unit_Actions) endfunction После этих нехитрых манипуляций с кодом мы приступаем к реализации задуманного. Итак, для того, чтобы убить юнита, мы воспользуемся тривиальной функцией
Code call KillUnit(GetSpellTargetUnit()) где GetSpellTargetUnit() - юнит-цель заклинания. Но сначала нам надо ввести условие срабатывания триггера. Для этого в условие мы пишем Code return GetSpellAbilityId() == 'A000' где 'A000'- равкод вашего заклинания (нажатие сочетания Ctrl+D в РО заменит названия заклинаний на их равкоды). В итоге наш код приобретет следующий вид:
Code function Trig_Kill_Unit_Conditions takes nothing returns boolean return GetSpellAbilityId() == 'A000' endfunction
function Trig_Kill_Unit_Actions takes nothing returns nothing call KillUnit(GetSpellTargetUnit()) endfunction
function InitTrig_Kill_Unit takes nothing returns nothing set gg_trg_Kill_Unit = CreateTrigger() call TriggerRegisterAnyUnitEventBJ(gg_trg_Kill_Unit, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddCondition(gg_trg_Kill_Unit, Condition(function Trig_Kill_Unit_Conditions)) call TriggerAddAction(gg_trg_Kill_Unit, function Trig_Kill_Unit_Actions) endfunction
Сохраняем, тестируем. Работает? Ну куда ж ему деться с подводной лодки. Но вы спросите: "А где же тут муи?". Муи этого спелла - убийство юнита без занесения его в глобальную переменную. Никакой перезаписи, все отлично. Но давайте усложним задачу - убьем юнита через определенный промежуток времени. На гуи это решалось просто - "Ждать Н сек.", но это плохой способ. Очень. Поэтому юзаем таймер. Для начала создадим его: Code local timer t = CreateTimer() и возьмем его уникальный идентификатор (Ид хэндла): Code local integer hid = GetHandleId(t) на это значение мы будем сохранять нужные данные в хэш. Сохраняем юнита в хэш: Code call SaveAgentHandle(udg_hash, hid, 0, GetSpellTargetUnit()) Замечу, что с помощью этой функции можно (и нужно) сохранять не только юнитов, но и группы, эффекты, таймеры, декорации и все остальные объекты. Далее запускаем таймер: Code call TimerStart(t, 3., false, function Trig_Kill_Unit_Timer) где t - наш таймер; 3. - время, через которое он истечет; false (или true) - периодичность таймера (true - периодичесские действия, false - однократный таймер); function Trig_Kill_Unit_Timer - функция, которая выполнится при истечении таймера. Не забываем обнулять локальные переменные: Далее нам надо написать само тело таймера. Займемся этим:
Code function Trig_Kill_Unit_Timer takes nothing returns nothing local timer t = GetExpiredTimer() local integer hid = GetHandleId(t) local unit target = LoadUnitHandle(udg_hash, hid, 0) call KillUnit(target) call FlushChildHashtable(udg_hash, hid) call DestroyTimer(t) set t = null set target = null endfunction
Глаза разбегаются? Изучаем! Функция тамера ничего не берет и не возвращает. Заносим в локальные переменные истекающий таймер (GetExpiredTimer()), берем его уникальный идентификатор (GetHandleId(t)). Дальше - интереснее: в локальную переменную загружаем юнита из хэша (call LoadUnitHandle()) и... Маньячно убиваем его. Далее странная функция.... Все просто - чистим хэш от всех сохраненных значений (call FlushChildHashtable(udg_hash, hid)), уничтожаем таймер (call DestroyTimer(t)) и обнуляем локальные переменные. Все! При касте спелла цель умрет через 3 секунды. Снова закономерный вопрос: "А где муи?". Отвечаю: муи данного спелла - сохранение юнита (точнее всех данных, но об этом дальше) в хэш на ид таймера. При каждом касте создается новый таймер, ид каждого уникален, перезаписи значений нет, а следовательно не будет стандартных "гуишных лагов". На этом я заканчиваю первую статью из своего мелкого цикла "Муи спеллы". Пожелания, вопросы и исправления - в тему. Всем спасибо за внимание! П.с. Извините за скудное оформление - нет во мне дизайнерской жилки by Max Karelov aka Ty3uK
|
|
|
|
Dreii | Дата: Суббота, 14 Января 2012, 17:59:31 | Сообщение # 2 |
10 уровень
Группа: Проверенные
Сообщений: 4991
Награды: 0
Репутация: 603
Блокировки:
| Нужно добавить,если делают переодический таймер,то при ф-ии DestroyTimer(t) нужно поставить PauseTimer(t) Также необязательно в данном случаее забивать GetHandleId(..) в переменную.
|
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 18:24:16 | Сообщение # 3 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Офк, добавлю. Вторая статья будет про спеллы с периодическими действиями
|
|
|
|
[DUОS] | Дата: Суббота, 14 Января 2012, 20:59:10 | Сообщение # 4 |
Группа: Заблокированные
Сообщений: 6279
Награды: 9
Репутация: 1708
Блокировки:
| Познавательная для новичков статья... Jass2 слитно надо писать, это раз. Рассказать надо было нагляднее о муишном респауне, это два. А так четвёрка с плюсом из пяти.
|
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 21:09:34 | Сообщение # 5 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Ок, учту на будущее, спасибо
|
|
|
|
lawson | Дата: Суббота, 14 Января 2012, 22:41:13 | Сообщение # 6 |
Группа: Проверенные
Сообщений: 3482
Награды: 0
Репутация: 974
Блокировки:
| Вижу ты начал писать статьи, одобряю.
Nic nie wiem bo mam chuj. редактирую посты! ВСЕ!
|
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 22:41:54 | Сообщение # 7 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Спасибо, развиваю навык
|
|
|
|
lawson | Дата: Суббота, 14 Января 2012, 22:46:13 | Сообщение # 8 |
Группа: Проверенные
Сообщений: 3482
Награды: 0
Репутация: 974
Блокировки:
| В общем статья, хмм согласен с дуосом, напоминает пропаганду жасс2. Но большой респект за то что не очередная ктознаетзачем наработка, а целую статью запилил со скринами и пояснениями, без дуратских терий и определений, Молодцом!
Nic nie wiem bo mam chuj. редактирую посты! ВСЕ!
Сообщение отредактировал lawson - Суббота, 14 Января 2012, 22:49:10 |
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 22:48:27 | Сообщение # 9 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Благодарю, завтра напишу вторую. Рассмотрю периодические таймеры и спеллы на них. И, возможно, запилю наработку со спеллами как приложение к статьям. Стоит?
|
|
|
|
lawson | Дата: Суббота, 14 Января 2012, 22:49:30 | Сообщение # 10 |
Группа: Проверенные
Сообщений: 3482
Награды: 0
Репутация: 974
Блокировки:
| Quote (Ty3uK) И, возможно, запилю наработку со спеллами как приложение к статьям. Стоит? С пояснениями и комментариями!
Nic nie wiem bo mam chuj. редактирую посты! ВСЕ!
Сообщение отредактировал lawson - Суббота, 14 Января 2012, 22:49:45 |
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 22:51:26 | Сообщение # 11 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Ну офк же насчет пропаганды жасс2: я не шарю в vjass, а из cjass знаю только синтаксис. Смысл мне делать статью на нем? Тем более, я расчитывал ее на новичков
|
|
|
|
lawson | Дата: Суббота, 14 Января 2012, 22:52:58 | Сообщение # 12 |
Группа: Проверенные
Сообщений: 3482
Награды: 0
Репутация: 974
Блокировки:
| Quote (Ty3uK) Смысл мне делать статью на нем? Я не имел ввиду выбрать один какой либо диалект, я просто хотел сказать: зачем новичкам знать на какой жассе они кодят, объединил бы все эти ЗИНКИ и вжассы в одно слово - ЖАСС.
Nic nie wiem bo mam chuj. редактирую посты! ВСЕ!
Сообщение отредактировал lawson - Суббота, 14 Января 2012, 22:53:55 |
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 22:54:12 | Сообщение # 13 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| А... На будущее, чтобы потом не было разных фейлов среди "подрастающего поколения"
|
|
|
|
lawson | Дата: Суббота, 14 Января 2012, 22:55:18 | Сообщение # 14 |
Группа: Проверенные
Сообщений: 3482
Награды: 0
Репутация: 974
Блокировки:
| Ty3uK, Ты же сам видишь что для всех новичков есть один ЖАСС, а ты им с лету мозги промываешь вжассами и сжассами.
Nic nie wiem bo mam chuj. редактирую посты! ВСЕ!
|
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 22:56:24 | Сообщение # 15 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Ничего-ничего, боевое крещение. Пускай привыкают
|
|
|
|
lawson | Дата: Суббота, 14 Января 2012, 23:00:13 | Сообщение # 16 |
Группа: Проверенные
Сообщений: 3482
Награды: 0
Репутация: 974
Блокировки:
| Ty3uK, Пару ошибок бы подправить:Quote (Ty3uK) Функция тамера
Nic nie wiem bo mam chuj. редактирую посты! ВСЕ!
Сообщение отредактировал lawson - Суббота, 14 Января 2012, 23:00:32 |
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 23:01:35 | Сообщение # 17 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Эн... В чем ошибка?
|
|
|
|
lawson | Дата: Суббота, 14 Января 2012, 23:02:38 | Сообщение # 18 |
Группа: Проверенные
Сообщений: 3482
Награды: 0
Репутация: 974
Блокировки:
|
Nic nie wiem bo mam chuj. редактирую посты! ВСЕ!
|
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 23:03:48 | Сообщение # 19 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| А... Слепой. Очепятка, завтра поправлю. Спасибо
|
|
|
|
lawson | Дата: Суббота, 14 Января 2012, 23:07:05 | Сообщение # 20 |
Группа: Проверенные
Сообщений: 3482
Награды: 0
Репутация: 974
Блокировки:
| Ty3uK, Я бы еще в важных местах поставил бы знак восклицания - тоесть места которые надо читать более внимательно. Например:Quote (Ty3uK) Функция тамера ничего не берет и не возвращает Я бы здесь указал что это ОБЯЗАТЕЛЬНО(или ВАЖНО), а то можно подумать что это в твоем случае функция ничего не берет и не возвращает. Т.к уже с таким сталкивался.
Nic nie wiem bo mam chuj. редактирую посты! ВСЕ!
Сообщение отредактировал lawson - Суббота, 14 Января 2012, 23:12:28 |
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 23:10:16 | Сообщение # 21 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Окей, учту и исправлю, спасибо. Надо спросить у админки разрешение отметить такие места красным
|
|
|
|
Brut@lus | Дата: Суббота, 14 Января 2012, 23:21:49 | Сообщение # 22 |
Группа: Заблокированные
Сообщений: 2496
Награды: 1
Репутация: 924
Блокировки:
| Ty3uK, выделяй оранжевым+ жирным.
|
|
|
|
Ty3uK | Дата: Суббота, 14 Января 2012, 23:30:09 | Сообщение # 23 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Я так и делаю Добавлено (14 Январь 2012, 23:30:09) --------------------------------------------- Блин, так привык к подсветке синтаксиса, что укозовский код смотрится убого
|
|
|
|
SirNikolas | Дата: Воскресенье, 15 Января 2012, 19:38:13 | Сообщение # 24 |
Группа: Модераторы
Сообщений: 6729
Награды: 1
Репутация: 1867
Блокировки:
| Ждем комментариев от "непосвященных".
|
|
|
|
Ty3uK | Дата: Воскресенье, 15 Января 2012, 20:58:15 | Сообщение # 25 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Бтв, Ник, что сам скажешь про статью?
|
|
|
|