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

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

Ответ
 
FoK_KruGer
<3 Vocal Trance
offline
Опыт: 19,940
Активность:
Цитата:
так как добавить герою спел нельяз - только абилку.

Чёт я не понял в чём разница???
а на счет покупки спеллов то что будут покупать самые мощные.
НУЖНО Чтоб все такими были.
Если вы считаете что это не реально,то подумайте "как и сколько по времени делали Доту??"
Насчёт наземного транспорта:
неплохо было б если им являлся военный американский джип.Такой темно-зелёный с открытым верхом.

Новая идея:морские Корабли!можно купить и с моря обстреливать чё-нибудь.

З.ы. Ща буду сидеть и перебирать игры в которые играл и думать что оттуда можно с комуниздить(идеи)
Спасибо что приняли в команду!!! :loveyou:
Старый 13.04.2006, 19:53
Warden
:::...
offline
Опыт: 26,106
Активность:
Пожалуйста :loveyou:
Старый 13.04.2006, 20:23
FoK_KruGer
<3 Vocal Trance
offline
Опыт: 19,940
Активность:
Цитата:
Пожалуйста :loveyou:

Типа ты обиделся?Это просто смешной смаил

FoK_KruGer добавил:
Придумал.
При одевании вещи ВИДНО НА ГЕРОЕ что она одета.И Как вещь и как иконка.
ИМХО глупость(ЛОЛ)
Jon>>>>>>Кто я?
1.Ну знаю триггеры-----40. Кстати, ваш онлаин тестер первый тест прошел с первого раза.
2.Рельефщик---0 так как пункт 3
3.Фантазия-----0
4.кто там ещё есть?
5.моделщик тоже нулевой так как макса даже в глаза не видел(но хочу в нем поработать)
6.Идейщик---10 ну уже понятно
7.Оригиналщик---10 тоже
8.В принципе я хороший Оператор-----30.
9.Хорошо знаю Редактор ОбъеДков и Сам ворд эдитор(по тестам)
10.Чуство юмора-------100

Теперь то что я не умею:
(Ну к 14 годам все выучить тяжело)

1.Понятие не имею о джасе
2.массив?---че это такое?
3.переменными я не пользуюсь(ток очень редко(т.к. о них почти ничего не знаю))
4.Не умею делать таблички которые сверху справа расположены
5.Диалоговое окно я сделаю но с трудом..
6.АИ не сделаю точно.
7.Самое страшное----не разбираюсь в циклах.
Но если мне объяснят то пойму. Я быстро учусь)

Кстати,карту скинте в личку хочу просмотреть.(без защиты)(лол)(хочу спеллы научится делать(они же у вас есть(надеюсь на джасе))))(Лол сколько скобок!)

Насчёт секретов:у базы Наг будет стоять статуя с Варденкой))))
А у базы Эльфов(с большой буквы так как Эльфы---имба) Котёнок на пьедестале на котором начертано:Ну разве не прелесть???
Или посередине вместе и В обнимку!
Л о о о о л
л л о о л л
л л о о о о л л

И всё же я настаиваю на покупке спелла.Или выборе.Но за деньги.(ЛОЛ)


:loveyou: :end:
Старый 13.04.2006, 21:15
Van Damm
wait... what?
offline
Опыт: 22,268
Активность:
Jon по поводу расширенного инвентаря - ты знаешь, как сделать его одновременно и удобным, и не занимающим много способностей->времени загрузки карты, и не занимающим много времени на доступ, и не перекрывающим обзор за событиями на поле боя?
Старый 14.04.2006, 00:06
Warden
:::...
offline
Опыт: 26,106
Активность:
FoK_KruGer - Я не обиделся :loveyou:

Warden добавил:
FoK_KruGer - На счет покупки - тебе не жаль тех людей, которые старались, придумывали спеллы и.т.д

Warden добавил:
А че на счет скрещивания (Смотри карту)
Старый 14.04.2006, 08:51
FoK_KruGer
<3 Vocal Trance
offline
Опыт: 19,940
Активность:
WardenТо что придумывали то молодцы.
Остолось их купить. :loveyou:
Ты хоть мое сообщение предыдыщее читал?? :end:
Старый 14.04.2006, 11:09
dk

offline
Опыт: 60,293
Активность:
Понимаешь FoK_KruGer если мы сделаем покупку, то все спелы либо будут одного уровня(как у обычных юнитов) либо как у героев, но в этом случае придется делать столько героев(задумывалось 36 а будет во много раз больше). Jon по поводу выбора в самом начале, то это еще можно, кстати было это в одной карте на XGM'е щас название скажу, если найду!
Старый 14.04.2006, 11:35
FoK_KruGer
<3 Vocal Trance
offline
Опыт: 19,940
Активность:
Dead_knight
ТОЧНО!
А я чет не додумался!Во нуууууб
З.Ы,А пичиму ты ни в школе?
Старый 14.04.2006, 11:50
dk

