Сейчас 10:54:46 Среда, 18 декабря, 2024 год
Главная ⇒ Форум ⇐ RSS Файлы Cтатьи Картинки В о й т и   или   з а р е г и с т р и р о в а т ь с я

Меню сайта

Категории

Наш опрос
Ваша любимая раса?
Проголосовало: 177951

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

Реклама

Главная » Статьи по WarCraft 3 » Создание карт » Jass
Создание MUI-спеллов - Часть 2
В прошлой статье мы изучили базовые состявляющие триггерных "муи"-заклинаний - понятие хэндл, использование хэша и таймеры. В сегодняшней статье мы изучим создание заклинание с периодическим эффектом. На роль "жертвы" возьмем приблизительный аналог "горелки" Акса из ДотЫ. Как обычно готовим каркас триггера:

[code=jass]function Trig_Burning_Condition takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction

function Trig_Burning_Actions takes nothing returns nothing
endfunction

function InitTrig_Burning takes nothing returns nothing
set gg_trg_Burning = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Burning, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Burning, Condition(function Trig_Burning_Condition))
call TriggerAddAction(gg_trg_Burning, function Trig_Burning_Actions)
endfunction[/code]

Теперь продумаем последовательность действий, происходящих при использовании способности:
  • Мы кастуем на врага способность
  • Враг начинает гореть
  • Появляется эффект горения
  • Цель получает урон
  • Способность перестает действовать после N-секунд


Приступаем к написанию кода. Дальше будет полный спелл с последующим пояснением всего:
[code=jass]function Trig_Burning_Condition takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction

function Trig_Burning_Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer hid = GetHandleId(t)
//Грузим сохраненные переменные
local unit caster = LoadUnitHandle(udg_hash, hid, 0)
local unit target = LoadUnitHandle(udg_hash, hid, 1)
local effect burning = LoadEffectHandle(udg_hash, hid, 2)
local real time = LoadReal(udg_hash, hid, 3)
if time <= 7. then //Если время меньше семи, то
//мы наносим цели урон
call UnitDamageTarget(caster, target, 20., true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
if GetWidgetLife(target) > .405 then //Если у цели есть еще здоровье, то
set time = time + 1. //Увеличиваем время на 1 секунду
call SaveReal(udg_hash, hid, 3, time) //и сохраняем его в хэш
else //Если цель мертва, то мы
call PauseTimer(t) //Ставим таймер на паузу (!!ОБЯЗАТЕЛЬНО ДЛЯ ПЕРИОДИЧ. ТАЙМЕРОВ!!)
call DestroyTimer(t) //Уничтожаем таймер
call DestroyEffect(burning) //Уничтожаем эффект
call FlushChildHashtable(udg_hash, hid) //Чистим хэш
endif
else //Если время больше 7, то все делаем аналогично:
call PauseTimer(t) //Ставим таймер на паузу (!!ОБЯЗАТЕЛЬНО ДЛЯ ПЕРИОДИЧ. ТАЙМЕРОВ!!)
call DestroyTimer(t) //Уничтожаем таймер
call DestroyEffect(burning) //Уничтожаем эффект
call FlushChildHashtable(udg_hash, hid) //Чистим хэш
endif
set t = null
set caster = null
set target = null
set burning = null
endfunction

function Trig_Burning_Actions takes nothing returns nothing
local timer t = CreateTimer()
local integer hid = GetHandleId(t)
local unit caster = GetTriggerUnit()
local unit target = GetSpellTargetUnit()
local effect burning = AddSpecialEffectTarget("Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl", target, "origin") //Эффект горения
//Сохраняем все переменные в хэш//
call SaveAgentHandle(udg_hash, hid, 0, caster)
call SaveAgentHandle(udg_hash, hid, 1, target)
call SaveAgentHandle(udg_hash, hid, 2, burning)
call SaveReal(udg_hash, hid, 3, 0.) //Время
//==============================================//
call TimerStart(t, 1., true, function Trig_Burning_Timer) //Запускаем периодический таймер
set t = null
set caster = null
set target = null
set burning = null
endfunction

function InitTrig_Burning takes nothing returns nothing
set udg_hash = InitHashtable()
set gg_trg_Burning = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Burning, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Burning, Condition(function Trig_Burning_Condition))
call TriggerAddAction(gg_trg_Burning, function Trig_Burning_Actions)
//Здесь я просто отключу туман войны
call FogEnable(false)
call FogMaskEnable(false)
//==================================
endfunction[/code]

