WarCraft 3: [Lua] Поворачиваем башню танка за курсором

» Раздел: Основы

Основная цель

Основная цель этой статьи, показать, как же хорош новый патч и почему не стоит сидеть ну ГУИ или же 126 патче
Последние патчи дают доступ к такому функционалу, который многие бы посчитали неестественным
а именно тот самый доступ к курсору, за которым я так давно гоняюсь

Старые способы

Сильно не хочу расписывать, но на 126 патче, доступ к курсору можно было получить только через мемхак . И то на синхронизацию положения через игровой кеш нужно было бы затратить 2 секунды
» олдовый код
gamecache cache = InitGameCache("cache")
function SyncReal takes player p, real val returns real
if (GetLocalPlayer() == p) then
 StoreReal(cache, "", "", val)
endif
TriggerSyncStart()
if (GetLocalPlayer() == p) then
SyncStoredReal(cache, "", "")
endif
TriggerSleepAction(2)// меньшнее значение вызывает десинх
TriggerSyncReady()
return GetStoredReal(cache, "", "")
endfunction
//==================================================
function Trig_CameraSynh_Actions takes nothing returns nothing
player p = Player(0)
real x=0
real y=0
real syncx=0
real syncy=0
string xs,ys
if GetLocalPlayer()==p
xs=R2S(GetMouseTerrainX())
ys=R2S(GetMouseTerrainY())
x=S2R(xs)// перезапись через строковый тип
y=S2R(ys)// иначе нули
endif
syncx = SyncReal(p, x)
syncy = SyncReal(p, y)
CreateUnit(p, 'e009', syncx, syncy, 0)
endfunction

//===========================================================================
function InitTrig_CameraSynh takes nothing returns nothing
    set gg_trg_CameraSynh = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_CameraSynh, 2.10 )
    call TriggerAddAction( gg_trg_CameraSynh, function Trig_CameraSynh_Actions )
endfunction
И это было ужасно, так же мною был найден способ следить за курсором через автоповтор ПКМ (RMB), с помощью системы WFE , такая комбинация позволяла получать курсор другого игрока при зажатой ПКМ вот в этом проекте , но частота повтора больше чем 0,1 вызывала большие нагрузки по сети при синхронизации пакетов

А зачем же вообще нужен курсор

Да для чего угодно, например для того чтобы:
  1. Рисовать в варкрафте как в Paint
  2. Делашть шутеры
  3. Делать интересные системы, требущие направления при касте (вспоминаем скил Пангольера или стенку Дарксира из Доты 2)
  4. Делать системы квиккастов, как вот в такой карте
  5. Рисовать заклинания как в серии игры Trine
  6. И самое главное, зачем мы все сегодня собрались это:
Делать так, чтобы башня вращалась вслед за курсором

А что же теперь

А теперь это всё может заменить на 2 ГУИ триггера (почти), если бы ГУИ был нормальным, то может быть и да, а так, там есть 1 нюанас
» нюанс
На ГУИ нельзя повернуть башню, которая находится на кости turret, на ГУИ можно указать только голову head и туловище chest
но это легко обойти, если переименовать кость в редакторе MDLVIS
Триггер 1: двигаем указатель вслед за курсором
Триггер 2: закрепляем кость танка за подвижным указателем
как раз таки кости turret и нет на скрине

А на Lua вот

» так вот
(Отредактировано Назаром, я бы так не смог)
do
    local tankId           = FourCC('hmtt') -- ID боевой машины, башней которой планируете крутить
    local pointerId        = FourCC('ewsp') -- ID  невидимого указателя, который будет следовать за курсором
    local tank             = {} -- массив боевых машин
    local pointer          = {} -- массив указателей
    local InitGlobalOrigin = InitGlobals
    function InitGlobals()
        InitGlobalOrigin()
        -- регистрация триггера с событием, "Мышь передвинута"
        local mouseMoveTrigger = CreateTrigger()
        -- смешение юнита указателя к курсору
        TriggerAddAction(mouseMoveTrigger, function()
            local id = GetPlayerId(GetTriggerPlayer())
            SetUnitX(pointer[id], BlzGetTriggerPlayerMouseX())
            SetUnitY(pointer[id], BlzGetTriggerPlayerMouseY())
        end)
        --
        for i = 0, bj_MAX_PLAYER_SLOTS - 1 do
            local player = Player(i)
            if GetPlayerSlotState(player) == PLAYER_SLOT_STATE_PLAYING and GetPlayerController(player) == MAP_CONTROL_USER then
                TriggerRegisterPlayerEvent(mouseMoveTrigger, player, EVENT_PLAYER_MOUSE_MOVE)
                tank[i]    = CreateUnit(player, tankId, GetPlayerStartLocationX(player), GetPlayerStartLocationY(player), 0)
                pointer[i] = CreateUnit(player, pointerId, 0, 0, 0)
                SetUnitLookAt(tank[i], 'bone_turret', pointer[i], 0, 0, 90)
            end
        end
    end