offline
Опыт: 60,293
Активность:
У меня время +5 к Московскому!
Старый 14.04.2006, 12:11
J
expert
offline
Опыт: 48,447
Активность:
Допустим, вы хотите сделать спел. в котором хотите, чтобы также как Молот грома вызывал снаряд, летящий в юнита, и после столкновения с ним вызывал какие либо действия…
Вы берете Молот грома или другую подобную абилку, кастует ее по цели, и ждете ваитом (Wait) время (Расстояние до цели)/скорость снаряда
Скорость снаряда указана в РО и с этим проблем нет
Однако Расстояние до цели не постоянно, т.к. юнит движется, а рассчитываем расстояние мы только в момент каста… а что если скорость снаряда мала? И пока снаряд летит юнит сможет отбежать на приличное расстояние от рассчитанного? Тогда снаряд не успев долететь выполнит свои действия что будет выгладить не естественно, и не профессионально…
Однако большинство триггерщиков пренебрегают этим точностям… “Подумаешь как работает! Главное чтобы ведь работало!”
Однако, если мы захотим усложнить спел? Например, сделать так чтобы снаряд мог врезаться в любого встречного во время полета к цели. Через Молот Грома это никак не осуществить, и даже через любую стандартную абилку, тут поможет только джаз…
Так что объясню как сделать подобное, однако это будет сложно понять, не зная что такое таймеры или SCV, если вы знаете что это такое то вам можно это пропустить.

Таймеры


Таймер, это своего рода периодический триггер, выполняющий одну и туже функции раз в указанный промежуток времени.
Сначала надо создать таймер функцией CreateTimer(), название типа таймера называется timer, и он является один из подтипов handle.
Код:
local timer Timer = CreateTimer()

Но сам по себе таймер ничего не делает, его нужно запустить функцией TimerStart()
Код:
call TimerStart(timer, real, boolean, code)

Обьесняю принимаемые значения:
timer – Это уже созданный объект – таймер, который и будет выполнятся.
real – Заданный промежуток времени
bool – Логическая переменная, поставьте true, и таймер будет выполнятся периодически, каждый раз просчитывая заданный промежуток времени, поставьте false и таймер будет выполнен единично после того как пройдет заданное время
Приведем парочку простых примеров:
Код:
function FuncTimerStart_Timer takes nothing returns nothing  
    set udg_Integer = udg_Integer + 1 
    call DisplayTextToForce (bj_FORCE_ALL_PLAYERS, I2S(udg_Integer) )
endfunction

function FuncTimerStart takes nothing returns nothing
    local timer Timer = CreateTimer()
    call TimerStart(Timer, 1, true, function FuncTimerStart_Timer)
    set Timer = null
endfunction

в результате на экран будет выводиться каждую секунду число, постоянно увеличиваясь на единицу.
Код:
function FuncTimerStart_Timer takes nothing returns nothing  
    call DisplayTextToForce (bj_FORCE_ALL_PLAYERS, "Таймер сработал")
endfunction

function FuncTimerStart takes nothing returns nothing
    local timer Timer = CreateTimer()
    call TimerStart(Timer, 5, false, function FuncTimerStart_Timer)
    set Timer = null
endfunction

после вызова функции FuncTimerStart() спустя 5 секунд на экране появится надпись “Таймер сработал”, больше таймер выполнятся не будет, пока его снова не запустят.
Однако, если таймер и не запускать, он все равно будет существовать, и чтобы он ни весел мертвым грузом в памяти – его нужно удалить. Удаляется он функцией DestroyTimer(), однако в ней нужно указать переменную удаляемого таймера. Тут пригодится функция GetExpiredTimer() используя ее в функции что выполняет таймер, она возвращает его.
И получается чтобы удалить таймер, нужно в верхнем коде в функцию FuncTimerStart_Timer добавить еще одно действие:
Код:
function FuncTimerStart_Timer takes nothing returns nothing
    call DisplayTextToForce (bj_FORCE_ALL_PLAYERS, "Таймер сработал")
    call DestroyTimer(GetExpiredTimer())
endfunction

Также следует заметить, что после удаления таймера, функция, в которой он удалился, и которую он выполняет, все равно доработает до конца.
Если в Выполняемую функцию таймера вставить функцию, которая принимает любые параметры, то вас просто выкинет из игры с ошибкой в момент запуска таймера.
Таймер можно делать периодическим, но изменять его период нельзя, но иногда это требуется.
Для этого будем использовать рекурсию одиночный таймеров.
Код:
function FuncTimerStart_Timer takes nothing returns nothing  
    call DisplayTextToForce (bj_FORCE_ALL_PLAYERS, " Таймер сработал ")  
    call TimerStart(GetExpiredTimer(), udg_Real, false, function FuncTimerStart_Timer)
endfunction