Я пометил комментариями все важные участки кода, которые и заставляют работать наш спелл. Обращу внимание на то, что периодические таймеры обязательно надо ставить на паузу перед уничтожением. Большинство спеллов на таймере представляют собой некоторое количество (зачастую очень большое) конструкций проверки условий (if then else) и действий, которые будут происходить после выполнения (или невыполнения) условия(-й). Так как я думаю, что из-за комментариев в коде бъяснять уже нечего, давайте отвлечемся от практики и окунемся в теорию. Мы с Вами займемся изучением некоторых кодерских фич, которые здорово облегчат и, зачастую, убыстрят ваш код. :)



Финт №1

Допустим, у нас есть функция, возвращающая какой-то тип (например, число):
[code=jass]function abc takes nothing returns integer
return 666
endfunction[/code]
До сих пор если бы Вам сказали занести это число в хэш, вы бы сделали так:
[code=jass]local integer def = abc()
call SaveInteger(udg_hash, 0, 0, def)[/code]
Так можно, но кодеры со стажем обходят этап выделения памяти под переменную, которая будет просто сохранена в хэш. Ну а зачем? Делаем так:
[code=jass]call SaveInteger(udg_hash, 0, 0, abc())[/code]
Так как функция возвращает значение, то она может вернуть его в аргумент функции, то есть мы можем не выделять память под локальную переменную, а просто сохранить в хэш возвращенное значение :) Так же вы можете сохранять в хэш составные операции, напрмер сложение строк, арифметические операции с числами (с точкой и без), например:
[code=jass]call SaveInteger(udg_hash, 0, 0, abc() + 1)[/code]
сохранит в хэш число 667.



Финт №2


Возьмем все тот же спелл из статьи. У нас есть время, к которому мы прибавляем секунду, пока оно не станет больше либо равно 7. Так как в начале спелла время у нас равно 0 секунд, то мы можем не сохранять значение в хэш. Почему? При загрузке несуществующего значения из ячейки хэш-таблицы, мы получаем null. У числа он эквивалентен 0, у реальной - 0.000, у логической - false, а у типов-наследников handle или widget - ничему, то есть null. Согласно этому, в действиях мы можем не сохранять значение 0. в хэш, а уж тем более не выделять под него область памяти (см. Финт 1).

А теперь давайте перепишем наш код, использую полученные знания:
[code=jass]function Trig_Burning_Condition takes nothing returns boolean
return GetSpellAbilityId() == 'A000'
endfunction

function Trig_Burning_Timer takes nothing returns nothing
local timer t = GetExpiredTimer()
local integer hid = GetHandleId(t)
//Грузим сохраненные переменные
local unit caster = LoadUnitHandle(udg_hash, hid, 0)
local unit target = LoadUnitHandle(udg_hash, hid, 1)
local real time = LoadReal(udg_hash, hid, 3) //Мы не сохранили значение, поэтому получаем null, то есть 0.000
if time <= 7. then //Если время меньше семи, то
//мы наносим цели урон
call UnitDamageTarget(caster, target, 20., true, false, ATTACK_TYPE_NORMAL, DAMAGE_TYPE_NORMAL, WEAPON_TYPE_WHOKNOWS)
if GetWidgetLife(target) > .405 then //Если у цели есть еще здоровье, то
call SaveReal(udg_hash, hid, 3, time + 1.) //Сохраняем время, увеличенное на 1 секунду в хэш
else //Если цель мертва, то мы
call PauseTimer(t) //Ставим таймер на паузу (!!ОБЯЗАТЕЛЬНО ДЛЯ ПЕРИОДИЧ. ТАЙМЕРОВ!!)
call DestroyTimer(t) //Уничтожаем таймер
call DestroyEffect(LoadEffectHandle(udg_hash, hid, 2)) //Функция уничтожения берет эффект и вызывается один раз. Зачем переменная?
call FlushChildHashtable(udg_hash, hid) //Чистим хэш
endif
else //Если время больше 7, то все делаем аналогично:
call PauseTimer(t) //Ставим таймер на паузу (!!ОБЯЗАТЕЛЬНО ДЛЯ ПЕРИОДИЧ. ТАЙМЕРОВ!!)
call DestroyTimer(t) //Уничтожаем таймер
call DestroyEffect(LoadEffectHandle(udg_hash, hid, 2)) //Функция уничтожения берет эффект и вызывается один раз. Зачем переменная?
call FlushChildHashtable(udg_hash, hid) //Чистим хэш
endif
set t = null
set caster = null
set target = null
endfunction

