XGM Forum
Сайт - Статьи - Проекты - Ресурсы - Блоги

Форуме в режиме ТОЛЬКО ЧТЕНИЕ. Вы можете задать вопросы в Q/A на сайте, либо создать свой проект или ресурс.
Вернуться   XGM Forum > Warcraft> Академия: форум для вопросов> Jass
Ник
Пароль
Войти через VK в один клик
Сайт использует только имя.

Ответ
 
Markiz

offline
Опыт: 11,432
Активность:
Маленькие хитрости, здорово облегчающие жизнь
Вот у меня тут накопилось немного материала, этакий mini-faq, на статью его явно не хватает, но если дополнить, то мбмб.
Собственно, у каждого джассера есть свои какие-то приемы, фишки, которые он использует. Вот пара приемов от меня, не скажу, что Америку открыл или колесо изобрел, но многие и не знают:
1. Перебор группы без ForGroup().
a) Когда надо просто перебрать группу:
Код:
//Для примера полечим всех живых юнитов в области 300
local location loc=GetSpellTargetLoc()
local group g=GetUnitsInRangeOfLocMatching(300, loc, null)
local unit u
local player p=GetOwningPlayer(GetSpellAbilityUnit())
 loop
  set u=FirstOfGroup(g)
  exitwhen u==null
  call GroupRemoveUnit(g,u)
//Три операции выше и характеризуют описываемый метод, мы берем каждого юнита из группы по порядку
  if (not (IsUnitEnemy(u,p))) and (IsUnitType(u,UNIT_TYPE_STRUCTURE)) then
   call SetWidgetLife(u,GetWidgetLife(u)+100)
  endif
 endloop
 call RemoveLocation(loc)
 call DestroyGroup(g)
set loc=null
set u=null

b) Когда нужно сохранить содержимое группы
Банальное заведение второй переменной и присваивание ей значение первой не помогает. Тогда в конец тела цикла вставляем такой кусок кода:
Код:
loop
  ...
  call GroupAddUnit(g2,u)
 endloop

2. Return Array
Вы думаете это невозможно? Да, это в принципе невозможно, но есть способы вернуть массив. Предположим у нас есть некоторая функция, возвращающая массив точек (неважно, зачем у нас такая функция). Чтобы реализовать ее, мы воспользуемся эффектной комбинацией Stack+Return Bug:
Код:
globals
 integer udg_StackN=0
 integer array udg_Stack
endglobals
...
//Custom Code Section
function H2I takes handle h returns integer
 return h
 return 0
endfunction

function I2Loc takes integer i returns location
 return i
 return null
endfunction

function Push takes integer i returns nothing
 set udg_StackN=udg_StackN+1
 set udg_Stack[udg_StackN]=i
endfunction 

function Pop takes nothing returns integer
 set udg_StackN=udg_StackN-1
 return udg_Stack[udg_StackN+1]
endfunction
//End of Custom Code Section
function MyFunc takes params returns integer //params - аргументы функции
local integer i
local integer j=0
local location array locs
 ...
 //Вот мы получили массив locs и знаем, что всего элементов в нем i
 loop
  exitwhen j>=i
  call Push(H2I(locs[j]))
  set j=j+1
 endloop
 return i
endfunction

function GetArray takes nothing returns nothing
local integer i=MyFunc() //Получаем кол-во аргументов в стеке
local integer j=0
local location array locs
 loop
  exitwhen j>=i
  set locs[j]=I2Loc(Pop())
  set j=j+1
 endloop
 //Вуаля! Мы получили массив точек из функции MyFunc
endfunction

3. CastSpell noCache
Ну тут все совсем просто. Во всех виденных мною реализациях функции CastSpell (кастует нужный спелл) использовался кэш, чтобы удалить кастера, когда он не нужен в то время, как есть юолее красивое решение, не требующее отдельного потока и кэша:
Код:
call SetUnitExploded(caster, true)
call UnitApplyTimedLife(caster, 'X000', 10илискольковамнадомаксимум)

По последней информации SetUnitExploded ремувит юнита после смерти, вот так-то.
У меня все, жду дополнений.
Старый 04.07.2006, 21:18
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Цитата:
if (not (IsUnitEnemy(u,p))) and (IsUnitType(u,UNIT_TYPE_STRUCTURE)) then
call SetWidgetLife(u,GetWidgetLife(u)+100)

Имхо это можно было сделать сразу в фильтре группы... т.е. не брать врагов и билдинсов и п.р.
Цитата:
call SetUnitExploded(caster, true)
call UnitApplyTimedLife(caster, 'X000', 10илискольковамнадомаксимум)

А ты уверен что движок очистит память, а не просто убьет юнита?
Старый 05.07.2006, 09:36
Sir Lothar

offline
Опыт: 5,740
Активность:
Цитата:
А ты уверен что движок очистит память, а не просто убьет юнита?

Вот-вот. Если нет, то получится утечка памяти...
Старый 05.07.2006, 10:01
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Цитата:
Вот-вот. Если нет, то получится утечка памяти...

Туту конечно с обдной стороны разумно, зачем хранить взорванного юнита? Его косточки уже никуда не будут использдваны... а вот если взорванных юнитов можно возраждать всякой бякой как у Палыча, то движок все равно будет хранить координаты...
Старый 05.07.2006, 10:04
Markiz

offline
Опыт: 11,432
Активность:
Цитата:
Имхо это можно было сделать сразу в фильтре группы... т.е. не брать врагов и билдинсов и п.р

Чтобы передать в фильтр игрока, тебе придется юзать глобалку/кэщ.
В 3 пункте про explode я уже все написал вообще-то.
Старый 05.07.2006, 18:25
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Цитата:
Чтобы передать в фильтр игрока, тебе придется юзать глобалку/кэщ.