function FuncTimerStart takes nothing returns nothing
    local timer Timer = CreateTimer()
    call TimerStart(Timer, 1, false, function FuncTimerStart_Timer)
    set Timer = null
endfunction

И таймер будет постоянно выполнятся через время указанное в переменной udg_Real.
Надо будет просто изменять переменную и все…
В этом случае хоть таймер и одиночный, но после завершения удалять его не надо, т.к. он продолжает запускается вновь:
Вот все остальные функции по работе с таймером:
Код:
native TimerGetElapsed takes timer whichTimer returns real  native TimerGetRemaining takes timer whichTimer returns real  native TimerGetTimeout takes timer whichTimer returns real  native PauseTimer takes timer whichTimer returns nothing  native ResumeTimer takes timer whichTimer returns nothing

1) Принимает таймер, и возвращает значение уже пройденного времени с момента запуска, или с момента последнего выполнения
2) Принимает таймер, и возвращает оставшегося времени до следующего выполнения
3)
4) Останавливает принятый таймер
5) Продолжает Остановленный таймер

Также следует отметить преимущество таймера:
  1. Он Абсолютно точный, и выполняется точно через заданное время, 2 отдельно созданных таймера просчитывают свое время абсолютно синхронно, в отличии от ваитов.

  2. Таймер Ждет игровое время, значит во время пауз игры он не будет просчитывать оставшееся время, и игрок не сможет этим воспользоваться

  3. Т.к. таймер ждет игровое время, то быстрота его выполнения зависит от скорости игры, что при ваитах не имело место.

  4. Работает через сколь угодно малый промежуток времени, при обычном ваите, минимальный промежуток ожидания в минимуме составлял 0,125 секунд.
Если вы занимались триггерством, то вам должно быть известно действие Wait(game-time)
Преимущество ее от обычного ваита в том, что она просчитывает игровое время, а не реальное… Однако посмотрите на строение этой функции:
Код:
function PolledWait takes real duration returns nothing
    local timer t
    local real  timeRemaining
    if (duration > 0) then
        set t = CreateTimer()
        call TimerStart(t, duration, false, null)
        loop
            set timeRemaining = TimerGetRemaining(t)
            exitwhen timeRemaining <= 0
            if (timeRemaining > bj_POLLED_WAIT_SKIP_THRESHOLD) then
                call TriggerSleepAction(0.1 * timeRemaining)
            else
                call TriggerSleepAction(bj_POLLED_WAIT_INTERVAL)
            endif
        endloop
        call DestroyTimer(t)
    endif
endfunction

Видите, она использует обычный ваит (функция TriggerSleepAction()), который выполняется через цикл, фишка этой функции в том, что она создает и запускает таймер (без выполняемой функции, т.е. просто как счетчик). И через цикл периодически с помощью обычного ваита просчитывает оставшееся время до срабатывания таймера, и если оно равно 0 (таймер сработал) то выйти из цикла и продолжить выполнение всех действий после Wait(game-time). Тем самым, создавая эффект присчитывания игрового времени.
Однако неточность, присутствие ограничения, как и в обычном ваите, и его не универсальность все же намекают о том, что лучше использовать таймер напрямую.
В основном таймеры используют для движения прожектилов. Но об этом чуть позже…

Super Custom Value (SCV)


Ни будем ни что усложнять… возьмем самый простой бессмысленный пример для рассмотрения – Будем просто двигать юнита вправо.
Код:
function FuncTimerStart_Timer takes nothing returns nothing  
    call SetUnitX(udg_Unit, GetUnitX(udg_Unit)+5)
endfunction

function FuncTimerStart takes unit OurUnit returns nothing
    local timer Timer = CreateTimer()
    set udg_Unit = OurUnit
    call TimerStart(Timer, 0.04, true, function FuncTimerStart_Timer)
    set Timer = null
endfunction

Запуская Функцию FuncTimerStart(<НашЮнит>) мы заносим его в глобальную переменную (мы делаем так потому что просто передать пораметра в функцию выполнения таймера нельзя), и запускаем таймер который будет двигать этого юнита вправо… все очень просто, НО, попробуйте запустить эту функцию со вторым юнитом, и что же мы уведем?
А то что первый юнит перестал двигаться, а второй стал двигаться в 2 раза быстрее чем нужно… Это объясняется тем что глобальная переменная всего одна, и первый и второй таймер используют именно ее, и записывая в нее второго юнита, первый и новосозданный второй таймер начинают действовать только на второго юнита, и первый уже не двигается…
Как же добиться очень главного качества – универсальности?
Чтобы работало со всеми, и не мешало другим...
Все делается через SCV, оно сопоставляет любому объекту (в данном случае это нужно сопоставить таймеру) любое число, строку или объект (в данном случае юнита).

game cache


