|
|
|
|
Учимся Enum'ить декорации без локальных ректов
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 12:07:30 | Сообщение # 1 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Всем доброго утра/дня/вечера/ночи. Недавно я учил свои заклинания корректно работать с окружающим миром, и конечно же встал вопрос: а как же можно делать выборку дектораций без локальных ректов? Напомню, что основополагающая функция выбора дектораций - это функцияCode native EnumDestructablesInRect takes rect r, boolexpr filter, code actionFunc returns nothing она собирает декорации в определенном ректе. Все сразу же подумали "ну а что такого-то в локальных ректах? создаем, удаляем, эка невидаль". Ан нет, мои друзья, ректы сильно грузят процессор (доходит до такого, что спелл без утечек начинает лагать как первый опыт гуишника по созданию "ультрамегагиперкрутого заклинания"). Я нашел выход (возможно, их может быть и несколько, мне пришел в голову только один). О нем ниже.
Итак, какой же способ я придумал? А все очень просто - мы выбираем все декорации на карте с помощью статичного глобального ректа bj_mapInitialPlayableArea, высчитываем расстояние между взятой декорацией и точкой, от которой идет отсчет, и, если она удовлетворяет нашим требованиям - мы производим с ней действия. Немного полистав учебник геометрии и вспомнив из векторной геометрии, как можно вычислить расстояние между координатами, я написал такую функцию:Code function GetDistanceBetweenCoords takes real x1, real y1, real x2, real y2 returns real return SquareRoot((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)); endfunction которая возвращает нам расстояние между координатами. Итак, ядро у нас есть, давайте накинем на него "мяска". Полный листинг своего спелла я приводить не буду (вы можете увидеть его в моей карте Simple Shooter под названием MK209), приведу лишь необходимую часть кода:Code function Trig_Example_Enum takes nothing returns nothing local destructable d = GetEnumDestructable() // Берем декорацию и начинаем проверять расстояние между ней и юнитом в переменной if GetDistanceBetweenCoords(GetWidgetX(d), GetWidgetY(d), GetWidgetX(udg_someUnit), GetWidgetY(udg_someUnit)) <= 300. then call KillDestructable(d) endif set d = null endfunction
function Trig_Example_Conditions takes nothing returns boolean if GetSpellAbilityId() == 'ANcl' then set udg_someUnit = GetTriggerUnit() // Прошу прощения за глобалку, мне было лень писать пример через хэш :/ call EnumDestructablesInRect(bj_mapInitialPlayableArea, null, function Trig_Example_Enum) // Набираем декорации и делаем с ними что-нибудь через объявленную функу endif return false endfunction Итак, что мы сделали? Занесли кастера в переменную, выбрали все декорации на карте и после сравнения расстояния убили все декорации в радиусе 300. от юнита. "Систему" можно совершенствовать как угодно (например, через сравнение GetDestructableTypeId() сравнивать тип декорации и уничтожать только деревья), все ограничено только вашей фантазией. К... Кхм... "Статье" я приложил карту-пример. Спасибо всем за внимание, до новых встреч
Maxim Karelov aka Ty3uK © 2012
Сообщение отредактировал Ty3uK - Четверг, 15 Марта 2012, 12:11:06 |
|
|
|
Borodach | Дата: Четверг, 15 Марта 2012, 12:25:56 | Сообщение # 2 |
9 уровень
Группа: Проверенные
Сообщений: 930
Награды: 0
Репутация: 422
Блокировки:
| В некоторых картах декора доходит до 10 000 и мне кажется что 10 000 проверок не меньше грузит чем 1 рект. В общем расчитано на не большые карты и это изобретение велосипеда, так как уже такое видел
Karamba
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 12:29:03 | Сообщение # 3 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Borodach, линк. Это раз. Два - на некоторых картах юнитов доходит до 30000, но все равно лучше юзатьCode unit target; group g = CreateGroup(); GroupEnumUnitsInRange(g, x, y, 300., null); loop{ target = FirstOfGroup(g) exitwhen target == null KillUnit(target); GroupRemoveUnit(g, target); }; Нападки бессмысленны
|
|
|
|
Impregnable | Дата: Четверг, 15 Марта 2012, 12:34:34 | Сообщение # 4 |
6 уровень
Группа: Проверенные
Сообщений: 231
Награды: 0
Репутация: 92
Блокировки:
| Я хотел сделать такое для юнитов, но при тестирования карты, где находилось примерно 200 юнитов, вар просто завис. А если перебирать все декорации, число которых может достигать 2000, то страшно подумать что будет...
P.S. Тты сам то тестировал свою карту не на 150 декораций?
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 12:46:51 | Сообщение # 5 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Impregnable, я тестировал луп юнитов на овер 5000к боевых единиц Добавлено (15 Март 2012, 12:46:51) --------------------------------------------- Если кто-то сомневается, то взгляните на это.
|
|
|
|
Impregnable | Дата: Четверг, 15 Марта 2012, 12:52:15 | Сообщение # 6 |
6 уровень
Группа: Проверенные
Сообщений: 231
Награды: 0
Репутация: 92
Блокировки:
| Попробуй: Code function Test_Enum takes nothing returns nothing if GetDistanceBetweenCoords(0., 0., GetWidgetX(GetEnumDestructable()), GetWidgetY(GetEnumDestructable())) <= 300. then endif endfunction
function Test takes nothing returns nothing call EnumDestructablesInRect(bj_mapInitialPlayableArea, null, function Test_Enum) endfunction
function InitTrig_Test takes nothing returns nothing local integer i = 0
loop call TimerStart(CreateTimer(), .05, true, function Test)
exitwhen i == 9 set i = i + 1 endloop endfunction ИCode function Test_Enum takes nothing returns nothing if GetDistanceBetweenCoords(0., 0., GetWidgetX(GetEnumDestructable()), GetWidgetY(GetEnumDestructable())) <= 300. then endif endfunction
function Test takes nothing returns nothing local rect rct = Rect(0., 0., 1700., 1700.)
call EnumDestructablesInRect(rct, null, function Test_Enum)
call RemoveRect(rct) set rct = null endfunction
function InitTrig_Test takes nothing returns nothing local integer i = 0
loop call TimerStart(CreateTimer(), .05, true, function Test)
exitwhen i == 9 set i = i + 1 endloop endfunction И не надо писать, что создается 10 таймеров, это никак не влияет.
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 12:57:25 | Сообщение # 7 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Impregnable, я кинул ссылку. Смотри на то, что я кинул, там проблем нет. А если там нет проблем и лагов, то не надо мне "лечить" мозг Добавлено (15 Март 2012, 12:57:25) --------------------------------------------- Я считаю, что если мой пример работает (и работает без лагов), то больше мне ничего знать не надо. Тем более я просто не могу понять, на кой ляд тут таймер. Ну и чтобы окончательно заовнить, так сказать, вот мой спелл. В нем каждые .04 происходит энум дектораций (коих у меня на карте овер 1к) и ничего не лагает. Code private void Enum() { timer t = GetExpiredTimer(); int hid = GetHandleId(t); destructable d = GetEnumDestructable(); real x1 = GetWidgetX(d); real y1 = GetWidgetY(d); real x2 = GetWidgetX(LoadUnitHandle(hash, hid, 1)); real y2 = GetWidgetY(LoadUnitHandle(hash, hid, 1)); int id = GetDestructableTypeId(d); if GetDistanceBetweenCoords(x1, y1, x2, y2) <= 200. && destr { KillAndRemoveDestructable(d); if !LoadBoolean(hash, hid, -2) { SaveBoolean(hash, hid, -2, true); }; }; flush locals; }; private void Timer() { timer t = GetExpiredTimer(); int hid = GetHandleId(t); unit caster = LoadUnitHandle(hash, hid, 0); int i = 1; unit u; real angle; real dist; real x; real y; while(i < 21){ u = LoadUnitHandle(hash, hid, i); angle = GetUnitFacing(u); dist = LoadReal(hash, GetHandleId(u), hid); x = GetWidgetX(u); y = GetWidgetY(u); SetUnitPosition(u, x + 25. * Cos(angle * .017), y + 25. * Sin(angle * .017)); SaveReal(hash, GetHandleId(u), hid, dist + 25.); i++; }; i = 1; if dist >= 350. { for(unit target; UnitsInRange(GetWidgetX(caster), GetWidgetY(caster), 700.) use temp){ if enemy(target, caster) && dead(target){ damage(caster, target, 15.); }; }; while(i < 21){ u = LoadUnitHandle(hash, hid, i); x = GetWidgetX(u); y = GetWidgetY(u); RemoveUnit(u); DestroyEffect(AddSpecialEffect(GRENADEboom, x, y)); RemoveSavedReal(hash, GetHandleId(u), hid); i++; }; PauseTimer(t); DestroyTimer(t); FlushChildHashtable(hash, hid); }; flush locals; }; private bool Act() { if GetSpellAbilityId() == GRENADEid { timer t = CreateTimer(); int hid = GetHandleId(t); unit caster = GetTriggerUnit(); real x = GetWidgetX(caster); real y = GetWidgetY(caster); real angle = 0.; int i = 1; SaveAgentHandle(hash, hid, 0, caster); while(angle < 360.){ SaveAgentHandle(hash, hid, i, CreateUnit(GetTriggerPlayer(), GRENADE, x, y, angle)); i++; angle += 18.; }; TimerStart(t, .04, true, function Timer); lastWeapon[GetPlayerId(GetTriggerPlayer())] = "Grenade Launcher" }; flush locals; return false; };
|
|
|
|
Impregnable | Дата: Четверг, 15 Марта 2012, 13:11:07 | Сообщение # 8 |
6 уровень
Группа: Проверенные
Сообщений: 231
Награды: 0
Репутация: 92
Блокировки:
| Правильно не лагает, ведь если бы вар лагал при выполнении такого количества действий, то было бы очень печально. А таймеры имитируют работу одновременно нескольких спеллов, систем и прочих действий. В игре же не будет так, как ты тестируешь - 1 игрок применил способность, прошла секунда, 2 применил и еще кроме самих способностей в данный момент ничего не работает. Разве так бывает?
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 13:18:21 | Сообщение # 9 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Impregnable, бывает, вчера тестировали эту систему на моей карте 3х3, спелл кастовался с частотой раз в 5 секунд практически всеми игроками. Все ок
|
|
|
|
Impregnable | Дата: Четверг, 15 Марта 2012, 13:21:57 | Сообщение # 10 |
6 уровень
Группа: Проверенные
Сообщений: 231
Награды: 0
Репутация: 92
Блокировки:
| Ладно. Я уже понял, что с тобой спорить бесполезно. Раз так, то спроси у SirNikolas. Как он скажет так и делай...
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 13:24:24 | Сообщение # 11 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| Impregnable, я так и собирался, надеюсь Ник посетит эту тему Добавлено (15 Март 2012, 13:24:24) --------------------------------------------- Бтв, Скорп на хгм никаких претензий не выставил и сказал, что все ок. Внезапно
|
|
|
|
vov68 | Дата: Четверг, 15 Марта 2012, 13:30:19 | Сообщение # 12 |
10 уровень
Группа: Проверенные
Сообщений: 1329
Награды: 3
Блокировки:
| Quote (Ty3uK) радиусе 300. от юнита. если мерить в стандартных деревьев, то это 20 штук. такое количество можно и без джасса.
Зачем делать для других новые карты... ... лучше устроить коту божественный почесон. :)
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 13:50:50 | Сообщение # 13 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| vov68, прости, но тут не шаришь
Сообщение отредактировал Ty3uK - Четверг, 15 Марта 2012, 13:53:31 |
|
|
|
vov68 | Дата: Четверг, 15 Марта 2012, 14:09:54 | Сообщение # 14 |
10 уровень
Группа: Проверенные
Сообщений: 1329
Награды: 3
Блокировки:
| Quote (Ty3uK) прости, но тут не шаришь да куды ж нам лопоухим то.
Quote (Ty3uK) Немного полистав учебник геометрии и вспомнив из векторной геометрии, как можно вычислить расстояние между координатами, я написал такую функцию: вообще-то есть локальная переменная - расстояние между точками
Зачем делать для других новые карты... ... лучше устроить коту божественный почесон. :)
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 14:12:37 | Сообщение # 15 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| vov68, ты смотрел ее начинку? То-то же
|
|
|
|
vov68 | Дата: Четверг, 15 Марта 2012, 14:20:36 | Сообщение # 16 |
10 уровень
Группа: Проверенные
Сообщений: 1329
Награды: 3
Блокировки:
| Quote (Ty3uK) ты смотрел ее начинку? чью начинку?
Зачем делать для других новые карты... ... лучше устроить коту божественный почесон. :)
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 14:27:33 | Сообщение # 17 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| vov68, функции получения расстояния между точками, про которую ты судачишь
|
|
|
|
SirNikolas | Дата: Четверг, 15 Марта 2012, 14:37:04 | Сообщение # 18 |
Группа: Модераторы
Сообщений: 6729
Награды: 1
Репутация: 1867
Блокировки:
| GetWidgetXY(udg_someUnit) - в глобалки.
А тебе не кажется, что лучше иметь один глобальный рект и двигать его куда надо?
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 14:43:53 | Сообщение # 19 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| SirNikolas, для муишности на всех не напасешься, как думаешь? Добавлено (15 Март 2012, 14:43:53) --------------------------------------------- SirNikolas, и, бтв, что вообще скажешь?
|
|
|
|
SirNikolas | Дата: Четверг, 15 Марта 2012, 14:58:44 | Сообщение # 20 |
Группа: Модераторы
Сообщений: 6729
Награды: 1
Репутация: 1867
Блокировки:
| Quote (Ty3uK) для муишности на всех не напасешься Более одной области требуется только если совершается пик в пике. И то не уверен, надо тестировать.
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 15:03:00 | Сообщение # 21 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| SirNikolas, да, я тут на хгм спросил - ты был прав, лучше делать через движение региона. Завтра перепишу "статью"
|
|
|
|
vov68 | Дата: Четверг, 15 Марта 2012, 15:04:29 | Сообщение # 22 |
10 уровень
Группа: Проверенные
Сообщений: 1329
Награды: 3
Блокировки:
| Quote (Ty3uK) функции получения расстояния между точками, про которую ты судачишь как джазист я её не смотрел, но в ней учитывается наличие порталов на пути и всяких сокращалок. данная функция вообще-то предназначена для прокладки пути юнитов.
но на расстоянии 300, думаю, порталов работающих внутри этого расстояния не будет.
Зачем делать для других новые карты... ... лучше устроить коту божественный почесон. :)
|
|
|
|
SirNikolas | Дата: Четверг, 15 Марта 2012, 15:08:53 | Сообщение # 23 |
Группа: Модераторы
Сообщений: 6729
Награды: 1
Репутация: 1867
Блокировки:
| vov68, это самая обыкновенная тригонометрическая функция. sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2). Да и было бы странно, если бы плазменная пушка уничтожала деревья, находящиеся рядом с точкой выхода портала.
|
|
|
|
Ty3uK | Дата: Четверг, 15 Марта 2012, 15:12:30 | Сообщение # 24 |
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
| SirNikolas, Снеси тогда топан, я дико ступил -_____-
Сообщение отредактировал Ty3uK - Четверг, 15 Марта 2012, 15:14:02 |
|
|
|
vov68 | Дата: Четверг, 15 Марта 2012, 15:23:31 | Сообщение # 25 |
10 уровень
Группа: Проверенные
Сообщений: 1329
Награды: 3
Блокировки:
| SirNikolas я здесь с одной дурью столкнулся, называется - разброс стартовых позиций (не локаций) игроков одного клана. там конечно учитывается наикратчайшее расстояние между уже установленными позициями и будущей. так вот - если имеется порталы между хотя бы одним из будущих возможных стартовых позиций (а проще говоря установленными локациями), и этот портал делает расстояние меньше, чем у других возможных, то будет взят путь по порталу. проверено на практике неоднократно. вопрос - где зарыта собака?[
Зачем делать для других новые карты... ... лучше устроить коту божественный почесон. :)
Сообщение отредактировал vov68 - Четверг, 15 Марта 2012, 15:24:09 |
|
|
|
|
|
|
|
|
|
|