function Trig_Burning_Actions takes nothing returns nothing
local timer t = CreateTimer()
local integer hid = GetHandleId(t)
local unit target = GetSpellTargetUnit()
//Сохраняем все переменные в хэш//
call SaveAgentHandle(udg_hash, hid, 0, GetTriggerUnit()) //Кастер появился один раз, переменная не нужна
call SaveAgentHandle(udg_hash, hid, 1, target) //А вот цель нужна будет для создания эффекта, поэтому она в переменной
//Функция создания эффекта вернет нам тип effect, который мы спойкойно сохраняем в хэш
call SaveAgentHandle(udg_hash, hid, 2, AddSpecialEffectTarget("Environment\\LargeBuildingFire\\LargeBuildingFire1.mdl", target, "origin"))
//==============================================//
call TimerStart(t, 1., true, function Trig_Burning_Timer) //Запускаем периодический таймер
set t = null
set target = null
endfunction

function InitTrig_Burning takes nothing returns nothing
set udg_hash = InitHashtable()
set gg_trg_Burning = CreateTrigger()
call TriggerRegisterAnyUnitEventBJ(gg_trg_Burning, EVENT_PLAYER_UNIT_SPELL_EFFECT)
call TriggerAddCondition(gg_trg_Burning, Condition(function Trig_Burning_Condition))
call TriggerAddAction(gg_trg_Burning, function Trig_Burning_Actions)
//Здесь я просто отключу туман войны
call FogEnable(false)
call FogMaskEnable(false)
//==================================
endfunction[/code]

На этом я заканчиваю и готов отвечать на любые вопросы в комментах к статье. Всего вам хорошего, до встречи!

by Max Karelov aka Ty3uK
Просмотров: 1944 Добавил: Ty3uK Добавлено: 15 Марта 2013 в 20:45:04
Комментариев: 6 |

Всего комментариев: 6
16 Августа 2014
6. Проскурин Илья Владимирович (shekspire996) [Материал]
Мда, я ничего не понял, хотя хорошо разбираюсь в тригерах.

19 Июня 2013
5. Эрик ((ZFT)T_D) [Материал]
Помогите сделать этот скил пасивкой..я попытался но не удалось..пожалуйста

17 Июня 2013
4. Эрик ((ZFT)T_D) [Материал]
Спасибо за статью:) А если сделать из нее "стрелы хускара" (ну накидывать постоянно чтобы эффект складывался), то не будет ошибок связанных с хэш? а то я не так силен в jass...
Ответ: Нет, при использовании хэша и таймера никаких ошибок в накладывании эффектов и урона не будет.

25 Апреля 2013
С оптимизацией было бы лучше, хоть даже и непонятно для некоторых.

15 Марта 2013
2. Максим Карелов (Ty3uK) [Материал]
Статья расчитана на новичков, я не хотел грузить ее "дедовскими" способами оптимизации. :)
Ответ: Понятно, спасибо! :)

15 Марта 2013
1. Simplar Duoson (Duosora) [Материал]
Оформление: 5/5
Использованы цветовые выделения, ВВ-коды и спойлеры, код запихнулся туда, куда надо. Как и в Части 1, придраться не к чему. Шрифт Georgia очень здесь хорошо пошёл, получилось довольно недурно оформленная статья.

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

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

Всего: 5/5
Определённо, объективно нравится то, что делает автор подобных статей.
Статья прошла модерацию.

//===========
Один вопрос: почему весь код нельзя было запихнуть в блок Conditions и сделать его тем самым асинхронным? :)

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

Форма входа

Поиск

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

Случайный файл
[21 Июня 2008]
[Replay · С чемпионатов ?х?]
Dreamhack Summer -
Пак с самыми интересными играми с турнира Dreamhack Summer 2008 WC3 clanwar.

Новые карты
[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 ]
[ РеКсАр ] [ 27 ]

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

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

Статистика

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