Если вы занимались триггерством, то вам должно быть известно, что существует Кеш - Динамичный Ассоциативный массив.
Динамичный потому что он как резиновый, имеет размер сопоставляемый с количеством записей в нем.
И ассоциативный, потому что в качестве 2-ух ключей/индексов в нем служат не целые числа (как в обычных массивах), а произвольные строки.

handle


У каждого объекта на карте имеется уникальный номер, который не повторяется (хотя это не так, но в рамках данной статьи это не рассматривается), его называют хендл.
При создании объекта хендл увеличивается, при удалении объектов, его хендл высвобождается, и его место занимает следующий созданный объект.
Этот хендл можно получить с помощью функции.
Код:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

объяснять принцы не буду, главное что она работает.
Чтобы вернуть юнита по его уникальному номеру воспользуемся функцией
Код:
function I2U takes integer i returns unit
    return i
    return null
endfunction



Теперь вернемся к нашей теме, как передать в функцию таймера параметр действительный только для этого таймера? Если учесть все факты что были сказано выше, то:
можно занести в Кеш в качестве первого индекса Уникальный ключ нашего таймера, а во второй индекс просто индексионую строку “Unit”, когда же выполнится функция, мы используя уникальный ключ таймера который в данный момент выполнил эту функции и вернем сопоставленного ему юнита.
Код:
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function I2U takes integer i returns unit
    return i
    return null
endfunction

function FuncTimerStart_Timer takes nothing returns nothing 
    local timer Timer = GetExpiredTimer()
    local unit OurUnit = I2U(GetStoredInteger(udg_cache, I2S(H2I(Timer)), "Unit")) 
    call SetUnitX(OurUnit, GetUnitX(OurUnit)+5)
endfunction

function FuncTimerStart takes unit OurUnit returns nothing
    local timer Timer = CreateTimer()
    call TimerStart(Timer, 0.04, true, function FuncTimerStart_Timer)
    call StoreInteger(udg_cache, I2S(H2I(Timer)), "Unit", H2I(OurUnit))
    set Timer = null
endfunction

И сколько бы вы не запускали функцию FuncTimerStart() их выполнение не будет никак мешать друг на друга…

projectile


Теперь вернемся к тому что обсуждалось во вступлении:

Нам понадобятся Функции расчета расстояния, и угла между 2-мя точками, но тру челы точки не юзают, потому мы будем пользоваться координатами, но к сожалению аналогов функция DistanceBetweenPoints и DistanceAnglePoints работающих на координатах нету в blizzard.j.
Потому мы напишем их сами…
Код:
//=======Растояние между точками (AX; AY) и (BX; BY)===========
function DistanceBetweenCord takes real AX, real AY, real BX, real BY returns real
    local real dx = BX - AX
    local real dy = BY - AY
    return SquareRoot(dx * dx + dy * dy)
endfunction          
   
//=======Угол между точками (AX; AY) и (BX; BY)===========
function AngleBetweenCord takes real AX, real AY, real BX, real BY returns real
    return bj_RADTODEG * Atan2(BY - AY, BX - AX)
endfunction

Также в данной области нужно очень хорошо знать тригонометрию, я советую всем незнающим почитать эту тему обязательно http://xgm.guru/forum/showthread.php?t=9431

Теперь приступаем к нашему таймеру:
Нам нужно всево напросто создать таймер, передать в него Снаряд, Цель и все… С помощью полярных координат передвинуть прожектил ближе к цели, и если расстояние от него до цели меньше определенного значения, то закнчить таймер и выполнить нужные действия:


Код:
function FuncTimerStart_Timer takes nothing returns nothing 
    local timer Timer = GetExpiredTimer()
    local unit projectile = I2U(GetStoredInteger(udg_cache, I2S(H2I(Timer)), "projectile"))  
    local unit Target     = I2U(GetStoredInteger(udg_cache, I2S(H2I(Timer)), "Target"    )) 
    local real Xp = GetUnitX(projectile)
    local real Yp = GetUnitY(projectile)
    local real Xt = GetUnitX(Target)
    local real Yt = GetUnitY(Target)
    local real Angle = AngleBetweenCord (Xp, Yp, Xt, Yt)
    local unit caster
    if DistanceBetweenCord (Xp, Yp, Xt, Yt) > 40 then
        call SetUnitX(projectile, Xp+20*Cos(Angle*bj_DEGTORAD))  
        call SetUnitY(projectile, Yp+20*Sin(Angle*bj_DEGTORAD))
        call SetUnitFacing(projectile, Angle)
    else                  
        set Caster = I2U(GetStoredInteger(udg_cache, I2S(H2I(Timer)), "Caster")) //Обязательно до обнуления.
        call FlushStoredMission(udg_cache, I2S(H2I(Timer))) //Удаляем все записи из Кеша для этого таймера, нужно это делать обязательно ДО удаления таймера.
        call DestroyTimer(Timer) 
        //...
        // Сдесь делаем что хотим когда прожектил встретил цель, Кастер нам известен, можем наносвить от него урон, можем создавать дами юнита и коставать абилку и т.п.
        //...
        call DisplayTextToForce (bj_FORCE_ALL_PLAYERS, "Снаряд долетел")
    endif    
