Основы Интерфейса

Содержание:
это продолжение предыдущего урока.
кратко: можно подразделить экран на два разных поля - игровое поле (карта) и поле интерфейса (интерфейса).
Вы можете спросить а зачем это нужно? В разных ситуациях можно переделать интерфейс и вы можете регулировать различные процессы. Например, как узнать, что нажатие кнопки мыши происходит в игровом поле, а не внутри интерфейса?
В некоторых ситуациях, буду знать, что клик мыши произошел внутри интерфейса. И значит, могут ставить waypoints или чего нибудь еще.
перечисление причин
Например, в игре я вызвал таргет. И когда я навожу мышкой на точку, должно что-то происходить по задумке. Будль стройка или каст. Также я триггерами узнаю координаты на карте. В некоторых системах я например отслеживаю нажатие кнопки мыши (пример очередь приказов через SHIFT). Поскольку так я узнаю где, и как. Однако, когда курсор лежит внутри интерфейса, то это клики происходят не там. Система думает: "ага, клик произошел". А в игре мне выводят сообщение: "вы не можете навести", или прицел просто закрывается.
А еще есть забавная штука в рефордже - координаты мыши. Мы можешь узнать координаты мыши на карте. А как только мышь оказывается на верхней панеле интерфейса - тут же обнуляются координаты (0,0).
Например, я сделал самодельное “меню строительства”. Там контейнер из кнопок-фреймов, которое вызывается фрейм-кнопкой “меню строительства”. Пришлось менюшку строительства просто убрать. Иначе при клике таргет закрывается, когда там запрещено или чего то такое. При выборе одной из кнопки-фрейма здании вам открывается таргет-прицел, а по факту скрываем прицел. за курсором двигаем спецэффект в виде модели здания и индикатор из images. Вторая проблема, это курсор мыши нельзя пермаментно спрятать нативкой BlzEnableCursor(enable) тк настройка постоянно сбрасывается. Проблема сброса происходит из-за дефолтного интерфейса, если его скрыть то такого не происходит. Когда вы невидимый курсор перемещаете к интерфейсу, происходит сброс. Но я полностью не стал переделывать интерфейс, меня вполне устраивает и старый, и из-за этого сбросы. Но они решаются.
И самая главная причина, по которой я все это затеял - это из события мыши EVENT_PLAYER_MOUSE_MOVE - когда у вас таргет включен, мы двигаем курсор в пределах игрового поля, и пытаемся выбрать, у вас по событию меняются координаты мыши. Но это работает даже в пределах нижнего поля интерфейса, что очень не красиво. У меня даже отслеживается событие нажатие кнопки мыши, когда я щёлкаю по кнопкам интерфейса и пр.

Реализация идеи

Можно отслеживать событиями фреймов MOUSE_ENTER и MOUSE_LEAVE, когда курсор входит в фрейм или покидает фрейм. Еще можно отслеживать перемещается ли курсор по карте событием EVENT_PLAYER_MOUSE_MOVE
Пробовал отслеживать нахождение курсора в нижней части интерфейса, создана было 3 фрейма, отслеживалось событие MOUSE ENTER и MOUSE LEAVE:
У меня перестала работать мини-карта. Миникарту вижу, но не могу кликать. Все перепробовал, и уровни менять. Короче, все дело в том, что мини-карта видимо находится по уровню ниже, чем мой невидимый фрейм.
Поэтому я поменял обычно стандартного родителя BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI,0) на BlzGetFrameByName("ConsoleUIBackdrop", 0). Когда вы создаете фрейм вначале, он принимает уровень родителя, и ниже его опустить нельзя (хотя я не уверен, не тестил отрицательные значения). И меня перестало мучить. Теперь все фреймы находятся выше моего, тк BlzGetFrameByName("ConsoleUIBackdrop", 0) занимает почти самый низкий уровень.
Но я все равно испытывал не точности определения, когда мой курсор входит в один из фреймов: будь это любая кнопка CoomandBar, кнопка Items, портрет, миникарта или любая иконка центральной панели (защита, атака, характеристики), то у меня постоянно покидал наш фрейм, и входил в любой другой. Отследить такое было невозможно по началу.
update: на самом деле есть решение, но это нужно создать больше проверяющих фреймов. когда входите в игровое поле, то сразу прячем проверяющие вхождение в игровое поле фреймы, и показываем проверяющие фреймы на вход в поле интерфейса. Как только курсор окажется в поле интерфейса, то прячем фреймы поля интерфейса и показываем фреймы игрового поля. Так вы будете знать, где находятся фреймы. Но использовать для проверки события MOUSE ENTER, MOUSE LEAVE - плохое решение. Во первых, события медленные, и могут не зафиксировать входы/выходы мыши, как стоит курсор быстро прокрутить, и это не всегда фиксируется - только когда медленно водишь, тогда норм. а во-вторых, они фиксируют только заход и выход, если быстро прокрутить, то курсор может не зафиксировать заход, но ваш курсор уже находится внутри фрейма, значит события на такое не рассчитаны. Вывод: Рекомендовал проверять с помощью tooltips, вешаем на наши фреймы пустышки-tooltip и радуемся

