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


[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 1 из 2
  • 1
  • 2
  • »
Модератор форума: PUVer, SirNikolas, Ty3uK  
Форум о Warcraft 3 » Раздел для картостроителей » Раздел картостроителя » [Система]Система отталкивания
[Система]Система отталкивания
rixt7956Дата: Пятница, 14 Января 2011, 17:09:44 | Сообщение # 1
9 уровень
Группа: Проверенные
Сообщений: 1097
Награды: 0
Репутация: 153
Блокировки:
Использованны vJass и cJass, так что НУЖЕН JNGP с установленным AdicHelper!'
Система отталкивает юнитов, при этом учитываеться растояние от юнита до центра отталкивания, скорость их отталкивания, а
также при встрече с припятствиями юниты отлетают от них,но уже с меньшей скоростью.

Обновления
v1.1
  • Отличный рекошет (сделал 'SirNikolas')
  • Теперь юниты ещё реагируют на высоту рельефа. Если юнит отталкиваеться на гору то он начинает быстро тормозить, а если с горы то набирает скорость.
    v1.2
  • Стали доступны функции OTR_ConvertReal и OTR_Recochet
  • Система немного оптимизирована.
  • Значительно увеличина точность рекошета.
  • Дана возможность отключения спецэфекта, так как из-за него при отталкивание большого количества юнитов (более 30)
    начинаются небольшие лаги.(true - включить, false - выключить).
  • Дана возможность настроек параметров step и max. Если их не указывать будут использованны параметры по умолчанию.

    Импорт:
    Для использлвания в своей карте скопируйте триггер OTR.

    Функции:

    OTR_Start(unit u,real radius,real maxdist,boolean effecton,real step,real max) - отталкивает юнитов в определённом радиусе от юнита.
    Параметр maxdist рекомендую ставить 2000, он что то вроде импульса.
    radius - радиус от x;y координат юнита, выбранные все живые, вражесские юниты в нём будут отталкиваться.
    Вы можете не указывать параметры step и max тоесть можно также писать
    call OTR_Start(u,radius,maxdist,e) или только step call OTR_Start(u,radius,maxdist,e,step), при этом они будут установленны по умолчанию.
    step по умолчанию - .34907 ,а max - 3.1415926536. Анологично можно делать и в функциях OTR_StartXY и в OTR_GrUnit.

    OTR_StartXY(player p,real x,real y,real radius,real maxdist,boolean effecton,real step,real max)- отталкивает всех от точки, за исключением юнитов указанного игрока.
    OTR_GrUnit(unit u,real x,real y,real maxdist,real step,real max)- отталкивает определённого юнита.
    OTR_XYpr(real x,real y)- проверяет точку на проходимость.
    (Автор следущих двух функций [/b]SirNikolas)
    OTR_ConvertReal(real r,real min,real max)- возвращает число в указанном диапозоне.
    OTR_Ricochet(real x,real y,real angle,real dist,real step,real max) - определяет угол (в радианах!) по которому будет продолжать движение объект попадающий в точку (
    x;y) и движущийся под углом angle. Также она берёт доп. параметры.
    dist('Оптимальное значение - 15') - определяет, в каком радиусе нужно искать препятствие. При слишком высоких значениях функция может не заметить не большой объект, а
    при низких юнит будет рекошировать
    от малых шерховатостей, и следовательно, совсем в другую сторону.
    step('Оптимальное значение - .34907') - чем меньше это параметр , тем выше точность рикошета, но и лаги тоже увеличиваються
    max('Оптимальное значение - 3'(в радианах!)) - Показывает под каким максимальным углом следует искать препятствие. Если оно не будет найдено под этим углом, рикошет
    будет в сторону, противоположенную движение.



    Сообщение отредактировал rixt7956 - Пятница, 14 Января 2011, 17:09:58
  •  

    SirNikolasДата: Пятница, 14 Января 2011, 18:26:12 | Сообщение # 2
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Интересно, только я не понял, зачем выгружать данные из структуры в локалки?
    Quote (rixt7956)
    local unit u=h.u
    local real speed=h.speed
    local real angle=h.angle


     

    rixt7956Дата: Пятница, 14 Января 2011, 18:27:12 | Сообщение # 3
    9 уровень
    Группа: Проверенные
    Сообщений: 1097
    Награды: 0
    Репутация: 153
    Блокировки:
    SirNikolas, Мне так удобней, хотя тупанул
     

    SirNikolasДата: Пятница, 14 Января 2011, 18:27:56 | Сообщение # 4
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Можно еще модернизировать систему, сделав так, чтобы при столкновении юнит отлетал не всегда против часовой стрелки и не обязательно под углом в 45 градусов.



    Сообщение отредактировал SirNikolas - Суббота, 15 Января 2011, 07:13:54
     

    rixt7956Дата: Пятница, 14 Января 2011, 18:29:47 | Сообщение # 5
    9 уровень
    Группа: Проверенные
    Сообщений: 1097
    Награды: 0
    Репутация: 153
    Блокировки:
    SirNikolas, Я думал над этим, только если угол будет рандомным это будет тупо, как ты предложишь?
     

    SirNikolasДата: Пятница, 14 Января 2011, 18:32:24 | Сообщение # 6
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Геометрия рикошета.

     

    rixt7956Дата: Пятница, 14 Января 2011, 18:37:26 | Сообщение # 7
    9 уровень
    Группа: Проверенные
    Сообщений: 1097
    Награды: 0
    Репутация: 153
    Блокировки:
    SirNikolas, А не дашь формулу для кода, а то мне не кайф думать перед завтрашней геометреей в школе :)
     

    SirNikolasДата: Пятница, 14 Января 2011, 18:46:25 | Сообщение # 8
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Я же там прямым тесктом написал:
    Quote
    BX = 2CD - α
    Quote
    ЕСЛИ α ≥180˚ И RB ≥ 90˚
    ТО CD=RB+90˚
    ИНАЧЕ CD=RB-90˚
    , где α - угол движения, BX - угол рикошета, RB - угол от центра препятствия до юнита, CD - перпендикуляр рикошета.


     

    rixt7956Дата: Пятница, 14 Января 2011, 18:55:26 | Сообщение # 9
    9 уровень
    Группа: Проверенные
    Сообщений: 1097
    Награды: 0
    Репутация: 153
    Блокировки:
    SirNikolas, А кодом это будет примерно так?
    Code
    local real a=bj_RADTODEG*Atan2(y-y2,x-x2)
    local real BX
    local real CD
    local real RB=bj_RADTODEG*Atan2(y2-y1,x2-x1)
    if a>=180 and RB >=90 then
    set CD=RB+90
    else
    CD=RB-90
    endif
    set BX=2*CD-a
     

    SirNikolasДата: Пятница, 14 Января 2011, 19:04:16 | Сообщение # 10
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    rixt7956, боюсь, что я тоже тупанул, причем капитально. Я это писал, расчитывая на то, что юнит будет сталкиваться только с другими юнитами. То, что ты написал в RB - это угол не от центра препятствия, а от точки столкновения, т. е., если использовать это, то юнит всегда будет отлетать перпендикулярно движению, что еще хуже. У меня есть мысль, как можно определить центр, главное - ее оформить в виде кода.

     

    rixt7956Дата: Пятница, 14 Января 2011, 19:06:44 | Сообщение # 11
    9 уровень
    Группа: Проверенные
    Сообщений: 1097
    Награды: 0
    Репутация: 153
    Блокировки:
    SirNikolas, Ну давай :)
     

    SirNikolasДата: Пятница, 14 Января 2011, 19:09:22 | Сообщение # 12
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Ты надеешься, что я ее уже обдумал? Напрасно. :p Завтра будет.

     

    rixt7956Дата: Пятница, 14 Января 2011, 19:12:37 | Сообщение # 13
    9 уровень
    Группа: Проверенные
    Сообщений: 1097
    Награды: 0
    Репутация: 153
    Блокировки:
    SirNikolas, Ок :)
     

    SirNikolasДата: Суббота, 15 Января 2011, 07:42:02 | Сообщение # 14
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Code
    library OTR
               globals
                   private constant hashtable hash=InitHashtable()
               endglobals
             private struct str
             unit u
             real speed
             real angle
             endstruct

             public function XYpr takes real x,real y returns boolean
    local item t=CreateItem('texp',x,y)
    local real x1
    local real y1
    call SetItemPosition(t,x,y)
    set x1=GetItemX(t)
    set y1=GetItemY(t)
    call RemoveItem(t)
    set t=null
    return x==x1 and y==y1
            endfunction

    public function ConvertReal takes real r, real min, real max returns real
           loop
               exitwhen r <= max
               set r = r - max
           endloop
           loop
               exitwhen r >= min
               set r = r + max
           endloop
           return r
    endfunction

    public function Ricochet takes real x, real y, real angle, real dist, real step, real max returns real
           local real r = step
           local real a = angle          
           local real x1
           local real y1
           local real x2
           local real y2
           loop
               set x1 = x + Cos(a) * dist
               set y1 = y + Sin(a) * dist              
               exitwhen r >= max or OTR_XYpr(x1, y1)
               set r = r + step
               set a = OTR_ConvertReal(angle + r, .0, 360.)
           endloop
           if a == angle then
               return angle
           endif
           set r = step
           loop
               set x2 = x + Cos(a) * dist
               set y2 = y + Sin(a) * dist
               exitwhen r >= max or OTR_XYpr(x2, y2)
               set r = r + step
               set a = OTR_ConvertReal(angle - r, .0, 360.)
           endloop
           set r = OTR_ConvertReal(3.1415926536 + (Atan2(y1 - y, x1 - x) + Atan2(y2 - y, x2 - x)) / 2, .0, 6.283185306)
           if r >= 1.5707963265 and a >= 3.1415926536 then
               return 2 * (r + 1.5707963265) - a
           endif
           return 2 * (r - 1.5707963265) - a
    endfunction

             private function GrAc3 takes nothing returns nothing
    local timer t=GetExpiredTimer()
    local str h=LoadInteger(hash,GetHandleId(t),0)
    local real x=GetWidgetX(h.u)
    local real y=GetWidgetY(h.u)
    local real x1=x+h.speed*Cos(h.angle*.0174532)
    local real y1=y+h.speed*Sin(h.angle*.0174532)
    local real angle
            if h.speed>.0 then
                   set angle = OTR_Ricochet(x1, y1, h.angle, 15., .3490658502, 3.1415926536)
                   if angle == h.angle then
                       call SetUnitX(h.u,x1)
                       call SetUnitY(h.u,y1)
                   else
                       set h.angle = angle
                       set h.speed=h.speed-1.
                   endif
               call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl",x1,y1))
               set h.speed=h.speed-.3
            else
                call FlushChildHashtable(hash,GetHandleId(t))
                call DestroyTimer(t)
                call h.destroy()
            endif
    set t=null
             endfunction

             public function GrUnit takes unit u,real x,real y,real maxdist returns nothing
    local timer t=CreateTimer()
    local real xu=GetUnitX(u)
    local real yu=GetUnitY(u)
    local real angle=bj_RADTODEG*Atan2(yu-y,xu-x)
    local real speed=maxdist/100-SquareRoot((x-xu)*(x-xu)+(y-yu)*(y-yu))/100
    local str h=str.create()
    set h.u=u
    set h.speed=speed
    set h.angle=angle
    call SaveInteger(hash,GetHandleId(t),0,h)
    call TimerStart(t,0.02,true,function GrAc3)
    set t=null
             endfunction

             public function Start takes unit u,real radius,real maxdist returns nothing
    local group g=CreateGroup()
    local unit ugr
    local real x=GetWidgetX(u)
    local real y=GetWidgetY(u)
    call GroupEnumUnitsInRange(g,x,y,radius,null)
               loop
                   set ugr=FirstOfGroup(g)
                   exitwhen ugr==null
                       if IsUnitEnemy(ugr,GetOwningPlayer(u)) and GetWidgetLife(ugr)>.0 then
                           call GrUnit(ugr,x,y,maxdist)
                       endif
                   call GroupRemoveUnit(g,ugr)
               endloop
    call DestroyGroup(g)
    set g=null
             endfunction

              public function StartXY takes player p,real x,real y,real radius,real maxdist returns nothing
    local group g=CreateGroup()
    local unit ugr
    call GroupEnumUnitsInRange(g,x,y,radius,null)
               loop
                   set ugr=FirstOfGroup(g)
                   exitwhen ugr==null
                       if IsUnitEnemy(ugr,p) and GetWidgetLife(ugr)>.0 then
                           call GrUnit(ugr,x,y,maxdist)
                       endif
                   call GroupRemoveUnit(g,ugr)
               endloop
    call DestroyGroup(g)
    set g=null
             endfunction

    endlibrary
    Функция OTR_Ricochet определяет угол (в радианах!), по которому будет продолжать движение объект, попадающий в точку (x; y) и движущийся под углом angle. Также она берет дополнительные параметры.
    dist определяет, в каком радиусе нужно искать препятствие. При слишком высоких значениях она может не заметить небольшой объект (например, овцу), а при низких юнит будет рикошетировать от малых шероховатостей, и следовательно, совсем в другую сторону. Оптимальное значение - 15.
    Чем меньше параметр step, тем выше точность рикошета, но и лаги тоже увеличиваются. Оптимальное значение - .34907. Измеряется в радианах!
    Параметр max показывает, под каким максимальным углом следует искать препятствие. Оптимальное значение - 3.141592. Измеряется в радианах!

    Добавлено (15-01-2011, 07:42)
    ---------------------------------------------
    Само собой разумеется, существует погрешность, и, я думаю, немалая, но в таких случаях ей можно пренебречь.
    P. S. Функцию не тестировал.




    Сообщение отредактировал SirNikolas - Суббота, 15 Января 2011, 10:12:12
     

    rixt7956Дата: Суббота, 15 Января 2011, 19:50:22 | Сообщение # 15
    9 уровень
    Группа: Проверенные
    Сообщений: 1097
    Награды: 0
    Репутация: 153
    Блокировки:
    спс,потом дам +

    Добавлено (15-01-2011, 19:50)
    ---------------------------------------------
    SirNikolas, от твоего кода игра просто зависает.

     

    SirNikolasДата: Среда, 19 Января 2011, 13:59:49 | Сообщение # 16
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Дело было в том, что я запутался, где градусы, а где радианы. Вот работающий код.
    Code
    library OTR
         globals
             private constant hashtable hash=InitHashtable()
         endglobals

         private struct str
             unit u
             real speed
             real angle
         endstruct

         public function XYpr takes real x,real y returns boolean
             local item t=CreateItem('texp',x,y)
             local real x1
             local real y1
             call SetItemPosition(t,x,y)
             set x1=GetWidgetX(t)
             set y1=GetWidgetY(t)
             call RemoveItem(t)
             set t=null
             return x==x1 and y==y1
         endfunction

         public function ConvertReal takes real r, real min, real max returns real
             loop
                 exitwhen r <= max
                 set r = r - max
             endloop
             loop
                 exitwhen r >= min
                 set r = r + max
             endloop
             return r
         endfunction

         public function Ricochet takes real x, real y, real angle, real dist, real step, real max returns real
             local real r = step
             local real a = angle
             local real x1
             local real y1
             local real x2
             local real y2
             loop
                 set x1 = x + Cos(a) * dist
                 set y1 = y + Sin(a) * dist
                 exitwhen r >= max or OTR_XYpr(x1, y1)
                 set r = r + step
                 set a = OTR_ConvertReal(angle + r, .0, 6.283185306)
             endloop
             if a == angle then
                 return angle
             endif
             set r = step
             loop
                 set x2 = x + Cos(a) * dist
                 set y2 = y + Sin(a) * dist
                 exitwhen r >= max or OTR_XYpr(x2, y2)
                 set r = r + step
                 set a = OTR_ConvertReal(angle - r, .0, 6.283185306)
             endloop
             set r = OTR_ConvertReal(3.1415926536 + (Atan2(y1 - y, x1 - x) + Atan2(y2 - y, x2 - x)) / 2, .0, 6.283185306)
             if r >= 1.5707963265 and a >= 3.1415926536 then
                 return 2 * (r + 1.5707963265) - a
             endif
             return 2 * (r - 1.5707963265) - a
         endfunction

         private function GrAc3 takes nothing returns nothing
             local timer t=GetExpiredTimer()
             local str h=LoadInteger(hash,GetHandleId(t),0)
             local real x=GetWidgetX(h.u)
             local real y=GetWidgetY(h.u)
             local real x1=x+h.speed*Cos(h.angle)
             local real y1=y+h.speed*Sin(h.angle)
             local real angle
             if h.speed>.0 and GetWidgetLife(h.u) > .0 then
                 set angle = OTR_Ricochet(x1, y1, h.angle, 15., .3490658502, 3.1415926536)
                 if angle == h.angle then
                     call SetUnitX(h.u,x1)
                     call SetUnitY(h.u,y1)
                 else
                     set h.angle = angle
                     set h.speed=h.speed-1.
                 endif
                 call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Human\\FlakCannons\\FlakTarget.mdl",x1,y1))
                 set h.speed=h.speed-.3
             else
                 call FlushChildHashtable(hash,GetHandleId(t))
                 call DestroyTimer(t)
                 call h.destroy()
             endif
             set t=null
         endfunction

         public function GrUnit takes unit u,real x,real y,real maxdist returns nothing
             local timer t=CreateTimer()
             local real xu=GetUnitX(u)
             local real yu=GetUnitY(u)
             local real angle=Atan2(yu-y,xu-x)
             local real speed=maxdist/100-SquareRoot((x-xu)*(x-xu)+(y-yu)*(y-yu))/100
             local str h=str.create()
             set h.u=u
             set h.speed=speed
             set h.angle=angle
             call SaveInteger(hash,GetHandleId(t),0,h)
             call TimerStart(t,0.02,true,function GrAc3)
             set t=null
         endfunction

         public function Start takes unit u,real radius,real maxdist returns nothing
             local group g=CreateGroup()
             local unit ugr
             local real x=GetWidgetX(u)
             local real y=GetWidgetY(u)
             call GroupEnumUnitsInRange(g,x,y,radius,null)
             loop
                 set ugr=FirstOfGroup(g)
                 exitwhen ugr==null
                 if IsUnitEnemy(ugr,GetOwningPlayer(u)) and GetWidgetLife(ugr)>.0 then
                     call GrUnit(ugr,x,y,maxdist)
                 endif
                 call GroupRemoveUnit(g,ugr)
             endloop
             call DestroyGroup(g)
             set g=null
         endfunction

         public function StartXY takes player p,real x,real y,real radius,real maxdist returns nothing
             local group g=CreateGroup()
             local unit ugr
             call GroupEnumUnitsInRange(g,x,y,radius,null)
             loop
                 set ugr=FirstOfGroup(g)
                 exitwhen ugr==null
                 if IsUnitEnemy(ugr,p) and GetWidgetLife(ugr)>.0 then
                     call GrUnit(ugr,x,y,maxdist)
                 endif
                 call GroupRemoveUnit(g,ugr)
             endloop
             call DestroyGroup(g)
             set g=null
         endfunction
    endlibrary


     

    AUДата: Четверг, 20 Января 2011, 10:10:13 | Сообщение # 17
    7 уровень
    Группа: Проверенные
    Сообщений: 471
    Награды: 0
    Репутация: 70
    Блокировки:
    оё! тут бы импульсы пригодились...

    Остаться в живых
    стрелялка с мышковым управлением =)
     

    SirNikolasДата: Четверг, 20 Января 2011, 13:36:35 | Сообщение # 18
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Ты сейчас к чему это сказал?

     

    [stebashka]Дата: Четверг, 20 Января 2011, 13:45:08 | Сообщение # 19
    пути и нити разными бывают
    Группа: Библиотекари
    Сообщений: 4719
    Награды: 5
    Блокировки:
    SirNikolas, а на гуи это перевести возможно? я жасс не знаю

     

    DreiiДата: Четверг, 20 Января 2011, 13:50:07 | Сообщение # 20
    10 уровень
    Группа: Проверенные
    Сообщений: 4991
    Награды: 0
    Репутация: 603
    Блокировки:
    [stebashka], аналогично этой?Нет

     

    [stebashka]Дата: Четверг, 20 Января 2011, 13:51:04 | Сообщение # 21
    пути и нити разными бывают
    Группа: Библиотекари
    Сообщений: 4719
    Награды: 5
    Блокировки:
    Dreii, эх жаль

     

    SirNikolasДата: Четверг, 20 Января 2011, 13:56:35 | Сообщение # 22
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Что значит "нет"? Разумеется, можно, только структуры придется обычными массивами заменить, либо хэшем.

     

    DreiiДата: Четверг, 20 Января 2011, 14:10:06 | Сообщение # 23
    10 уровень
    Группа: Проверенные
    Сообщений: 4991
    Награды: 0
    Репутация: 603
    Блокировки:
    Quote (SirNikolas)
    структуры

    не шарю ^_^


     

    SirNikolasДата: Четверг, 20 Января 2011, 14:22:51 | Сообщение # 24
    Группа: Модераторы
    Сообщений: 6729
    Награды: 1
    Репутация: 1867
    Блокировки:
    Quote (SirNikolas)
    Code
    private struct str
         unit u
         real speed
         real angle
    endstruct
    Структура - это своеобразная "связка" переменных. Здесь она используется, чтобы уменьшить кол-во обращений к хэшу, т. к. гораздо быстрее использовать внутриструктурные переменные, чем выгружать их из хэш-таблицы.


     

    KartohaДата: Четверг, 20 Января 2011, 17:38:25 | Сообщение # 25
    10 уровень
    Группа: Ветераны
    Сообщений: 2851
    Награды: 1
    Блокировки:
    Открыл через JNGP, жму "проверка карты", загружается, открывает варкрафт и выкидывает в гм, почему такое может быть?
     

    Форум о Warcraft 3 » Раздел для картостроителей » Раздел картостроителя » [Система]Система отталкивания
    • Страница 1 из 2
    • 1
    • 2
    • »
    Поиск:

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