endfunction

function FuncTimerStart takes unit Caster, unit Target returns nothing
    local timer Timer = CreateTimer()
    local unit  projectile = CreateUnit(GetOwningPlayer(Caster), 'ewsp', GetUnitX(Caster), GetUnitY(Caster), 0)
    call TimerStart(Timer, 0.04, true, function FuncTimerStart_Timer)     
    call StoreInteger(udg_cache, I2S(H2I(Timer)), "Caster"    , H2I(Caster    )) 
    call StoreInteger(udg_cache, I2S(H2I(Timer)), "Target"    , H2I(Target    )) 
    call StoreInteger(udg_cache, I2S(H2I(Timer)), "projectile", H2I(projectile))
    set Timer = null
endfunction

При запуске функции FuncTimerStart(Кастер, Цель)? Создается снаряд летящий от кастера к цели, встречается с ним, и выполняет указанное в коде место…

Но это лишь маленький пример того как можно его двигать.
Теперь много усложним задачу… перейдем от 2D к 3D
Т.е. Снаряд у нас будет проходить не в одной плоскости, а в пространстве.
Думаю что все знают что такое парабола, если использовать ее для того чтобы начертить график движения юнита, получится такая формула:
Y=4*S*hig*(1-X/len)/len
В результате движения в плоскости карты + движение по Z с помощью этой формулы получится, что юнит будет лететь по дуговой траектории, максимальная высота которой ровна hig, а длина len, а S – уже пройденное расстояние из len.
Подобные движения уже сложно осуществлять между юнитами, и они требуют точных расчетов и точного значения начала и конца пути.
Потому напишем функции только принимающая начал и конец в координатах.

Код:
function FuncTimerStart_Timer takes nothing returns nothing 
    local timer Timer = GetExpiredTimer() 
    local real len   = GetStoredReal (udg_cache, I2S(H2I(Timer)), "len"  ) 
    local real hig   = GetStoredReal (udg_cache, I2S(H2I(Timer)), "hig"  ) 
    local real Speed = GetStoredReal (udg_cache, I2S(H2I(Timer)), "Speed")
    local real S     = GetStoredReal (udg_cache, I2S(H2I(Timer)), "S"    )         
    local unit projectile = I2U(GetStoredInteger(udg_cache, I2S(H2I(Timer)), "projectile"))
    local real Angle = GetUnitFacing(projectile)     
    local real X     = GetUnitX     (projectile)
    local real Y     = GetUnitY     (projectile)
    set S = S + Speed
    if S > 40 then   
        call StoreReal(udg_cache, I2S(H2I(Timer)), "S", S)
        call SetUnitX (projectile, Xp+Speed*Cos(Angle))  
        call SetUnitY (projectile, Yp+Speed*Sin(Angle))
        call SetUnitFlyHeight (projectile, 4*S*hig*(1-X/len)/len, 10000000)
    else
        call FlushStoredMission(udg_cache, I2S(H2I(Timer)))
        call DestroyTimer(Timer)                            
        //...
        // Сдесь снаряд долетел. 
        //...
    endif    
endfunction

function FuncTimerStart takes real X1, real Y1, real X2, real Y2, real Speed returns nothing
    local timer Timer = CreateTimer()             
    local real len = DistanceBetweenCord (X1, Y1, X2, Y2)
    local real Angle = DistanceAngleCord (X1, Y1, X2, Y2)
    local unit  projectile = CreateUnit(GetOwningPlayer(Caster), 'ewsp', GetUnitX(Caster), GetUnitY(Caster), Angle)
    call TimerStart  (Timer, 0.04, true, function FuncTimerStart_Timer)     
    call StoreReal   (udg_cache, I2S(H2I(Timer)), "len"  , len    ) //Длина пути
    call StoreReal   (udg_cache, I2S(H2I(Timer)), "hig"  , len*0.6) //Максимальная высота пути, будем расчитывать от длины, чтобы было реалистичнее...  
    call StoreReal   (udg_cache, I2S(H2I(Timer)), "S"    , 0      ) //Пройденный путь, в начальный момент времени равен 0.   
    call StoreReal   (udg_cache, I2S(H2I(Timer)), "Speed", Speed  ) //Скорость снаряда
    call StoreInteger(udg_cache, I2S(H2I(Timer)), "projectile", H2I(projectile))
    set Timer = null
endfunction

