Сейчас 16:13:28 Пятница, 29 марта, 2024 год
[ x ] Главная ⇒ Форум ⇐ RSS Файлы Cтатьи Картинки В о й т и   или   з а р е г и с т р и р о в а т ь с я


[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 2
  • 1
  • 2
  • »
Модератор форума: PUVer, SirNikolas, Ty3uK  
Форум о Warcraft 3 » Раздел для картостроителей » Раздел картостроителя » Учимся Enum'ить декорации без локальных ректов
Учимся 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


╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек


Сообщение отредактировал 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);
};
Нападки бессмысленны


╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

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)
---------------------------------------------
Если кто-то сомневается, то взгляните на это.


╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

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;
     };


╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

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 секунд практически всеми игроками. Все ок

╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

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)
---------------------------------------------
Бтв, Скорп на хгм никаких претензий не выставил и сказал, что все ок. Внезапно


╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

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, прости, но тут не шаришь

╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек


Сообщение отредактировал 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, ты смотрел ее начинку? То-то же

╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

vov68Дата: Четверг, 15 Марта 2012, 14:20:36 | Сообщение # 16
10 уровень
Группа: Проверенные
Сообщений: 1329
Награды: 3
Блокировки:
Quote (Ty3uK)
ты смотрел ее начинку?

чью начинку?


Зачем делать для других новые карты...
... лучше устроить коту божественный почесон. :)
 

Ty3uKДата: Четверг, 15 Марта 2012, 14:27:33 | Сообщение # 17
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
vov68, функции получения расстояния между точками, про которую ты судачишь

╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

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, и, бтв, что вообще скажешь?


╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

SirNikolasДата: Четверг, 15 Марта 2012, 14:58:44 | Сообщение # 20
Группа: Модераторы
Сообщений: 6729
Награды: 1
Репутация: 1867
Блокировки:
Quote (Ty3uK)
для муишности на всех не напасешься
Более одной области требуется только если совершается пик в пике. И то не уверен, надо тестировать.


 

Ty3uKДата: Четверг, 15 Марта 2012, 15:03:00 | Сообщение # 21
Группа: Ветераны
Сообщений: 6125
Награды: 2
Репутация: 1617
Блокировки:
SirNikolas, да, я тут на хгм спросил - ты был прав, лучше делать через движение региона. Завтра перепишу "статью" trollface

╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек
 

vov68Дата: Четверг, 15 Марта 2012, 15:04:29 | Сообщение # 22
10 уровень
Группа: Проверенные
Сообщений: 1329
Награды: 3
Блокировки:
Quote (Ty3uK)
функции получения расстояния между точками, про которую ты судачишь

как джазист я её не смотрел, но в ней учитывается наличие порталов на пути и всяких сокращалок.
данная функция вообще-то предназначена для прокладки пути юнитов. ;)

но на расстоянии 300, думаю, порталов работающих внутри этого расстояния не будет. :D


Зачем делать для других новые карты...
... лучше устроить коту божественный почесон. :)
 

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, trollface
Снеси тогда топан, я дико ступил -_____-


╭∩╮(︶︿︶)╭∩╮
"Ульта Тайда мне в жопу!" © k0fe1n
Статьи: MUI-1|MUI-2|Шрифт
Полезности: JASP|JNGP|Уголок библиотек


Сообщение отредактировал Ty3uK - Четверг, 15 Марта 2012, 15:14:02
 

vov68Дата: Четверг, 15 Марта 2012, 15:23:31 | Сообщение # 25
10 уровень
Группа: Проверенные
Сообщений: 1329
Награды: 3
Блокировки:
SirNikolas
я здесь с одной дурью столкнулся, называется - разброс стартовых позиций (не локаций) игроков одного клана. там конечно учитывается наикратчайшее расстояние между уже установленными позициями и будущей.
так вот - если имеется порталы между хотя бы одним из будущих возможных стартовых позиций (а проще говоря установленными локациями), и этот портал делает расстояние меньше, чем у других возможных, то будет взят путь по порталу.
проверено на практике неоднократно.
вопрос - где зарыта собака?[


Зачем делать для других новые карты...
... лучше устроить коту божественный почесон. :)


Сообщение отредактировал vov68 - Четверг, 15 Марта 2012, 15:24:09
 

Форум о Warcraft 3 » Раздел для картостроителей » Раздел картостроителя » Учимся Enum'ить декорации без локальных ректов
  • Страница 1 из 2
  • 1
  • 2
  • »
Поиск:

Copyright © 2006 - 2024 Warcraft3FT.info При копировании материалов c сайта ставьте, пожалуйста, активную обратную ссылку на нас • Design by gReeB04ki ©
Хостинг от uCoz