end
В принципе даже настройки выведены, надо указать лишь кто танк, а кто указатель, и в качестве указателя лучше использовать правильно настроенного Dummy (Неуязвимого москита, без тени и модели, и без обзора)
Как всегда видео образец и карта пример
(Обязательно приму замечания гуру луа и справлюсь, если что не так)
» Hive
В качестве подопытной, используется эта модель
Только у неё удалены анимации Stand -2, Stand -3, Walk-2, Walk-3
В которых башня вращается сама по себе

Просмотров: 622

pro100master #1 - 3 недели назад 0
Теперь сделай так чтобы дамми не перемешал а двигал к следом позиции со скоростью 2000. Это даст плавный поворот при 180 градусов. Ну много фич можеш замутить.
Bergi_Bear #2 - 3 недели назад 0
pro100master, да согласен, сейчас башня двигается рвано, зато мнгновенно, может это и лучше в игровом плане, потому что нет задержки при поворотах, хотя выглядит не очень
Koladik #3 - 3 недели назад (отредактировано ) 0
Осталось дождаться, когда дадут возможность проигрывать анимацию отдельных частей модельки независимо и можно будет делать выстрел или атаку в движении. Ото пока это тоже костылеписание с разделением модели на две части (хотя я и такой наработки не встречал)
NazarPunk #4 - 3 недели назад (отредактировано ) 0
Что если не использовать даммика, а заставить юнита смотреть на себя и манипулировать offset?
---@param whichUnit unit
---@param whichBone string
---@param lookAtTarget unit
---@param offsetX real
---@param offsetY real
---@param offsetZ real
function SetUnitLookAt(whichUnit, whichBone, lookAtTarget, offsetX, offsetY, offsetZ) end
Bergi_Bear #5 - 3 недели назад 0
NazarPunk, я давно пробовал заставить смотреть на самого себя, но была полная ерунда, чаще всего дуло загибается просто вниз
N1ghtSiren #6 - 3 недели назад 0
@Bergi_Bear, можете добавить проверку на 0.0, ибо когда мышь на интерфейсе либо в недоступной зоне, то отправляются нули
на 7й секунде видео это видно
NazarPunk #7 - 3 недели назад 0
можете добавить проверку на 0.0, ибо когда мышь на интерфейсе либо в недоступной зоне, то отправляются нули
на 7й секунде видео это видно
Это же демо пример, а не полноценная система. Можно ж ещё например попробовать создать одного даммика, ориентировать всех на него и с помощью матемагии манипулировать оффсетами.
Bergi_Bear #8 - 3 недели назад 0
N1ghtSiren, да на интерфейсе, на черных запрпедельных областях... как только начнем пилить полноценную карту на этой системе, тогда да, обязательно появится эти проверки и темка обновится
Steal nerves #9 - 3 недели назад (отредактировано ) 0
идея очень хорошая, возьму на вооружению (хотя что то такое и предлагал ранее)
а нельзя ли сделать без даймика, мб модель танка с вращающей пушкой (пример) сделать?
хотя если использовать даймика, что можно намутить конструктор танка (кто играл на сонька Warzone 2100 поймет): меняешь корпус или меняешь пушку. Это же классно. а вот с моделью танка наверн тяжелее?
у тебя пушка может подниматься наверх (горизонтальные наклоны нативка делает)? стрельба по возвышенным противникам или артиллерия
NazarPunk #10 - 3 недели назад 0
а нельзя ли сделать без даймика, мб модель танка сделать?
Можно поэксперементировать с направлением на себя или одним даммиком на всех.
Steal nerves #11 - 3 недели назад 0
NazarPunk, как это на себя?
NazarPunk #12 - 3 недели назад 0
как это на себя?
В SetUnitLookAt указать целью самого юнита.
Steal nerves #13 - 3 недели назад (отредактировано ) 0
хотя если использовать даймика, что можно намутить конструктор танка (кто играл на сонька Warzone 2100 поймет): меняешь корпус или меняешь пушку. Это же классно. а вот с моделью танка наверн тяжелее?
неправильно подумал. я думал там два юнита: сам корпус и перемещающая за корпусом пушка. а там значит целиком один юнит


еще помню констр-страйк в варкрафте от первого лица, мб делать снайперские выстрелы из танка
Proshel_Doty #14 - 3 недели назад 0
Ты смотри аккуратнее, там модель Генерала Франка

А так система норм тема
NazarPunk #15 - 3 недели назад (отредактировано ) 0
Ты смотри аккуратнее, там модель Генерала Франка
И что с того? Её же не режут на запчасти и не приклеивают к своей модели.
konvan5 #16 - 2 недели назад 0
На ГУИ нельзя повернуть башню, которая находится на кости turret, на ГУИ можно указать только голову head и туловище chest но это легко обойти, если переименовать кость в редакторе MDLVIS
Есть предположение, а через код можно ли указать другие кости кроме head и chest? Тогда не придется переименовывать их через mdlvis.
Bergi_Bear #17 - 2 недели назад 2
konvan5, да я имено это и сделал через код
SetUnitLookAt(tank[i], 'bone_turret', pointer[i], 0, 0, 90)
bone_turret