Сейчас 08:11:59 Пятница, 19 апреля, 2024 год
Главная ⇒ Форум ⇐ RSS Файлы Cтатьи Картинки В о й т и   или   з а р е г и с т р и р о в а т ь с я

Меню сайта

Категории

Наш опрос
Какой тип карт вам нравится больше всего?
Проголосовало: 145102

Сейчас на сайте
На сайте всего: 4
Гостей: 4
Пользователей: 0

Реклама

Главная » Статьи по WarCraft 3 » Создание карт » Jass
Создание MUI спеллов - Часть 1

Часть 1

Начну я, пожалуй, с небольшого лирического отступления. Примеры я буду давать на классическом Jass 2 от близзард (без надстроек типа cJass и vJass напару с ZINC). Теперь изучим суть MUI. MUI - это возможность одновременного каста одного и того же заклинания разными боевыми единицами (суть состоит в отсутствии перезаписи значений переменных, как это может быть с глобальными переменными). Это достигается за счет сохранения нужных локальных переменных в хэш (по правде, можно и не заносить некоторые ссылки в переменные и сохранять их сразу, но об этом позже). Пока у вас не разбежались глаза, я подкину нам практической работы. Давайте создадим способность, которая у нас будет работать триггерно. Для этого мы создадим способность на основе заклинания "Канал" (можно брать и любые другие, но лучший вариант: Канал для активных заклинаний и Бонус аттрибутов для пассивных). Настройке способности я внимания уделять не буду. Следующий шаг - редактор триггеров. Открываем. Давайте создадим переменную типа хэштаблица (hashtable) с незамысловатым названием hash. Создали? Отлично. Далее нам надо инициализировать ее, для этого в наш триггер инициализации надо вставить такую строчку
[code=jass]set udg_hash = InitHashtable()[/code]

После этого действия мы сможем сохранять значения в хэш. Первая часть закончена!

Часть 2

Давайте создадим новый триггер и назовем его... Kill Unit. Незамысловато, но точно отражает суть того, на чем мы будем учиться. Думаю, что все уже поняли - мы будем создавать заклинание, которое будет убивать цель. В качестве события выбираем "Юнит привел способность в действие" (A unit Starts the effect of an ability), добавляем первое же условие (оно нужно для упрощения работы далее) и переводим триггер в текст при помощи "Правка - Перевести в текст" (Edit - Convert to Custom Text).


Лирическое отступление номер два: я не буду парить вам мозг о красоте кода и манере скриптописания, для этого вам стоит почитать статью Ajaccio, я стараюсь делать код читабельным, но не нагружать лишними символами, поэтому я рьярно избавляюсь от стандартного комментария между действиями и инициализацией, а так же от пробелов в функциях инициализации. В итоге мой "девственный" код превращается в это:
[code=jass]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]
После этих нехитрых манипуляций с кодом мы приступаем к реализации задуманного. Итак, для того, чтобы убить юнита, мы воспользуемся тривиальной функцией

[code=jass]call KillUnit(GetSpellTargetUnit())[/code]
где GetSpellTargetUnit()- юнит-цель заклинания. Но сначала нам надо ввести условие срабатывания триггера. Для этого в условие мы пишем
[code=jass]return GetSpellAbilityId() == 'A000'[/code]
где 'A000'- равкод вашего заклинания (нажатие сочетания Ctrl+D в РО заменит названия заклинаний на их равкоды). В итоге наш код приобретет следующий вид:

[code=jass]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]

Сохраняем, тестируем. Работает? Ну куда ж ему деться с подводной лодки. Но вы спросите: "А где же тут муи?". Муи этого спелла - убийство юнита без занесения его в глобальную переменную. Никакой перезаписи, все отлично. Но давайте усложним задачу - убьем юнита через определенный промежуток времени. На гуи это решалось просто - "Ждать Н сек.", но это плохой способ. Очень. Поэтому юзаем таймер. Для начала создадим его:
[code=jass]local timer t = CreateTimer()[/code]
и возьмем его уникальный идентификатор (Ид хэндла):
[code=jass]local integer hid = GetHandleId(t)[/code]
на это значение мы будем сохранять нужные данные в хэш. Сохраняем юнита в хэш:
[code=jass]call SaveAgentHandle(udg_hash, hid, 0, GetSpellTargetUnit())[/code]
Замечу, что с помощью этой функции можно (и нужно) сохранять не только юнитов, но и группы, эффекты, таймеры, декорации и все остальные объекты. Далее запускаем таймер:
[code=jass]call TimerStart(t, 3., false, function Trig_Kill_Unit_Timer)[/code]
где t - наш таймер; 3. - время, через которое он истечет; false (или true) - периодичность таймера (true - периодичесские действия, false - однократный таймер); function Trig_Kill_Unit_Timer - функция, которая выполнится при истечении таймера. Не забываем обнулять локальные переменные:
[code=jass]set t = null[/code]
Далее нам надо написать само тело таймера. Займемся этим:

[code=jass]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[/code]

Глаза разбегаются? Изучаем!
Функция тамера ничего не берет и не возвращает. Заносим в локальные переменные истекающий таймер (GetExpiredTimer()), берем его уникальный идентификатор (GetHandleId(t)). Дальше - интереснее: в локальную переменную загружаем юнита из хэша (call LoadUnitHandle()) и... Маньячно убиваем его. Далее странная функция.... Все просто - чистим хэш от всех сохраненных значений (call FlushChildHashtable(udg_hash, hid)), уничтожаем таймер (call DestroyTimer(t)) и обнуляем локальные переменные. Все! При касте спелла цель умрет через 3 секунды. Снова закономерный вопрос: "А где муи?". Отвечаю: муи данного спелла - сохранение юнита (точнее всех данных, но об этом дальше) в хэш на ид таймера. При каждом касте создается новый таймер, ид каждого уникален, перезаписи значений нет, а следовательно не будет стандартных "гуишных лагов". На этом я заканчиваю первую статью из своего мелкого цикла "Муи спеллы". Пожелания, вопросы и исправления - в тему. Всем спасибо за внимание! П.с. Извините за скудное оформление - нет во мне дизайнерской жилки :(

by Max Karelov aka Ty3uK
Просмотров: 2611 Добавил: Ty3uK Добавлено: 15 Марта 2013 в 20:26:28
Комментариев: 4 |

Всего комментариев: 4
07 Марта 2014
4. Александр (аркей) [Материал]
убери вставки [code]
а так +5

16 Марта 2013
3. Максим Карелов (Ty3uK) [Материал]
К сожалению, он тогда очень мелкий.

16 Марта 2013
2. Влад (vladyka) [Материал]
я бы уменьшил размер шрифта до стандартного.

15 Марта 2013
1. Simplar Duoson (Duosora) [Материал]
Оформление: 5/5
Использованы картинки, цветовые выделения, ВВ-коды и спойлеры. В этом пункте придраться вообще не к чему в буквальном смысле слова. Несмотря на то, как автор заканчивает статью, я скажу, что жилка оформителя здесь проскакивает очень чётко.

Содержание: 5/5
Лаконично и подробно. Тема раскрыта полностью (учитывая, что автор говорит о том, что возможно продолжение). Объём статьи соответствует норме.

Орфография: 5/5
Всё написано строго согласно правилам русского языка.

Всего: 5/5
Таких статей надо больше!
Модерацию статья проходит.

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

Форма входа
Логин:
Пароль:

Поиск

Случайная картинка

Случайный файл
[06 Мая 2008]
[Карты · Melee]
Desidarius' Dodecagon -
Великолепно выполненная карта для режима "Сражение" для двенадцати игроков. Представляет собой большой симметричный остров, по углам которого чуть в стороне располагаются меньшие островки с большими залежами золота.

Новые карты
[07 Февраля 2016]
Переезжаем на другой сайт, господа![Dota]
[18 Октября 2015]
Duel of Gods PreV[Другое]
[18 Октября 2015]
Hero of The Empire v1.18g[RPG]
[17 Октября 2015]
Servant War v1.05[Другое]
[17 Октября 2015]
Age of Vikings Edited v1.6[Другое]
[17 Октября 2015]
Strife of the Champions Beta v1.2[Arena]
[17 Октября 2015]
VirusBoll (rus)[Другое]
[17 Октября 2015]
Exterminators v1[AoS]
[17 Октября 2015]
The Lord Heroes v1.2[Другое]
[17 Октября 2015]
Versus heroe Arena 1.0 AI[Arena]

5 лучших по кол-ву добавленных статей
[ Duosora ] [ 58 ]
[ Messenger ] [ 52 ]
[ Bru ] [ 39 ]
[ Pand@ ] [ 35 ]
[ OrcRider ] [ 27 ]

Наша кнопка
Warcraft3FT.info - Всё для Warcraft 3 и DotA

Другие варианты

Статистика

Материалы:
Новости: 1010
Файлы: 8668
Статьи: 680
Картинки: 8256
Форум: 30520/954989
Комментарии: 58094
Copyright © 2006 - 2024 Warcraft3FT.info При копировании материалов c сайта ставьте, пожалуйста, активную обратную ссылку на нас • Design by gReeB04ki ©
Хостинг от uCoz