Однако.. как стоить заметить, эта функция двигает Снаряд только в плости карты, и создает только визуальную видимость что он перемещается в воздухе… т.е. мы указываем в функции скорость юнита в плоскости, а не в пространстве.
С введением пространственной скорости, функция должно усложнится, в этом случае тоже приведу свой пример:
В нем я уже применил другую формулу, а именно весьма известную формулу равно ускоренного движения тел.
S = S0 + U*t + (a*t^2)/2
Код:
function FuncTimerStart_Time takes nothing returns nothing
    local timer  Timer  = GetExpiredTimer()   
    local string STimer = I2S(H2I(Timer)) //В связи с большим количество применения этого значения, его лучше занести в переменную   
    local unit  projectile = I2U(GetStoredInteger(udg_cache, STimer, "projectile"))  
    local real  t      = GetStoredReal(udg_cache, STimer, "t")
    local real  X      = GetStoredReal(udg_cache, STimer, "Xstart") + GetStoredReal(udg_cache, STimer, "SpeedX") *t - (GetStoredReal(udg_cache, STimer, "FtormX")*t*t)/2
    local real  Y      = GetStoredReal(udg_cache, STimer, "Ystart") + GetStoredReal(udg_cache, STimer, "SpeedY") *t - (GetStoredReal(udg_cache, STimer, "FtormY")*t*t)/2                      
    local real  Z      = GetStoredReal(udg_cache, STimer, "Zstart") + GetStoredReal(udg_cache, STimer, "SpeedZ") *t - (GetStoredReal(udg_cache, STimer, "g"     )  *t*t)/2        
    call SetUnitX (projectile, X)
    call SetUnitY (projectile, Y)
    call SetUnitFlyHeight(projectile, Z, 1000000000)        
    if Z <= 1 then
        call DestroyTimer (Timer)
        call FlushStoredMission(udg_cache, STimer)
    else              
        call StoreReal (udg_cache, STimer, "t", t+GetStoredReal(udg_cache, STimer, "SpeedTime") )  
    endif                                                    
endfunction

function FuncTimerStart takes unit projectile, real SpeedXYZ, real GAngle, real VAngle, real g, real Ftorm, real SpeedTime returns nothing
    local timer  Timer  = CreateTimer  ()
    local string STimer = I2S(H2I(Timer)) //В связи с большим количество применения этого значения, его лучше занести в переменную
    local real SpeedXY = SpeedXYZ * Cos(VAngle*bj_DEGTORAD) // Расчитываем скорость в плоскасти XY   
    local real SpeedX  = SpeedXY  * Cos(GAngle*bj_DEGTORAD) // Расчитываем скорость по Оси X
    local real SpeedY  = SpeedXY  * Sin(GAngle*bj_DEGTORAD) // Расчитываем скорость по Оси Y
    local real SpeedZ  = SpeedXYZ * Sin(VAngle*bj_DEGTORAD) // Расчитываем скорость по Оси Z   
    call TimerStart (Timer, 0.04, true, function FuncTimerStart_Time)    
    call StoreInteger (udg_cache, STimer, "projectile", H2I(projectile))
    call StoreReal    (udg_cache, STimer, "Xstart"   , GetUnitX(projectile))
    call StoreReal    (udg_cache, STimer, "Ystart"   , GetUnitY(projectile))
    call StoreReal    (udg_cache, STimer, "Zstart"   , GetUnitFlyHeight(projectile))    
    call StoreReal    (udg_cache, STimer, "SpeedX"   , SpeedX     )
    call StoreReal    (udg_cache, STimer, "SpeedY"   , SpeedY     )
    call StoreReal    (udg_cache, STimer, "SpeedZ"   , SpeedZ     )    
    call StoreReal    (udg_cache, STimer, "t"        , 0          )
    call StoreReal    (udg_cache, STimer, "g"        , g          )
    call StoreReal    (udg_cache, STimer, "FtormX"  , Cos(GAngle*bj_DEGTORAD)*Ftorm)
    call StoreReal    (udg_cache, STimer, "FtormY"  , Sin(GAngle*bj_DEGTORAD)*Ftorm)
    call StoreReal    (udg_cache, STimer, "SpeedTime", SpeedTime  )
    set Timer = null
endfunction

FuncTimerStart takes unit projectile, real SpeedXYZ, real GAngle, real VAngle, real g, real Ftorm, real SpeedTime
Projectile – Уже созданный снаряд (или даже просто юнит) который и будет двигатся
SpeedXYZ – Пространственная скорость снаряда
GAngle – угол движения юнита в игровой плоскасти
GAngle – угол движения юнита от горизонта в вертикальной плоскасти
g – Ускорение свободного падения т.е. замедление скорости снаряда по оси Z… т.е. он будет лететь уже не по симметричной траектории как в предыдущем случае.
Ftorm – Своего рода, сила трения воздуха… т.е. постепенно замедляя скорость снаряда по оси X и Y.