Элементы интерфейса

Стоит еще проверять выскакивает ли вариковская подсказка ORIGIN_FRAME_UBERTOOLTIP , когда вы наводите курсором на элементы интерфейса: коммандные кнопки, итемы-кнопки, кнопка рабочих, полоса героев, часы, кнопки мини-карты, иконки и пр. Обычно эта подсказка невидима, но как только курсором навести на что-то, то всплывает подсказка, это подсказка может работать отдельно от вспомогательной подсказки.
Отдельная категория - миникарта и портрет. Они не выдают никаких подсказок, но нажатие на них смещает камеру. А отдача какого-нибудь приказа по миникарте, можно действительно вызвать приказ. Поэтому нужно как-то отслеживать приказы. Строительство в мини-карте не отмечают никак, нужно выбирать на карте. Я заметил, что это у таких таргетных абил есть прицел с возможностью навести на мини-карту

код опредения

lua код
--чекаем принадлежность курсора в игровом поле
  local cursorInGame = true
  TimerStart(CreateTimer(),0.0, false,function()
     local parent = BlzGetFrameByName("ConsoleUIBackdrop", 0)  
     local gameUI = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
     --DestroyTimer(GetExpiredTimer())
     --Screen - родитель игрового поля (т.е. экрана)
     local Screen = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
                
     --левая центральная
     local ScreenFrame1 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", Screen, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(ScreenFrame1, 50)
     BlzFrameSetAbsPoint(ScreenFrame1, FRAMEPOINT_CENTER, 0.1,0.154+((0.416)/2))
     BlzFrameSetSize(ScreenFrame1, 0.2, 0.416)
     --центральная игровая
     local ScreenFrame2 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", Screen, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(ScreenFrame2, 50)
     BlzFrameSetAbsPoint(ScreenFrame2, FRAMEPOINT_CENTER, 0.4,0.128+((0.442)/2))
     BlzFrameSetSize(ScreenFrame2, 0.4, 0.442)
     --правая центральная игровая
     local ScreenFrame3 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", Screen, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(ScreenFrame3, 50)
     BlzFrameSetAbsPoint(ScreenFrame3, FRAMEPOINT_CENTER, 0.7,0.154+((0.416)/2))
     BlzFrameSetSize(ScreenFrame3, 0.2, 0.416)
     --левая боковая игровая
     local ScreenFrame4 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", Screen, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(ScreenFrame4, 50)
     BlzFrameSetAbsPoint(ScreenFrame4, FRAMEPOINT_CENTER, -0.144/2,(0.164+0.410)/2)
     BlzFrameSetSize(ScreenFrame4, 0.144, 0.164+0.410)
     --правая боковая игровая
     local ScreenFrame5 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", Screen, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(ScreenFrame5, 50)
     BlzFrameSetAbsPoint(ScreenFrame5, FRAMEPOINT_CENTER, 0.8+0.144/2,(0.164+0.410)/2)
     BlzFrameSetSize(ScreenFrame5, 0.144, 0.164+0.410)

     --Sreentools - всплывающая подсказка-пустышка
     local Sreentools = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
     BlzFrameSetAlpha(Sreentools, 0)
     BlzFrameSetAbsPoint(Sreentools, FRAMEPOINT_BOTTOMLEFT, 0, 0)
     BlzFrameSetSize(Sreentools, 0, 0)
     BlzFrameSetTooltip(ScreenFrame1, Sreentools)
     BlzFrameSetTooltip(ScreenFrame2, Sreentools)
     BlzFrameSetTooltip(ScreenFrame3, Sreentools)
     BlzFrameSetTooltip(ScreenFrame4, Sreentools)
     BlzFrameSetTooltip(ScreenFrame5, Sreentools)
       
     --InterfaceField - родитель интерфейса
     local InterfaceField = BlzCreateFrameByType("FRAME", "FaceFrame", gameUI, "", 0)
            
     --левая нижняя панель
     local Interface1 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", InterfaceField, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(Interface1, 50)
     BlzFrameSetAbsPoint(Interface1, FRAMEPOINT_CENTER, 0.1, 0.144/2)
     BlzFrameSetSize(Interface1, 0.2, 0.154) --0.176
     --центральная панель
     local Interface2 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", InterfaceField, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(Interface2, 50)
     BlzFrameSetAbsPoint(Interface2, FRAMEPOINT_CENTER, 0.4, 0.118/2)
     BlzFrameSetSize(Interface2, 0.4, 0.128) --0.15
     --правая нижняя панель
     local Interface3 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", InterfaceField, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(Interface3, 50)
     BlzFrameSetAbsPoint(Interface3, FRAMEPOINT_CENTER, 0.7, 0.146/2)
     BlzFrameSetSize(Interface3, 0.2, 0.154) --0.176
     --верхняя панель
     local Interface4 = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
     BlzFrameSetAlpha(Interface4, 50)
     BlzFrameSetAbsPoint(Interface4, FRAMEPOINT_CENTER, 0.4, 0.6-(0.026/2))
     BlzFrameSetSize(Interface4, 1.088, 0.026) --0.176
           
     --Interfacetools - всплывающая подсказка поля интерфейса
     local Interfacetools = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
     BlzFrameSetAlpha(Interfacetools, 0)
     BlzFrameSetAbsPoint(Interfacetools, FRAMEPOINT_BOTTOMLEFT, 0, 0)
     BlzFrameSetSize(Interfacetools, 0, 0)
     BlzFrameSetTooltip(Interface1, Interfacetools)
     BlzFrameSetTooltip(Interface2, Interfacetools)
     BlzFrameSetTooltip(Interface3, Interfacetools)
     BlzFrameSetTooltip(Interface4, Interfacetools)
                
     TimerStart(CreateTimer(),1/32, true,function()
                    
        if BlzFrameIsVisible(Sreentools) then
            print("курсор в игровом поле")
            BlzFrameSetVisible(ScreenFrame1,false)
            BlzFrameSetVisible(ScreenFrame2,false)
            BlzFrameSetVisible(ScreenFrame3,false)
            BlzFrameSetVisible(ScreenFrame4,false)
            BlzFrameSetVisible(ScreenFrame5,false)
            BlzFrameSetVisible(InterfaceField,true)
            if GetLocalPlayer() ~= nil then
                cursorInGame = true
            end
        elseif BlzFrameIsVisible(Interfacetools) or BlzFrameIsVisible(BlzGetOriginFrame(ORIGIN_FRAME_UBERTOOLTIP,0)) then
            print("курсор в поле интерфейса")
            BlzFrameSetVisible(ScreenFrame1,true)
            BlzFrameSetVisible(ScreenFrame2,true)
            BlzFrameSetVisible(ScreenFrame3,true)
            BlzFrameSetVisible(ScreenFrame4,true)
            BlzFrameSetVisible(ScreenFrame5,true)
            BlzFrameSetVisible(InterfaceField,false)
            if GetLocalPlayer()~=nil then
                cursorInGame = false
            end                    
       end
                
    end)

  end)
