Четверг, 21.11.2024, 20:33


Главная
Регистрация
Вход
Welcome to Home Приветствую Вас Гость | RSS  
Меню сайта

Категории раздела
Мои статьи [25]

Мини-чат

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Главная » Статьи » Мои статьи

Hashtable - работаем с хеш-таблицей

Хеш-таблица — это структура данных, реализующая интерфейс ассоциативного массива, а именно, она позволяет хранить пары (ключ, значение) и выполнять три операции: операцию добавления новой пары, операцию поиска и операцию удаления пары по ключу. Не будем вдаваться в подробности принципа её работы, об этом вы можете прочитать здесь.

В статье мы рассмотрим самую распространённую область её применения в wc3: прикрепление данных к объекту, на простейшем примере. Статья предполагает, что читатель знаком с основами работы таймеров. Пример будет только на обычном Jass, для совместимости (да и не все умеют работать c v/cJass).

Если вы знакомы с кэшем в wc3, то принцип работы с ним схож, с принципом работы с хеш-таблицей. Только вместо строковых ключей, хеш-таблица использует целочисленные значения (integer).
Допустим, мы хотим создать спелл, в котором врагу на протяжении некоторого времени с малым периодом постоянно наносится урон (для которого wait не подходит).

Мы создали триггер (в редакторе триггеров, для простоты объяснения) с событием каста, дали ему условия и действия:

function Spell takes nothing returns nothing
 local unit caster = GetSpellAbilityUnit() //Кастер
 local unit target = GetSpellTargetUnit() //Цель
endfunction

//Проверка спелла
function SpellCond takes nothing returns boolean
 return GetSpellAbilityId()=='A000'
endfunction

//===========================================================================
function InitTrig_Spell takes nothing returns nothing
 set gg_trg_Spell = CreateTrigger()
 call TriggerRegisterPlayerUnitEvent(gg_trg_Spell,Player(0),EVENT_PLAYER_UNIT_SPELL_CAST,null)
 call TriggerAddCondition(gg_trg_Spell,Condition(function SpellCond))
 call TriggerAddAction(gg_trg_Spell,function Spell)
endfunction

Далее, нам нужен таймер, который будет периодически вызывать функцию, внутри которой наносится урон:

function SpellDamage takes nothing returns nothing
 call UnitDamageTarget(...)
endfunction

function Spell takes nothing returns nothing
 local unit caster = GetSpellAbilityUnit() //Кастер
 local unit target = GetSpellTargetUnit() //Цель
 local timer t = CreateTimer() //Создаём таймер
 
 call TimerStart(t,0.04,true,function SpellDamage) //Стартуем таймер
endfunction

Но как передать в функцию, кто кому должен наносить урон, и сколько раз? Тут нам на помощь и приходит хеш-таблица. Перед работой нужно создать и инициализировать глобальную хеш-таблицу, желательно при инициализации карты.

» *1

Делать это нужно только один раз, например в этом триггере:

function InitTrig_Spell takes nothing returns nothing
 set gg_trg_Spell = CreateTrigger()
 call TriggerRegisterPlayerUnitEvent(gg_trg_Spell,Player(0),EVENT_PLAYER_UNIT_SPELL_CAST,null)
 call TriggerAddCondition(gg_trg_Spell,Condition(function SpellCond))
 call TriggerAddAction(gg_trg_Spell,function Spell)
 
 set udg_hash = InitHashtable() //Инициализируем хеш-таблицу
endfunction

» *2

Работает хеш-таблица так: [ключ|значение]. Только как ключ мы используем уникальный id объекта, а точнее - id нашего таймера.
На него и будем сохранять нужные нам данные:

function Spell takes nothing returns nothing
 local unit caster = GetSpellAbilityUnit() //Кастер
 local unit target = GetSpellTargetUnit() //Цель
 local timer t = CreateTimer() //Создаём таймер
 local integer h = GetHandleId(t) //Узнаём id таймера
 
 //Сохраняем объекты с ключом - id таймера
 call SaveUnitHandle(udg_hash,h,1,caster) //Сохраняем кастера со значением 1
 call SaveUnitHandle(udg_hash,h,2,target) //Сохраняем цель со значением 2
 call SaveInteger(udg_hash,h,3,125) //Сохраняем количество ударов, из расчёта, что урон наносится в течение 5 секунд (5/0.04=125).
 
 call TimerStart(t,0.04,true,function SpellDamage) //Стартуем таймер
 
 //Не забываем устранять утечки
 set caster = null
 set target = null
 set t = null
endfunction

» *3

» *4

» *5

Готово, данные сохранены, теперь их можно будет достать в функции нанесения урона, на которую запущен таймер.
Доставать данные мы будем тоже по id таймера:

function SpellDamage takes nothing returns nothing
 local timer t = GetExpiredTimer() //Наш таймер - истёкший
 local integer h = GetHandleId(t) //Узнаём id таймера
 local unit caster = LoadUnitHandle(udg_hash,h,1) //Достаём кастера из значения 1
 local unit target = LoadUnitHandle(udg_hash,h,2) //Достаём цель из значения 2
 local integer counter = LoadInteger(udg_hash,h,3) //Достаём количество ударов
 
 if counter>0 then //Если количество ударов больше 0
 call UnitDamageTarget(caster,target,1.0,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null) //Наносим урон цели
 call SaveInteger(udg_hash,h,3,counter-1) //Сохраняем количество ударов, убавленное на 1
 else //Иначе 
 call DestroyTimer(t) //Уничтожаем таймер
 //Очищаем хеш-таблицу, чтобы избежать утечек и наложений
 call FlushChildHashtable(udg_hash,h) //Очищаем ключ по id
 endif
 
 //Не забываем устранять утечки
 set caster = null
 set target = null
 set t = null
endfunction

» *6

Спелл готов, данные записываются, достаются и удаляются из хеш-таблицы.
Вот что у нас получилось в итоге:

function SpellDamage takes nothing returns nothing
 local timer t = GetExpiredTimer()
 local integer h = GetHandleId(t)
 local unit caster = LoadUnitHandle(udg_hash,h,1)
 local unit target = LoadUnitHandle(udg_hash,h,2)
 local integer counter = LoadInteger(udg_hash,h,3)
 
 if counter>0 then
 call UnitDamageTarget(caster,target,1.0,true,true,ATTACK_TYPE_NORMAL,DAMAGE_TYPE_NORMAL,null)
 call SaveInteger(udg_hash,h,3,counter-1)
 else
 call DestroyTimer(t)
 call FlushChildHashtable(udg_hash,h)
 endif
 
 set caster = null
 set target = null
 set t = null
endfunction

function Spell takes nothing returns nothing
 local unit caster = GetSpellAbilityUnit()
 local unit target = GetSpellTargetUnit()
 local timer t = CreateTimer()
 local integer h = GetHandleId(t)
 
 call SaveUnitHandle(udg_hash,h,1,caster)
 call SaveUnitHandle(udg_hash,h,2,target)
 call SaveInteger(udg_hash,h,3,125)
 
 call TimerStart(t,0.04,true,function SpellDamage)
 
 set caster = null
 set target = null
 set t = null
endfunction

function SpellCond takes nothing returns boolean
 return GetSpellAbilityId()=='A000'
endfunction

//===========================================================================
function InitTrig_Spell takes nothing returns nothing
 set gg_trg_Spell = CreateTrigger()
 call TriggerRegisterPlayerUnitEvent(gg_trg_Spell,Player(0),EVENT_PLAYER_UNIT_SPELL_CAST,null)
 call TriggerAddCondition(gg_trg_Spell,Condition(function SpellCond))
 call TriggerAddAction(gg_trg_Spell,function Spell)
 
 set udg_hash = InitHashtable()
endfunction
Категория: Мои статьи | Добавил: Enemy1PK (02.04.2017)
Просмотров: 677 | Рейтинг: 0.0/0
Всего комментариев: 0
avatar
Вход на сайт

Поиск

Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • База знаний uCoz

  • Copyright MyCorp © 2024uCoz