Но иногда нам неизвестен угол от горизонта, но известна конечная точка… как определить угол между стартовой и конечной точкой в вертикальной плоскости? Т.к. в варе нет для этого функции, можно воспользоваться моей:
Код:
function CosAngleXZ takes real X1, real Y1, real Z1, real X2, real Y2, real Z2 returns real
    return ((X2-X1)*(X2-X1)+(Y2-Y1)*(Y2-Y1))/(SquareRoot(((X2-X1)*(X2-X1)+(Y2-Y1)*(Y2-Y1)+(Z2-Z1)*(Z2-Z1))*((X2-X1)*(X2-X1)+(Y2-Y1)*(Y2-Y1))))    
endfunction

Она использует формулу Косинуса угла между векторами, и возвращает найденный угол в радианах.
Чтобы узнать синус можно его вывести из оновного тригонометрического тождества
Код:
function SinAngleXZ takes real X1, real Y1, real Z1, real X2, real Y2, real Z2 returns real
    local real C = CosAngleXZ(X1, Y1, Z1, X2, Y2, Z2)
    return SquareRoot(1- C*C)
endfunction

думаю на этом пожалуй все… перейдем к следующему…

GetLocationZ


Имя дело с этим и в триггерстве, вы знаете что высота юнита задается от точки на рельефе на которой он находится, и тем самым используя все выше упомянутые функции на очень неровном рельефе, то снаряд будет двигатся не очень корректно, т.к. весь рельев плоский или нет, представляет для него одну плоскость.
Но можно обойти эту проблему используя GetLocationZ(location)
Эта функция принимает точку, и возвращает высоту рельефа на которой находится точка
А функция GetUnitFlyHeight(unit)] возвращает высоту юнита от рельефа
Потому Абсолютная высота юнита будет ровна GetLocationZ(GetUnitLoc(unit))+ GetUnitFlyHeight(unit)
И к сожалению, функция GetLocationZ принимает параметр только точку… альтернативы с ее координатами нет, потому сейчас мы резко переходим от координат к точкам:
Надо добавить, что у точек немного другой оптимальный механизм движения.
Создавать точку нужно всего раз, а в функции выполнения таймера нужно всеволиж перемещать точку функцией MoveLocation(Loc, X, Y)
И при завершении движения - удалить точку.

Воспользуемся функцией прожектила использующего формулу с пространственной скоростью и предыдущей главы:
Но в данном примере мы лучше воспользуемся традиционным способом создания и удаления точек для буле лучшего понимания:
Код:
function SetUnitZ takes unit Unit, real X, real Y, real Z returns unit
    local location Loc = GetUnitLoc(Unit)
    local real LocZ  = GetLocationZ(Loc)
    local real 2LocZ
    call MoveLocation(Loc, X, Y)
    set 2LocZ = GetLocationZ(Loc)
    call SetUnitFlyHeight(projectile, Z-2LocZ+LocZ, 10000000) 
    call RemoveLocation(Loc)
    set Loc = null
endfunction

function FuncTimerStart_Time takes nothing returns nothing
    local timer  Timer  = GetExpiredTimer()   
    local string STimer = I2S(H2I(Timer)) //В связи с большим количество применения этого значения, его лучше занести в переменную   
    local unit  projectile = I2U(GetStoredInteger(udg_cache, STimer, "projectile"))  
    local real  t      = GetStoredReal(udg_cache, STimer, "t")
    local real  X      = GetStoredReal(udg_cache, STimer, "Xstart") + GetStoredReal(udg_cache, STimer, "SpeedX") *t - (GetStoredReal(udg_cache, STimer, "FtormX")*t*t)/2
    local real  Y      = GetStoredReal(udg_cache, STimer, "Ystart") + GetStoredReal(udg_cache, STimer, "SpeedY") *t - (GetStoredReal(udg_cache, STimer, "FtormY")*t*t)/2                      
    local real  Z      = GetStoredReal(udg_cache, STimer, "Zstart") + GetStoredReal(udg_cache, STimer, "SpeedZ") *t - (GetStoredReal(udg_cache, STimer, "g"     )  *t*t)/2        
    call SetUnitZ (projectile, X, Y, Z)
    call SetUnitX (projectile, X)
    call SetUnitY (projectile, Y)      
    if Z <= 1 then
        call DestroyTimer (Timer)
        call FlushStoredMission(udg_cache, STimer)
    else              
        call StoreReal (udg_cache, STimer, "t", t+GetStoredReal(udg_cache, STimer, "SpeedTime") )  
    endif                                                    
endfunction                                       