Вроде клик на портреты можно отслеживать событием клика. Зарегистрируйте событие клика на портрет, и тогда вы можете узнать. Обычно это помогает, если нужно узнать нацеливание на юнита

Второй способ

этот способ позволяет обнаружить лежит ли курсор на ORIGIN_FRAME_WORLD_FRAME. Это более точный, чем первый вариант.
lua код
do
    local InitGlobalsOrigin = InitGlobals

    function InitGlobals()
        InitGlobalsOrigin()
        gameUI = BlzGetOriginFrame ( ORIGIN_FRAME_GAME_UI , 0 )
        WorldFrame = BlzGetOriginFrame ( ORIGIN_FRAME_WORLD_FRAME , 0 )
        tooltip = BlzCreateFrameByType("FRAME", "", gameUI, "", 0)
        BlzFrameSetTooltip(frame, tooltip)
        
         TimerStart(CreateTimer(), 1.0/32, true, function()        
                if BlzFrameIsVisible(tooltip) then
                    print("курсор мыши лежит")
                else
                    print("курсор мыши НЕ лежит")
                end
        end)
    end
end

Как привязать курсор к игровому полю?

чтобы курсор не выходил за пределы есть спец нативка, привязывающая курсор к фрейму
---@param frame framehandle
---@param enable boolean
---@return nothing
function BlzFrameCageMouse(frame, enable) end -- (native)
хотел когда сднлать привязку к игровому полю в режиме нацеливания. Но отказался. Эта выше функция привязывает курсор к фрейму, и не может покинуть пределы.

Содержание
`
ОЖИДАНИЕ РЕКЛАМЫ...
0
17
1 год назад
Отредактирован TNT
0
была задача устроить динамическую зависимость скорости или любого параметра персонажа от апм, типа быстрее кликаешь - быстрее бежишь или типа того..
Клики на интерфейс нужно было фильтровать, т.к. это позволяло бы читерить, ну и фейлится отлов координат клика.
Если кликать на интерфейс и обычной функцией реакции для мыши проверять позицию курсора, событие срабатывает возвращает 0 для х и у.
Если координата х = 0.000 , клик не проходит.Или у = 0.000, или оба, или y = x. Играем на том, что маловероятно попадание мышью точно в 0-ю абциссу или ординату.
Понимаю, что немного не про фреймы, но думаю может быть полезно
0
27
1 год назад
Отредактирован MpW
0
TNT, в рефе отлов координат экрана не работает, только мировые коорды. Можно нахождение курсора мыши внутри фрейма - велосипед изобрести. и работает, то медленно через ивент. Все, что вы описали очень не понятно и сложно осуществить без нужного функционала.
Надо пробовать через ujapi
0
17
1 год назад
0
На том, что отлов координат не работает на интерфейсе, этот способ и сработал.
Все делалось стандартными нативками...
1
32
1 год назад
1
Если кликать на интерфейс и обычной функцией реакции для мыши проверять позицию курсора, событие срабатывает возвращает 0 для х и у.
хороший способ, я тоже так делаю отлов клика по интерфейсу
Чтобы оставить комментарий, пожалуйста, войдите на сайт.