Ха, что тебе мешает объявить локалку игрока до создания группы?

exploder добавил:
Цитата:
В 3 пункте про explode я уже все написал вообще-то.

Написано что сие есть красивое решение, но не написано реально это работает или просто очередная бредятина...
Старый 05.07.2006, 20:49
Markiz

offline
Опыт: 11,432
Активность:
exploder
Цитата:
Ха, что тебе мешает объявить локалку игрока до создания группы?

Не вижу разницы. Имхо удобнее так.
Цитата:
Написано что сие есть красивое решение, но не написано реально это работает или просто очередная бредятина...

Теперь перечитай то, что написал и посмейся.
Старый 05.07.2006, 20:51
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Цитата:
Теперь перечитай то, что написал и посмейся.

угу не заметиль =)) А точно? Проверенно? =))
Цитата:
Не вижу разницы. Имхо удобнее так.

Имхо удобнее через фильтр группы, не просто удобнее - логичнее, лучше всегда сразу отбрасывать не нужных юнитов, занимать меньше памяти, да и цикл будет крутится меньшее количество раз, не будет "пустых" проходов, когда мы нарвавшись на вражину не делаем ничего, а запускаем следующий виток...

exploder добавил:
Так что разница есть, и иногда очень существенная...
Старый 05.07.2006, 20:55
Markiz

offline
Опыт: 11,432
Активность:
exploder
нету там разницы. по сути варкрафту тоже приходится проходить циклом по группе и вычеркивать лишних, не удовлетворяющих условию. Не веришь? Втыкай код GetUnitsInRangeOfLocMatching в B.J
Старый 06.07.2006, 00:42
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Цитата:
Втыкай код GetUnitsInRangeOfLocMatching в B.J

А сам то фтыкал?
Цитата:
function GetUnitsInRangeOfLocMatching takes real radius, location whichLocation, boolexpr filter returns group
local group g = CreateGroup()
call GroupEnumUnitsInRangeOfLoc(g, whichLocation, radius, filter)
call DestroyBoolExpr(filter)
return g
endfunction

Причем:
Цитата:
native GroupEnumUnitsInRangeOfLoc takes group whichGroup, location whichLocation, real radius, boolexpr filter returns nothing

Ну и где цикл на джасс? Что я его не вижу...

exploder добавил:
Фильтрация происходит в коде игры и уж наверно намного быстрей чем на джасс...
Старый 06.07.2006, 10:36
Markiz

offline
Опыт: 11,432
Активность:
exploder
Все, убедил :)
Но я до сих пор не совсем понимаю, каким куском кода ты сам хочешь это заменить :dunno:
Старый 06.07.2006, 14:42
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Markiz, то то же =)) Завтра напишу сегедня времени совсем нет... Короч в двух лсовах создаешь кондишен функцию, и пихаешь ее вместо булекспр в фильтр...

Отредактировано exploder, 06.07.2006 в 21:42.
Старый 06.07.2006, 21:26
Markiz

offline
Опыт: 11,432
Активность:
exploder
Пфф.
Ну а как ты просунешь локалку туда, а, друг мой?
Старый 07.07.2006, 00:46
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Цитата:
Ну а как ты просунешь локалку туда, а, друг мой?

Зачем? Мы прямо в функции возмем то, что нам нужно, точно также также:
local player p=GetOwningPlayer(GetSpellAbilityUnit()), но тогда уже нам не придется писать эту строку в основной функии, т.к. там сы уже ничего не фильтруем...
Старый 07.07.2006, 09:43
Markiz

offline
Опыт: 11,432
Активность:
exploder
бред. зачастую группа генерируется по ходу выполнения функции, когда в GetSpellAbilityUnit() давно лежит всякий трэш.
Старый 07.07.2006, 13:34
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
//===================================================
function MyFilter takes nothing returns boolean
return (IsUnitEnemy(GetFilterUnit(), GetOwningPlayer(GetSpellAbilityUnit())) == false )
endfunction
//===================================================
local location loc=GetSpellTargetLoc()
local group g=GetUnitsInRangeOfLocMatching(300, loc, Condition(function MyFilter))
local unit u
loop
set u=FirstOfGroup(g)
exitwhen u==null
call GroupRemoveUnit(g,u)
call SetWidgetLife(u,GetWidgetLife(u)+100)
endloop
call RemoveLocation(loc)
call DestroyGroup(g)
set loc=null
set u=null
//===================================================

exploder добавил:
Если триггер срабатывает по событию каста, то функция GetSpellAbilityUnit() будет всегда возвращать то что нужно...
Старый 07.07.2006, 14:10
Markiz

offline
Опыт: 11,432
Активность:
exploder
до первого PolledWait()/TriggerSleepAction()
Старый 07.07.2006, 17:28
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Цитата:
до первого PolledWait()/TriggerSleepAction()

Ну это естественно... но я думаю ты же не будешь вэйт фтыкать в фильтр?
Старый 07.07.2006, 20:54
Markiz

offline
Опыт: 11,432
Активность:
exploder
причем тут это? если эффект от закла не единовременный, то придется ставить вейт.
Старый 08.07.2006, 16:27
exploder
iOS zealot
offline
Опыт: 19,394
Активность:
Цитата:
причем тут это? если эффект от закла не единовременный, то придется ставить вейт.

Если бы, да ка бы... приведи пример, а то я плохо понимаю о чем ты. Все равно ты группу собираешь в момент каста...
Старый 09.07.2006, 20:46
Ответ

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы можете скачивать файлы

BB-коды Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход



Часовой пояс GMT +3, время: 23:58.