function FuncTimerStart takes unit projectile, real SpeedXYZ, real GAngle, real VAngle, real g, real Ftorm, real SpeedTime returns nothing
    local timer  Timer  = CreateTimer  ()
    local string STimer = I2S(H2I(Timer)) //В связи с большим количество применения этого значения, его лучше занести в переменную
    local real SpeedXY = SpeedXYZ * Cos(VAngle*bj_DEGTORAD) // Рассчитываем скорость в плоскасти XY   
    local real SpeedX  = SpeedXY  * Cos(GAngle*bj_DEGTORAD) // Рассчитываем скорость по Оси X
    local real SpeedY  = SpeedXY  * Sin(GAngle*bj_DEGTORAD) // Рассчитываем скорость по Оси Y
    local real SpeedZ  = SpeedXYZ * Sin(VAngle*bj_DEGTORAD) // Рассчитываем скорость по Оси Z   
    call TimerStart (Timer, 0.04, true, function FuncTimerStart_Time)    
    call StoreInteger (udg_cache, STimer, "projectile", H2I(projectile))
    call StoreReal    (udg_cache, STimer, "Xstart"   , GetUnitX(projectile))
    call StoreReal    (udg_cache, STimer, "Ystart"   , GetUnitY(projectile))
    call StoreReal    (udg_cache, STimer, "Zstart"   , GetUnitFlyHeight(projectile))    
    call StoreReal    (udg_cache, STimer, "SpeedX"   , SpeedX     )
    call StoreReal    (udg_cache, STimer, "SpeedY"   , SpeedY     )
    call StoreReal    (udg_cache, STimer, "SpeedZ"   , SpeedZ     )    
    call StoreReal    (udg_cache, STimer, "t"        , 0          )
    call StoreReal    (udg_cache, STimer, "g"        , g          )
    call StoreReal    (udg_cache, STimer, "FtormX"  , Cos(GAngle*bj_DEGTORAD)*Ftorm)
    call StoreReal    (udg_cache, STimer, "FtormY"  , Sin(GAngle*bj_DEGTORAD)*Ftorm)
    call StoreReal    (udg_cache, STimer, "SpeedTime", SpeedTime  )
    set Timer = null
endfunction

Появилась новая функция, это для удобства применения, она устанавливает юниту новую высоту, учитывая погрешность рельефа на навой точке.

Ну что ж… думаю на этом все…

Отредактировано Jon, 24.07.2007 в 08:44.
Старый 14.04.2006, 13:26
FoK_KruGer
<3 Vocal Trance
offline
Опыт: 19,940
Активность:
Jon ---Я Уже понял.
Dead_knight -----прикольно
Старый 14.04.2006, 13:50
Warden
:::...
offline
Опыт: 26,106
Активность:
FoK_KruGer - :loveyou: :)
Старый 14.04.2006, 15:43
dk

offline
Опыт: 60,293
Активность:
Warden в чем смысл твоего высказывания?
Щас как модеры прийдут!
Старый 14.04.2006, 15:45
Warden
:::...
offline
Опыт: 26,106
Активность:
Dead_knight - мы так шутим :susel:
Старый 14.04.2006, 15:47
J
expert
offline
Опыт: 48,447
Активность:
Цитата:
Сообщение от Van Damm
Jon по поводу расширенного инвентаря - ты знаешь, как сделать ...[ляляля]... на поле боя?

нет, но надеюсь к нам поже присоеденятся еще джазеры - к томуже инвентать NETRATA кокраз подходит - он, вроде, для многих игроков. Место он занимает - но не очень большое, да в любом случае прийдется делать через бонус области камеры.
И там должно быть все подробно расписано об импортации. - он ведь не для себя его делает - для всех.
Старый 14.04.2006, 18:08
Warden
:::...
offline
Опыт: 26,106
Активность:
Jon - расширение инвентаря? - поможет система Sergey - там неограниченое число предметов + они дейтвуют даже если их не видно...
Старый 15.04.2006, 16:36
FoK_KruGer
<3 Vocal Trance
offline
Опыт: 19,940
Активность:
А я думаю что лучще игроки будут ДУМАТЬ что взять.А то понаберут все самые крутые итемы и все.
Ненужен этот инвентарь.ИМХО
Кстати,Warden :loveyou: :alc:
Старый 15.04.2006, 18:55
Van Damm
wait... what?
offline
Опыт: 22,268
Активность:
Jon основной частью высказывания было
Цитата:
обзор за событиями на поле боя
. этого не обеспечивает ни инвентарь нетрата, ни другие полноэкранные инвентари. поверь мне, я сам являюсь автором одного из них (делался для проекта Знамёна Тьмы). вот можешь глянуть скрин
FoK_KruGer абсолютно согласен. лучше если надо будет подумать, прежде чем купить
Старый 16.04.2006, 00:16
dk

offline
Опыт: 60,293
Активность:
В крайнем случае можно сделать старым дедовским способом, бессмертный юнит у которого тоже есть место для переноски предметов.
Старый 16.04.2006, 11:06
FoK_KruGer
<3 Vocal Trance
offline
Опыт: 19,940
Активность:
Цитата:
лучше если надо будет подумать, прежде чем купить

Надо же !меня кто-то понимает в этом злом мире..... :end:
Старый 16.04.2006, 18:09
Ответ

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

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

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

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



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