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

Содержание:
кратко: существуют экранные координаты (координаты на экране), так и мировые координаты (координаты на карте). Нам нужно вычислить координаты курсора мыши на экране. Близзард предоставили нам только нативки определения курсора мыши на карте.
Move Able Frame - система, которая позволяет перемещать фрейм за курсором мыши. Проблема вот в чем, игра не может нам выдать координаты мыши на экране, мы можем получить только координаты мыши на карте, которые недавно преподнесли разработчики игры. Мы не сможем переместить фрейм, не зная текущие координаты мыши на экране. Проблема была решена таким образом, создаются невидимые пустые-фреймы. Ранее был похожий пример. Когда курсор мыши наводят на фрейм, реагирует триггер. Но как этот пример поможет решить проблемы? А тут можно использовать этот же метод, только весь экран делим на клеточки. весь экран разбит на сетку фреймами 0,01x0,01 маленькие фреймы. Полный экран это 0.8, 0.6, получается фреймов 80x60=4800
Когда вы перемещает курсор мыши, вы всегда будете знать в какую часть экрана расположен курсор мыши. Когда курсор попадает внутри фрейма, вы будете знать в какой части экрана лежит курсор благодаря событиям фреймов
источник <= тут есть карта с lua-кодом, а в комментах коды jass и пр
memhack <= с такой проблемой возиться не нужно на старых патчах 1.26-1.27
mouse camera system еще один <= тут придумана система. только тут управление камерой фреймами. А не определение координат положения мыши. Возможно, тут на основе данных можно вращать не камеру, а мышь.
snippet-mouse-utility <= тут используют систему для нахождения игровых координат (не экранных!!!). Считают, что использовать нативки для определения курсора мыши плохо или неудобно, тк они используют события, а события движения мыши реагируют не чаще 0.15 сек.
framenet <= ну и еще один пример
Move Able Frame - это ресурс Lua, который позволяет пользователю перемещать фреймы с помощью перетаскивания (drag and drop). Другого применения кроме как перетаскивания не найти. Пользователь щелкает правой кнопкой мыши фрейм, и пока он удерживает правую кнопку мыши, фрейм будет следовать за мышью. Только фреймы, поддерживающие событие Frame Mouse Enter, могут быть перемещены с помощью этого ресурса. Он использует модифицированную версию глобального init от Bribe.
lua код - инициируем базу данных фреймов
--[[FrameGrid by Tasyen
--Got that Idea from CanFight, he mentioned something about a FPS game in which he clustered the screen with Frames to know the mouse position.
function FrameGrid.show(flag, player)
    show/hide the grid for player nil or GetLocalPlayer affect all players
--]]
FrameGrid = {}
FrameGrid.Boss = nil --the parent hide/show it to enable/disable the functionality of this system.
FrameGrid.GridFrames = {} --all grid frames
FrameGrid.GridFrames2 = {} --the tooltip frames of the grid
FrameGrid.LastFrame = 0 --the index of the frame hovered by the mouse, might be incorrect sometimes
onGameStart(function()
    --        print("FrameGrid.Init")
       
    FrameGrid.Timer = CreateTimer()
    TimerStart(FrameGrid.Timer, 0.01, true, FrameGrid.update)
    --the Grid Boss Frame its a BUTTON so it can have a higher Frame Level.
    --This Frame is used as on/off, when showing it the FrameGrid becomes active while it does nothing when Boss is disabled.
    FrameGrid.Boss = BlzCreateFrameByType("BUTTON", "FrameGridBoss", BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0),"",0)
    --be above other frames, using this allows to move into other frames but also stops their mouse enter events while FrameGrid is active.
    --I wasn't able to change this value at a later time hence there is no swap for this.
    --BlzFrameSetLevel(FrameGrid.Boss, 7)
  
    local xSize = 0.01 --dont go to low
    local ySize = 0.01 --dont go to low
    local yStart = ySize/2
    local xStart = xSize/2
    FrameGrid.FramesEachCol = 0.6 / ySize
    for x = xStart, 0.8, xSize do
        for y = yStart, 0.6, ySize do
            local newButton = BlzCreateFrameByType("FRAME", "", FrameGrid.Boss,"",0)
            local tooltipButton = BlzCreateFrameByType("FRAME", "", FrameGrid.Boss,"",0)
            BlzFrameSetAbsPoint(newButton, FRAMEPOINT_CENTER, x, y)
            BlzFrameSetSize(newButton, xSize, ySize)
            BlzFrameSetTooltip(newButton, tooltipButton)
            BlzFrameSetEnable(newButton, false)
            BlzFrameSetEnable(tooltipButton, false)
            FrameGrid[newButton] = {x, y}
            FrameGrid[tooltipButton] = {x, y}
            table.insert(FrameGrid.GridFrames, newButton)
            table.insert(FrameGrid.GridFrames2, tooltipButton)
        end
    end
   
    BlzFrameSetVisible(FrameGrid.Boss, false)
end)
Подвижная система такая:
lua код - проверяем
--[[
MoveAbleFrame (Mini) by Tasyen
MoveAbleFrame allows to drag&drop frames you have setuped to be moveable. This System is async do not use anthing of it in a sync manner. (Mini) does not save frame positions

function MoveAbleFrame.setup(frame)
    makes this frame moveable by user with drag and drop, only works on frameTypes supporting FRAMEEVENT_MOUSE_ENTER and FRAMEEVENT_MOUSE_LEAVE
    has to be called sync cause it creates events, unlike the other userMoveAbleFrame functions which should be used async
    The user changed position can be saved in a file and loaded. The frames are identyfied by the order, they were added to userMoveAbleFrame.
    Means when adding new userMoveAbleFrames not to the end (order wise), then a saved File can move a wrong frame when loading an File saved with an old version.

function MoveAbleFrame.enable(player[, flag])
    (dis)allows drag and drop moveable Frames for player, use GetLocalPlayer() to affect all players
    can be called without flag in such a case the current value is negated. true <-> false
    this has no impact on current done drag&dropping
    returns the value of MoveAbleFrame.Enabled
--]]
MoveAbleFrame = {}
MoveAbleFrame.Enabled = false --only when this is true, right clicking will have an effect on frames
MoveAbleFrame.Frame = nil -- the Frame beeing Moved
MoveAbleFrame.FramePoint = nil -- the FramePoint Frame is posed with nil = CENTER

function MoveAbleFrame.startMoving(frame, framePoint)
    MoveAbleFrame.Frame = frame
    if not framePoint then
       framePoint = FRAMEPOINT_CENTER
    end
    MoveAbleFrame.FramePoint = framePoint
    FrameGrid.show(true)
end

function MoveAbleFrame.moveFrame(x, y, finish)
    BlzFrameClearAllPoints(MoveAbleFrame.Frame)
    BlzFrameSetAbsPoint(MoveAbleFrame.Frame, MoveAbleFrame.FramePoint, x, y)
    if finish then
        FrameGrid.show(false)
    end
end

function MoveAbleFrame.enable(player, flag)
    if GetLocalPlayer() == player then
        if flag == nil then
            MoveAbleFrame.Enabled = not MoveAbleFrame.Enabled
        else
            MoveAbleFrame.Enabled = flag
        end
    end
    return MoveAbleFrame.Enabled
end

function MoveAbleFrame.setup(frame)
    if not MoveAbleFrame[frame] then
        MoveAbleFrame[frame] = true

        BlzTriggerRegisterFrameEvent(MoveAbleFrame.TriggerFrameEnter, frame, FRAMEEVENT_MOUSE_ENTER) --enable the hover feature
        BlzTriggerRegisterFrameEvent(MoveAbleFrame.TriggerFrameLeave , frame, FRAMEEVENT_MOUSE_LEAVE)
    end

end

onTriggerInit(function()
    xpcall(function()
    --        print("MoveAbleFrame.Init")

    --this is the FrameEnter Event trigger, every moveable Frame calls it, when entering remember the entere Frame
    MoveAbleFrame.TriggerFrameEnter = CreateTrigger()
    MoveAbleFrame.TriggerFrameEnterAction = TriggerAddAction(MoveAbleFrame.TriggerFrameEnter, function()
        if GetLocalPlayer() == GetTriggerPlayer() then
            MoveAbleFrame.PlayerHoveredFrame = BlzGetTriggerFrame()
        end
    end)

    MoveAbleFrame.TriggerFrameLeave = CreateTrigger()
    MoveAbleFrame.TriggerFrameLeaveAction = TriggerAddAction(MoveAbleFrame.TriggerFrameLeave, function()
        if GetLocalPlayer() == GetTriggerPlayer() then
            MoveAbleFrame.PlayerHoveredFrame = nil
        end
    end)

    MoveAbleFrame.MouseClickTrigger = CreateTrigger()
    MoveAbleFrame.MouseClickTriggerAction = TriggerAddAction(MoveAbleFrame.MouseClickTrigger, function()
        if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
            local player = GetTriggerPlayer()
            if MoveAbleFrame.PlayerHoveredFrame then
                --UI Edit Mode start moving that frame
                if MoveAbleFrame.Enabled then
                    if GetLocalPlayer() == player then
                        MoveAbleFrame.startMoving(MoveAbleFrame.PlayerHoveredFrame)
                        --disable the moving frame so it does not send mouse enter events, is more accurate to move and other frames are better respecected
                        BlzFrameSetEnable(MoveAbleFrame.PlayerHoveredFrame, false)
                    end
                end
            end
        end
    end)
    MoveAbleFrame.MouseReleaseTrigger = CreateTrigger()
    MoveAbleFrame.MouseReleaseTriggerAction = TriggerAddAction(MoveAbleFrame.MouseReleaseTrigger, function()
        if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
            --reenable the movedFrame, if there is one
            if MoveAbleFrame.Frame then
                BlzFrameSetEnable(MoveAbleFrame.Frame, true)
            end
            --UI Edit Mode start moving that frame
            FrameGrid.show(false, GetTriggerPlayer())
        end
    end)
  
    for playerIndex = 0, GetBJMaxPlayers()-1,1 do
        TriggerRegisterPlayerEvent(MoveAbleFrame.MouseClickTrigger, Player(playerIndex), EVENT_PLAYER_MOUSE_DOWN)
        TriggerRegisterPlayerEvent(MoveAbleFrame.MouseReleaseTrigger, Player(playerIndex), EVENT_PLAYER_MOUSE_UP)
    end
end, err)
end)
Проблема вот в чем, перемещение за курсором происходит рывками, как на gif-ке. Для того, чтобы получить сглаживание, необходимо следить за таймингами и уменьшать размер сетки, короче сделать размер фрейма еще меньше, чем было ранее (w=0.01, h=0.01). Но при создании сетки меньше чем 80x60 в сотни раз, мне комп говорит пока, и игра зависает сильно.
Нужно придумать такую систему, где либо используется минимальное число фреймов, и при этом при перемещении нет рывков.
Мне удавалось найти такие сочетания. Легко дебаг быстро определял координаты мыши. Однако, перемещения фреймов всегда происходят с задержками, рывками или зависаниями-дерганием. Замечал, что нативные функции фреймов медлительны. Для того, чтобы переместить его, делает с задержкой. Для того, чтобы скрыть/отобразить - тоже какая-то задержка. Появления подсказок - тоже не сразу появляются, на этом строится вся система отлова мыши. Ребята с хгм мне объяснили, что задержка происходит из-за синхронизации. Поэтому перетаскивания мб с рывками.
Еще проблема в том, что сетка часто накрывая экран, прячет куда-то дефолтный интерфейс. Происходит это из-за подобранного родителя. Если родителя ConsoleUIBackdrop подобрать, то у меня исчезают все кроме CommandBar. Дефотный можно заменить другим.
А еще главное требование - возможность кликать свободно по экрану. Посмотрел многие системы, и у некоторых проблемы с свободными кликами по карте: в точку, юниты, декор, итемы. Сетка накрывает сверху, и поэтому никак не выделить объекты на карте. Клики идут по фреймам сетки. Можно сделать зазор в данной точке, как только обнаруживается положение курсора, но это оч плохо работает. Задержками.
Способы оптимизации
Метод с уменьшением числа фреймов (!!не оптимизирована!!)
пример мы создаем фрейм размером 1 x 1. Пример экран забит 5x5 фреймами - 25 фреймов
мы можем уменьшить в несколько раз. Пример 5 горизонтальных фрейма (5x1) и 5 вертикальных фрейма (1x5). В итоге 5+5=10 фреймов
это сильно помогло бы уменьшить число фреймов. Вместо 80x60=4800 фреймов выше, могли бы сократить до 80+60=140 фреймов.
вывод: этот метод оптимизации плохой. Фреймы друг на друга наслаиваются, и вычислить можно только фрейм с высоким уровнем. Вам нужно будет перключать горизонтальную сетку - для проверки координаты y. А потом на вертикальную - для определния координаты x. А в промежутках отключать нужные фреймы (x,y), чтобы мышка могла кликать
Но тут то прокол: частота появления подсказок, короче нужно время для появления подсказки, нужен таймер с 0.01-0.02 сек. Когда вы отключаете выбранный фрейм, подсказка этого фрейма должна перестать работать. курсор перепрыгивает на другой фрейм, и подсказка сменяется. Смена происходит не сразу. Поэтому нужна задержка.
существует два таймера: основной и дополнительный. основной таймер каждые 1/3 сек запускает процесс проверки. здесь сразу же включаем показ горизонтальной сетки, через 0.01-0.02 сек доп таймером проверяем в каком горизонтальном фрейме лежит, и сразу же выключаем горизонтальную сетку и включаем вертикальную. через 0.01-0.02 сек доп таймером проверяем в каком вертикальном фрейм расположен, и сразу же выключаем. так мы получаем координаты x,y. Явный изврат с задержками, но что поделать то. Можно уменьшить, но главное вы поняли как работать с этим.
Вывод: Но такое очень плохо работает, дело в том, что фокус с фреймов снимается не сразу, обновляется не сразу, может что-то не обновится. И я все равно не смог сделать сглаживание, рывками перемещается. Тут со временем проблемы, каждый 0.03 сек запускает процесс проверки (включили сетку x), и еще два раза запускаем последовательно таймер 0.02 (проверили ось x, и выключили сетку x, включили сетку y потом задержка -> проверили ось y, выключили сетку).
кода и образцов не осталось.
вариант с зазорами (!!не работает!!)
кратко: не сказал бы, что плохо работает. Но и идеальным сложно назвать, пытался сделать объекты на карте максимально кликабельными, но такого сложно осуществить (в месте появления курсора фрейм исчезает, и появляется, как только курсор покидает область. В момент клика мб фрейм может не успеть исчезнуть). Размер сетки теперь можно уменьшить, что повысит точность. Но и проблемы остаются. Дело в том, что рывки все равно остаются, как бы не решали этот вопрос. Но зато они едва заметны. Тут зависит от того, как часто обновляется подсказка. Именно от этого зависит обновление информации. Если бы она сразу обновлялась, тогда не было никаких претензии, и создали бы идеальный костыль.
Можно переделать этот способ - создать зазоры между фреймами. типа так:
Вывод: пробовал использовать данный метод. Особое внимание - уменьшены фреймы до 1600 для сетки 0.001x0/001. Вроде работает хорошо, координаты быстро отображает. Но как только пытаешься двигать кнопку за курсором, то тут же возникают проблемы. Внимает забирает на себя эта кнопка, если только ее не отключить, и отключенной двигать. Вторая проблема (очень-очень важна!) - когда курсор лежит на вертикальном фрейме, я могу вдоль оси y двигать, не касаясь других, и почему то никак не замечаю изменения вдоль оси y - недостаток огромный.
Не знаю стоило ли скидывать код сюда?
II Метод разбивать фреймы на группы/секторы
Еще можно попробовать разбить экран на секторы. Изначально на весь экран создают сетку фреймов. Обычно когда у вас на экране очень много фреймов, у вас подлагивает. Стоит их отключить, спрятать. У отключенных фреймов не работают события, и у вас не должно подлагивать. Часть фреймов привязывают к одному большому фрейму, и так разбиваем на секторы. Когда курсор мыши входит в сектор, то включаем этот сетку сектора, а сетку старого отключаем. Надо просто включать часть фреймов и отключать другую часть.
Тут можно различными способами разбивать на секторы. Тут как вы хотите, так и будет. Есть различные варианты, я создал в качестве примера самый простой способ. Можно разбить экран на большую сетку 6x3 из 18 фреймов, каждый из которых может состоят из еще меньшей сетки. Как только курсор оказывается в одном из 18 больших фреймов, меняем большой фрейм на маленькую сетку. Маленькая сетка вычисляется по формуле, и зависит от размера size.
Мы прячем, и меняем так выбранный курсором фрейм на меньшую сетку, таким образом переключая с одного на другого. Дело в том, что не сразу меняется подсказка, нужна задержка 0.01-0.02 сек. Чем больше у вас сеток (большая, средняя, маленькая сетки фреймов), тем больше переключении => была самая большая 18, в одном из больших переключили на среднюю сетку => можно сделать еще переключения с средней на меньшую, если вам важна точность.
Можно по разному создавать систему. В одной из системы я видел как парень Nelloy создает сетку из 18 фреймов.
lua код
do
    local InitGlobalsOrigin = InitGlobals -- хукаем функцию InitGlobals

    function InitGlobals()
        InitGlobalsOrigin()

        --инициируем сетку
        
    function PXTODPI()
        return 0.6 / BlzGetLocalClientHeight()
    end

    function DPITOPX()
        return BlzGetLocalClientHeight() / 0.6
    end

    function FrameBoundWidth()
        return (BlzGetLocalClientWidth()-BlzGetLocalClientHeight()/600*800)/2
    end

    function GetScreenPosX(x)
        return (-FrameBoundWidth()+x)*PXTODPI()
    end

    function GetScreenPosY(y)
        return y*PXTODPI()
    end

    function ScreenRelativeX(x)
        return (x * DPITOPX()) * (0.8/BlzGetLocalClientWidth())
    end
        
            --print("инициируем большую сетку")
            --родитель большой сетки, короче всего экрана
            local parent = BlzGetFrameByName("ConsoleUIBackdrop", 0)
            --фрейм-кнопки
            local btns = {}
            --фрейм-подсказки
            local tools = {}
            
            --координаты
            local CoordXParentFrame = {}
            local CoordYParentFrame = {}
            local CoordXFrame = {}
            local CoordYFrame = {}

            --координата нижнего-левого угла
            local startx = GetScreenPosX(0.0)
            local starty = GetScreenPosY(0.0)
            --скалированный размер
            local ScaleSizeX = (startx^2)^0.5
            
            --размеры экрана
            local width = GetScreenPosX(BlzGetLocalClientWidth())+ScaleSizeX
            local height = GetScreenPosY(BlzGetLocalClientHeight())

            print("ширина: "..width.." ,высота: "..height)
            
            --БОЛЬШАЯ СЕТКА
                --кол-во строк и столбцов
                local COLS = 6
                local ROWS = 3     
                print("число строк: "..COLS.." ,число столбцов: "..ROWS)
                local xsize = width/6
                local ysize = height/3
            --МАЛЕНЬКАЯ СЕТКА
                local size = 0.01
                local countx = xsize/size
                local county = ysize/size
                local xoffset = size/2
                local yoffset = size/2
                local sbtns = {}
                local stools = {}
            --
             

            
            print("стартовые размеры экрана: "..startx..","..starty )
            BlzHideOriginFrames (true)
            BlzFrameSetScale(BlzFrameGetChild(BlzGetFrameByName("ConsoleUI",0),5), 0.001)
                
             for x = 1, COLS do
                 btns[x] = {}
                 tools[x] = {}
                 for y = 1, ROWS do
                    local sx =startx+(xsize*(x-1))
                    local sy =starty+(ysize*(y-1))
                    btns[x][y] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
                    BlzFrameSetAlpha(btns[x][y], 25)
                    BlzFrameSetAbsPoint(btns[x][y], FRAMEPOINT_BOTTOMLEFT, sx, sy)
                    BlzFrameSetSize(btns[x][y], xsize, ysize)
    
                    tools[x][y] = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
                    BlzFrameSetAlpha(tools[x][y], 0)
                    BlzFrameSetAbsPoint(tools[x][y], FRAMEPOINT_BOTTOMLEFT, 0, 0)
                    BlzFrameSetSize(tools[x][y], 0, 0)
                        
                    CoordXParentFrame[GetHandleId(btns[x][y])] = sx
                    CoordYParentFrame[GetHandleId(btns[x][y])] = sy
                        
                       
                    BlzFrameSetTooltip(btns[x][y], tools[x][y])
                 end
             end
             
             
            local grid = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
            BlzFrameSetAlpha(grid, 0)
            BlzFrameSetAbsPoint(grid, FRAMEPOINT_BOTTOMLEFT, 0, 0)
            BlzFrameSetSize(grid, size, size)
            --BlzFrameSetVisible(grid, false)
             
            for ax = 1, countx do
                sbtns[ax] = {}
                stools[ax] = {}
                for ay = 1, county do
                    sbtns[ax][ay] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", grid, "ScriptDialogButton", 0)
                    BlzFrameSetAlpha(sbtns[ax][ay], 25)
                    BlzFrameSetPoint(sbtns[ax][ay], FRAMEPOINT_CENTER, grid, FRAMEPOINT_BOTTOMLEFT, (size*(ax-1))+xoffset, (size*(ay-1))+xoffset)
                    BlzFrameSetSize(sbtns[ax][ay], size, size)
                    --BlzFrameSetVisible(sbtns[ax][ay], false)
                
                    stools[ax][ay] = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
                    BlzFrameSetAlpha(stools[ax][ay], 0)
                    BlzFrameSetAbsPoint(stools[ax][ay], FRAMEPOINT_CENTER, 0, 0)
                    BlzFrameSetSize(stools[ax][ay], 0, 0)
                    --BlzFrameSetVisible(stools[ax][ay], false)
                                    
                    CoordXFrame[GetHandleId(sbtns[ax][ay])] = (size*(ax-1))+xoffset
                    CoordYFrame[GetHandleId(sbtns[ax][ay])] = (size*(ay-1))+xoffset
                                    
                    BlzFrameSetTooltip(sbtns[ax][ay], stools[ax][ay])
                end
            end


            function ShowGrid(parent,show)
                local count = BlzFrameGetChildrenCount(parent)-1
                for i = 1, count do
                    BlzFrameSetVisible(BlzFrameGetChild(parent,i),show)
                end
                --if show then
                --    print("включить мелкую сетку "..CoordXParentFrame[GetHandleId(parent)]..","..CoordYParentFrame[GetHandleId(parent)])
                --else
                --    print("выключить мелкую сетку "..CoordXParentFrame[GetHandleId(parent)]..","..CoordYParentFrame[GetHandleId(parent)])
                --end
            end

            local frameblock = nil
            local lastframe = nil
            local sx
            local sy

             TimerStart(CreateTimer(),0.2,true,function()

                local b = true
                for x = 1, COLS do
                    for y = 1, ROWS do
                        local found = BlzFrameIsVisible(tools[x][y]) and lastframe ~= btns[x][y]
                        if (found) then
                            print("найден курсор в секторе "..x..","..y)
                            if lastframe ~= nil then
                                b = false
                                BlzFrameSetVisible(lastframe,true)
                            end
                            lastframe = btns[x][y]

                            sx =CoordXParentFrame[GetHandleId(lastframe)]
                            sy =CoordYParentFrame[GetHandleId(lastframe)]
                            print(sx..","..sy)
                            BlzFrameSetAbsPoint(grid, FRAMEPOINT_BOTTOMLEFT, sx, sy)
                            BlzFrameSetVisible(lastframe,false)

                            do return end
                        end
                    end
                end
                if b then
                
                    for ax = 1, countx do
                        for ay = 1, county do
                            local found = BlzFrameIsVisible(stools[ax][ay])
                            if (found) then
                                if frameblock ~= sbtns[ax][ay] then
                                    BlzFrameSetVisible(frameblock,true)
                                    frameblock = sbtns[ax][ay]
                                    BlzFrameSetVisible(frameblock,false)
                                
                                    print(CoordXParentFrame[GetHandleId(lastframe)]+CoordXFrame[GetHandleId(frameblock)]..","..CoordYParentFrame[GetHandleId(lastframe)]+CoordYFrame[GetHandleId(frameblock)])
                                    do return end
                                end
                            end
                        end
                    end
                end
                
                
             end)
             
            local MouseDown = CreateTrigger()
            TriggerRegisterPlayerMouseEventBJ( MouseDown, Player(0), bj_MOUSEEVENTTYPE_DOWN )
            TriggerAddAction( MouseDown, function ()
                BlzFrameSetVisible(grid,false)
            end)
            local MouseUp = CreateTrigger()
            TriggerRegisterPlayerMouseEventBJ( MouseUp, Player(0), bj_MOUSEEVENTTYPE_UP )
            TriggerAddAction( MouseUp, function ()
                BlzFrameSetVisible(grid,true)
            end)    
    end

end
Вывод:
проблемы те же. задержки, также плохо со свободным кликом по карте.
III Метод создать рамку вокруг курсора
В середине квадрата должен находится курсор мыши. Вокруг него 8 фреймов, когда курсор входит в один из них, то засекается tooltips, и сдвигаем. Короче квадрат должен двигаться за курсором. Как только вы пытаетесь сдвинуть курсор, то квадрат перемещается за курсором.
Недостаток: это работает очень плохо. Дело в том, что всплывающая подсказка (tooltip) появляется не сразу. И стоит быстро прокрутить мышь, и все. Курсор теперь лежит не внутри. Решение: растянуть на весь экран (см. ниже скрин). Тогда вы точно сможете найти координаты. Однако, обновляется не сразу. И эти фреймы теперь нельзя сделать прозрачными, придется использовать пустой шаблон вместо ScriptDialogButton. Вам нужно будет убрать “ScriptDialogButton”, чтобы они стали невидимыми
Недостаток: прямоугольная система из 8 фреймов перемещается не мгновенно. Стоит крутануть мышью из одного угла в другой угол экрана, то центр этих фреймов перемещается со скоростью b/interval. b - размер квадрата, interval - время таймера не меньше 0.01. Чем меньше размер b, тем выше точность, и одновременно, долгое перемещение. А вот interval зависим от tooltip, если сделать меньше 0.01, то подсказка не успевает скрыться, а уже таймер обработает несколько раз, что может вылететь за пределы экрана.
Иногда может дергаться, прыгать туда-туда. Причины неизвестны, возможна проблемы с размерами. Вот хотел заснять видео-пример, но при съемке прыгает. Поэтому мне и не удалось снять
lua код
do
    local real = MarkGameStarted
 function MarkGameStarted()
        real()

        local b = 0.01 --размер квадрата
        local c = 0.8
        local h = 0.6
        local a = b*3 --размер квадрата
       
        local offset = b  
        local cx,cy = 0.4,0.3 --координаты центра квадрата
        
        
        local parent = BlzGetFrameByName("ConsoleUIBackdrop", 0) 
        local gameUI = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
        local btns = {}
        local tools = {}
        local CoordX = {}
        local CoordY = {}

        --Верхний левый угол
        btns[1] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[1], 25)
        BlzFrameSetAbsPoint(btns[1], FRAMEPOINT_BOTTOMRIGHT,cx-b,cy+b)
        BlzFrameSetLevel(btns[1], 2)
        BlzFrameSetSize(btns[1], c, h)
        CoordX[GetHandleId(btns[1])]=cx-offset
        CoordY[GetHandleId(btns[1])]=cy+offset
        --верхний фрейм
        btns[2] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[2], 25)
        BlzFrameSetPoint(btns[2], FRAMEPOINT_BOTTOMLEFT, btns[1],FRAMEPOINT_BOTTOMRIGHT,0,0)
        BlzFrameSetLevel(btns[2], 2)
        BlzFrameSetSize(btns[2], b, h)
        CoordX[GetHandleId(btns[2])]=cx
        CoordY[GetHandleId(btns[2])]=cy+offset
        --Верхний правый угол
        btns[3] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[3], 25)
        BlzFrameSetPoint(btns[3], FRAMEPOINT_BOTTOMLEFT, btns[2],FRAMEPOINT_BOTTOMRIGHT,0,0)
        BlzFrameSetLevel(btns[3], 2)
        BlzFrameSetSize(btns[3], c, h)
        CoordX[GetHandleId(btns[3])]=cx+offset
        CoordY[GetHandleId(btns[3])]=cy+offset
        --правый фрейм
        btns[4] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[4], 25)
        BlzFrameSetPoint(btns[4], FRAMEPOINT_TOPLEFT, btns[3],FRAMEPOINT_BOTTOMLEFT,0,0)
        BlzFrameSetLevel(btns[4], 2)
        BlzFrameSetSize(btns[4], c, b)
        CoordX[GetHandleId(btns[4])]=cx+offset
        CoordY[GetHandleId(btns[4])]=cy
        --нижний правый угол
        btns[5] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[5], 25)
        BlzFrameSetPoint(btns[5], FRAMEPOINT_TOPRIGHT, btns[4],FRAMEPOINT_BOTTOMRIGHT,0,0)
        BlzFrameSetLevel(btns[5], 2)
        BlzFrameSetSize(btns[5], c, h)
        CoordX[GetHandleId(btns[5])]=cx+offset
        CoordY[GetHandleId(btns[5])]=cy-offset
        --нижний фрейм
        btns[6] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[6], 25)
        BlzFrameSetPoint(btns[6], FRAMEPOINT_TOPRIGHT, btns[5],FRAMEPOINT_TOPLEFT,0,0)
        BlzFrameSetLevel(btns[6], 2)
        BlzFrameSetSize(btns[6], b, h)
        CoordX[GetHandleId(btns[6])]=cx
        CoordY[GetHandleId(btns[6])]=cy-offset
        --нижний левый угол
        btns[7] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[7], 0)
        BlzFrameSetPoint(btns[7], FRAMEPOINT_TOPRIGHT, btns[6],FRAMEPOINT_TOPLEFT,0,0)
        BlzFrameSetLevel(btns[7], 2)
        BlzFrameSetSize(btns[7], c, h)
        CoordX[GetHandleId(btns[7])]=cx-offset
        CoordY[GetHandleId(btns[7])]=cy-offset
        --левый фрейм
        btns[8] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
        BlzFrameSetAlpha(btns[8], 25)
        BlzFrameSetPoint(btns[8], FRAMEPOINT_BOTTOMLEFT, btns[7],FRAMEPOINT_TOPLEFT,0,0)
        BlzFrameSetLevel(btns[8], 2)
        BlzFrameSetSize(btns[8], c, b)
        CoordX[GetHandleId(btns[8])]=cx-offset
        CoordY[GetHandleId(btns[8])]=cy
        
        
        for i = 1, 8 do
            tools[i] = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
            BlzFrameSetAlpha(tools[i], 0)
            BlzFrameSetAbsPoint(tools[i], FRAMEPOINT_BOTTOMLEFT, 0, 0)
            BlzFrameSetLevel(tools[i], 2)
            BlzFrameSetSize(tools[i], 0, 0)
            BlzFrameSetVisible(tools[i], false)
            BlzFrameSetTooltip(btns[i], tools[i])
        end
    
    --фитсируем курсор мышь в центре экрана
    TimerStart(CreateTimer(),0.1,false,function()
        BlzSetMousePos(BlzGetLocalClientWidth()/2, BlzGetLocalClientHeight()/2)
    
        --и таймером теперь чекаем
        TimerStart(CreateTimer(),0.01,true,function()
            for i = 1, 8 do
                local found = BlzFrameIsVisible(tools[i])
                if (found) then
                    --BlzFrameSetVisible(tools[i], false)
                    
                    cx = CoordX[GetHandleId(btns[i])]
                    cy = CoordY[GetHandleId(btns[i])]
                    print("найден курсор в секторе "..cx..","..cy)
                    
                    BlzFrameSetAbsPoint(btns[1], FRAMEPOINT_BOTTOMRIGHT,cx-b,cy+b)
                    CoordX[GetHandleId(btns[1])]=cx-offset
                    CoordY[GetHandleId(btns[1])]=cy+offset
                    
                    --BlzFrameSetAbsPoint(btns[2], FRAMEPOINT_LEFT,cx,cy+offset)
                    CoordX[GetHandleId(btns[2])]=cx
                    CoordY[GetHandleId(btns[2])]=cy+offset
                    
                    --BlzFrameSetAbsPoint(btns[3], FRAMEPOINT_LEFT,cx+offset,cy+offset)
                    CoordX[GetHandleId(btns[3])]=cx+offset
                    CoordY[GetHandleId(btns[3])]=cy+offset
                    
                    --BlzFrameSetAbsPoint(btns[4], FRAMEPOINT_LEFT,cx+offset,cy)
                    CoordX[GetHandleId(btns[4])]=cx+offset
                    CoordY[GetHandleId(btns[4])]=cy
                    
                    --BlzFrameSetAbsPoint(btns[5], FRAMEPOINT_LEFT,cx+offset,cy-offset)
                    CoordX[GetHandleId(btns[5])]=cx+offset
                    CoordY[GetHandleId(btns[5])]=cy-offset
                    
                    --BlzFrameSetAbsPoint(btns[6], FRAMEPOINT_LEFT,cx,cy-offset)
                    CoordX[GetHandleId(btns[6])]=cx+offset
                    CoordY[GetHandleId(btns[6])]=cy-offset
                    
                    --BlzFrameSetAbsPoint(btns[7], FRAMEPOINT_LEFT,cx-offset,cy-offset)
                    CoordX[GetHandleId(btns[7])]=cx-offset
                    CoordY[GetHandleId(btns[7])]=cy-offset
                    
                    --BlzFrameSetAbsPoint(btns[8], FRAMEPOINT_LEFT,cx-offset,cy)
                    CoordX[GetHandleId(btns[8])]=cx-offset
                    CoordY[GetHandleId(btns[8])]=cy
                    
                    
                    
                    break
                        
                end
            end
        end)
    end)
 end
end 
На видео не удалось это записать. дергаются че-то при записи. без записи работает норм.
IV Метод объединенный
Решил попробовать объединить II и III методы.
lua код
do
    local InitGlobalsOrigin = InitGlobals -- хукаем функцию InitGlobals

    function InitGlobals()
        InitGlobalsOrigin()

        --инициируем сетку
        
    function PXTODPI()
        return 0.6 / BlzGetLocalClientHeight()
    end

    function DPITOPX()
        return BlzGetLocalClientHeight() / 0.6
    end

    function FrameBoundWidth()
        return (BlzGetLocalClientWidth()-BlzGetLocalClientHeight()/600*800)/2
    end

    function GetScreenPosX(x)
        return (-FrameBoundWidth()+x)*PXTODPI()
    end

    function GetScreenPosY(y)
        return y*PXTODPI()
    end

    function ScreenRelativeX(x)
        return (x * DPITOPX()) * (0.8/BlzGetLocalClientWidth())
    end
        
        
        

            --print("инициируем большую сетку")
            --родитель большой сетки, короче всего экрана
            local parent = BlzGetFrameByName("ConsoleUIBackdrop", 0)
            --фрейм-кнопки
            local btns = {}
            --фрейм-подсказки
            local tools = {}
            
            --координаты
            local CoordXParentFrame = {}
            local CoordYParentFrame = {}
            local CoordXFrame = {}
            local CoordYFrame = {}

            --координата нижнего-левого угла
            local startx = GetScreenPosX(0.0)
            local starty = GetScreenPosY(0.0)
            --скалированный размер
            local ScaleSizeX = (startx^2)^0.5
            
            --размеры экрана
            local width = GetScreenPosX(BlzGetLocalClientWidth())+ScaleSizeX
            local height = GetScreenPosY(BlzGetLocalClientHeight())

            print("ширина: "..width.." ,высота: "..height)
            
            --БОЛЬШАЯ СЕТКА
                --кол-во строк и столбцов
                local COLS = 6
                local ROWS = 3     
                print("число строк: "..COLS.." ,число столбцов: "..ROWS)
                local xsize = width/6
                local ysize = height/3
            --МАЛЕНЬКАЯ СЕТКА
                local size = 0.01
                local countx = xsize/size
                local county = ysize/size
                local xoffset = size/2
                local yoffset = size/2
                local sbtns = {}
                local stools = {}
            --
             

            
            print("стартовые размеры экрана: "..startx..","..starty )
            BlzHideOriginFrames (true)
            BlzFrameSetScale(BlzFrameGetChild(BlzGetFrameByName("ConsoleUI",0),5), 0.001)
                
             for x = 1, COLS do
                 btns[x] = {}
                 tools[x] = {}
                 for y = 1, ROWS do
                    local sx =startx+(xsize*(x-1))
                    local sy =starty+(ysize*(y-1))
                    btns[x][y] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
                    BlzFrameSetAlpha(btns[x][y], 25)
                    BlzFrameSetAbsPoint(btns[x][y], FRAMEPOINT_BOTTOMLEFT, sx, sy)
                    BlzFrameSetLevel(btns[x][y], 4)
                    BlzFrameSetSize(btns[x][y], xsize, ysize)
    
                    tools[x][y] = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
                    BlzFrameSetAlpha(tools[x][y], 0)
                    BlzFrameSetAbsPoint(tools[x][y], FRAMEPOINT_BOTTOMLEFT, 0, 0)
                    BlzFrameSetSize(tools[x][y], 0, 0)
                        
                    CoordXParentFrame[GetHandleId(btns[x][y])] = sx
                    CoordYParentFrame[GetHandleId(btns[x][y])] = sy
                        
                       
                    BlzFrameSetTooltip(btns[x][y], tools[x][y])
                 end
             end
             
             
            local b = 0.01 --размер квадрата
            local c = width/6--0.8
            local h = height/3--0.6
            local a = b*3 --размер квадрата
       
            local offset = b  
            local cx,cy = 0.4,0.3 --координаты центра квадрата
        
            local sbtns = {}
            local stools = {}
            local CoordX = {}
            local CoordY = {}

            --Верхний левый угол
            sbtns[1] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
            BlzFrameSetAlpha(sbtns[1], 25)
            BlzFrameSetAbsPoint(sbtns[1], FRAMEPOINT_BOTTOMRIGHT,cx-b,cy+b)
            BlzFrameSetSize(sbtns[1], c, h)
            CoordX[GetHandleId(sbtns[1])]=cx-offset
            CoordY[GetHandleId(sbtns[1])]=cy+offset
            --верхний фрейм
            sbtns[2] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
            BlzFrameSetAlpha(sbtns[2], 25)
            BlzFrameSetPoint(sbtns[2], FRAMEPOINT_BOTTOMLEFT, sbtns[1],FRAMEPOINT_BOTTOMRIGHT,0,0)
            BlzFrameSetSize(sbtns[2], b, h)
            CoordX[GetHandleId(sbtns[2])]=cx
            CoordY[GetHandleId(sbtns[2])]=cy+offset
            --Верхний правый угол
            sbtns[3] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
            BlzFrameSetAlpha(sbtns[3], 25)
            BlzFrameSetPoint(sbtns[3], FRAMEPOINT_BOTTOMLEFT, sbtns[2],FRAMEPOINT_BOTTOMRIGHT,0,0)
            BlzFrameSetSize(sbtns[3], c, h)
            CoordX[GetHandleId(sbtns[3])]=cx+offset
            CoordY[GetHandleId(sbtns[3])]=cy+offset
            --правый фрейм
            sbtns[4] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
            BlzFrameSetAlpha(sbtns[4], 25)
            BlzFrameSetPoint(sbtns[4], FRAMEPOINT_TOPLEFT, sbtns[3],FRAMEPOINT_BOTTOMLEFT,0,0)
            BlzFrameSetSize(sbtns[4], c, b)
            CoordX[GetHandleId(sbtns[4])]=cx+offset
            CoordY[GetHandleId(sbtns[4])]=cy
            --нижний правый угол
            sbtns[5] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
            BlzFrameSetAlpha(sbtns[5], 25)
            BlzFrameSetPoint(sbtns[5], FRAMEPOINT_TOPRIGHT, sbtns[4],FRAMEPOINT_BOTTOMRIGHT,0,0)
            BlzFrameSetSize(sbtns[5], c, h)
            CoordX[GetHandleId(sbtns[5])]=cx+offset
            CoordY[GetHandleId(sbtns[5])]=cy-offset
            --нижний фрейм
            sbtns[6] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
            BlzFrameSetAlpha(sbtns[6], 25)
            BlzFrameSetPoint(sbtns[6], FRAMEPOINT_TOPRIGHT, sbtns[5],FRAMEPOINT_TOPLEFT,0,0)
            BlzFrameSetSize(sbtns[6], b, h)
            CoordX[GetHandleId(sbtns[6])]=cx
            CoordY[GetHandleId(sbtns[6])]=cy-offset
            --нижний левый угол
            sbtns[7] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
            BlzFrameSetAlpha(sbtns[7], 0)
            BlzFrameSetPoint(sbtns[7], FRAMEPOINT_TOPRIGHT, sbtns[6],FRAMEPOINT_TOPLEFT,0,0)
            BlzFrameSetSize(sbtns[7], c, h)
            CoordX[GetHandleId(sbtns[7])]=cx-offset
            CoordY[GetHandleId(sbtns[7])]=cy-offset
            --левый фрейм
            sbtns[8] = BlzCreateFrameByType("GLUETEXTBUTTON", "MyButton", parent, "ScriptDialogButton", 0)
            BlzFrameSetAlpha(sbtns[8], 25)
            BlzFrameSetPoint(sbtns[8], FRAMEPOINT_BOTTOMLEFT, sbtns[7],FRAMEPOINT_TOPLEFT,0,0)
            BlzFrameSetSize(sbtns[8], c, b)
            CoordX[GetHandleId(sbtns[8])]=cx-offset
            CoordY[GetHandleId(sbtns[8])]=cy
        
        
        for i = 1, 8 do
            stools[i] = BlzCreateFrameByType("FRAME", "FaceFrame", parent, "", 0)
            BlzFrameSetAlpha(stools[i], 0)
            BlzFrameSetAbsPoint(stools[i], FRAMEPOINT_BOTTOMLEFT, 0, 0)
            BlzFrameSetLevel(stools[i], 5)
            BlzFrameSetLevel(sbtns[i], 6)
            BlzFrameSetSize(stools[i], 0, 0)
            --BlzFrameSetVisible(sbtns[i], false)
            BlzFrameSetVisible(stools[i], false)
            BlzFrameSetTooltip(sbtns[i], stools[i])
        end

            local frameblock = nil
            local lastframe = nil
            local sx
            local sy

             TimerStart(CreateTimer(),0.1,true,function()

                for x = 1, COLS do
                    for y = 1, ROWS do
                        local found = BlzFrameIsVisible(tools[x][y]) and lastframe ~= btns[x][y]
                        if (found) then
                            print("найден курсор в секторе "..x..","..y)
                            if GetHandleId(lastframe)>0 then
                                BlzFrameSetVisible(lastframe,true)
                            end
                            lastframe = btns[x][y]
                            sx =CoordXParentFrame[GetHandleId(lastframe)]
                            sy =CoordYParentFrame[GetHandleId(lastframe)]
                            
                            print(sx..","..sy)
                            BlzFrameSetAbsPoint(sbtns[1], FRAMEPOINT_BOTTOMRIGHT, sx, sy)
                            CoordX[GetHandleId(sbtns[1])]=sx-offset
                            CoordY[GetHandleId(sbtns[1])]=sy+offset
                            
                            CoordX[GetHandleId(sbtns[2])]=sx
                            CoordY[GetHandleId(sbtns[2])]=sy+offset
                            
                            CoordX[GetHandleId(sbtns[3])]=sx+offset
                            CoordY[GetHandleId(sbtns[3])]=sy+offset
                            
                            CoordX[GetHandleId(sbtns[4])]=sx+offset
                            CoordY[GetHandleId(sbtns[4])]=sy
                            
                            CoordX[GetHandleId(sbtns[5])]=sx+offset
                            CoordY[GetHandleId(sbtns[5])]=sy-offset
                            
                            CoordX[GetHandleId(sbtns[6])]=sx+offset
                            CoordY[GetHandleId(sbtns[6])]=sy-offset
                            
                            CoordX[GetHandleId(sbtns[7])]=sx-offset
                            CoordY[GetHandleId(sbtns[7])]=sy-offset
                            
                            CoordX[GetHandleId(sbtns[8])]=sx-offset
                            CoordY[GetHandleId(sbtns[8])]=sy
                            
                            BlzFrameSetVisible(lastframe,false)

                           do return end
                        end
                    end
                end
                
             end)
        TimerStart(CreateTimer(),0.01,true,function()
            for i = 1, 8 do
                local found = BlzFrameIsVisible(stools[i])
                if (found) then
                    --BlzFrameSetVisible(stools[i], false)
                    
                    cx = CoordX[GetHandleId(sbtns[i])]
                    cy = CoordY[GetHandleId(sbtns[i])]
                    print("найден курсор в секторе "..cx..","..cy)
                    
                    BlzFrameSetAbsPoint(sbtns[1], FRAMEPOINT_BOTTOMRIGHT,cx-b,cy+b)
                    CoordX[GetHandleId(sbtns[1])]=cx-offset
                    CoordY[GetHandleId(sbtns[1])]=cy+offset
                    
                    --BlzFrameSetAbsPoint(sbtns[2], FRAMEPOINT_LEFT,cx,cy+offset)
                    CoordX[GetHandleId(sbtns[2])]=cx
                    CoordY[GetHandleId(sbtns[2])]=cy+offset
                    
                    --BlzFrameSetAbsPoint(sbtns[3], FRAMEPOINT_LEFT,cx+offset,cy+offset)
                    CoordX[GetHandleId(sbtns[3])]=cx+offset
                    CoordY[GetHandleId(sbtns[3])]=cy+offset
                    
                    --BlzFrameSetAbsPoint(sbtns[4], FRAMEPOINT_LEFT,cx+offset,cy)
                    CoordX[GetHandleId(sbtns[4])]=cx+offset
                    CoordY[GetHandleId(sbtns[4])]=cy
                    
                    --BlzFrameSetAbsPoint(sbtns[5], FRAMEPOINT_LEFT,cx+offset,cy-offset)
                    CoordX[GetHandleId(sbtns[5])]=cx+offset
                    CoordY[GetHandleId(sbtns[5])]=cy-offset
                    
                    --BlzFrameSetAbsPoint(sbtns[6], FRAMEPOINT_LEFT,cx,cy-offset)
                    CoordX[GetHandleId(sbtns[6])]=cx+offset
                    CoordY[GetHandleId(sbtns[6])]=cy-offset
                    
                    --BlzFrameSetAbsPoint(sbtns[7], FRAMEPOINT_LEFT,cx-offset,cy-offset)
                    CoordX[GetHandleId(sbtns[7])]=cx-offset
                    CoordY[GetHandleId(sbtns[7])]=cy-offset
                    
                    --BlzFrameSetAbsPoint(sbtns[8], FRAMEPOINT_LEFT,cx-offset,cy)
                    CoordX[GetHandleId(sbtns[8])]=cx-offset
                    CoordY[GetHandleId(sbtns[8])]=cy
                    
                    
                    
                    break
                        
                end
            end
        end)


    end

end
V Метод - использовать scrollbar (недоработка, просто идея)
Заметил, что когда нажимают на полоску, то ползунок (кнопка) перемещается туда, где мышь. Сам размер полосы можно задать, триггером можно зафиксировать значение между min b max. И сам scrollbar можно было растянуть на весь экран. Теоретически можно было сделать. Как триггером кликнуть фрейм? Нашел только BlzFrameClick(frame), но пока что не знаю, что за фрейм

Другие варианты

Или использовать какую нибудь вычислительную математику для конверта мировых в экранных.
Можно использовать фрейм курсора мыши, там просто нужно прикрепить к курсору фрейм нативкой BlzFrameSetPoint. И че-то не понимаю, как из нее можно получить координаты экрана. Ведь фреймовые нативки не имеют нужных нативок по выдаче координат окна.
Другой вариант использовать
DGUI - в этой системе есть конверт из мировых координат в оконные координаты. Или наоборот, из оконных в мировые. Однако, оно написано на Vjass, на рефордет оно прекрасно открывается.
PanelSystem - очень похожее на DGUI
Lua-wgeometry - эта 3D библиотека. Просто переписанная с DGUI. хотя библиотека очень топовая. По этой
Пока самый идеальный - это пример с хайва или тут. Пример с хайва хоть и рывками смещается, но они едва заметны. Пока не ясно насколько сильно просаживается fps, и нагружает компьютер. На пустой карте вообще не ощутимо. Предлагается автором карты включать/выключать в нужный момент родительский фрейм, чтобы отключить сетку.
Ее можно включать в нужный момент. Пример зельеварения, у вас есть ягода, которую нужно перенести в колбу. Пока можно сделать костылями это:
или стандартным способом с сеткой фреймов - просто перемещаем фрейм ягоды за курсором, а потом отпускаем ПКМ. И тут вам нужно отследить отпускание по колбе. Можно отслеживание вход курсора мыши в фрейм колбы.
ВАРИАНТ НЕ РАБОЧИЙ
  • есть другой вариант: здесь нам не нужна сетка. спрятать фрейм курсора, и нацепить BlzFrameSetPoint к курсору фрейм ягоды. И как только вы протащите фрейм к колбе, и кликнете по колбе. Сам курсор должен вернуться в норму. ВАРИАНТ НЕ РАБОТАЕТ: фрейм курсора, который мы нашли ранее, я не знаю что это. К нему нельзя привязать фрейм, а если можно, то игра вылетает. Поэтому никак нам не обратиться к нему
  • Можно попробовать сдвинуть фрейм по BlzGetTriggerPlayerMouseX() и BlzGetTriggerPlayerMouseY(). ВАРИАНТ НЕ БУДЕТ РАБОТАТЬ: не забывайте, что эти функции выдают игровые координаты. нужно затем перевести в экранные.
  • Можно изменить изображение курсора. Проблема как его заменить? И потом ловим вхождение курсор в фрейм, и отпускание ПКМ. Можно попробовать спрятать курсор. А вместо него попробовать двигать image, раз не получить экранные координаты, берем игровые.
Зная игровые координаты, некоторые можете перемещать скажем image:
function BlzGetTriggerPlayerMouseX() end    -- (native)
---@return real
function BlzGetTriggerPlayerMouseY() end    -- (native)
---@return location
function BlzGetTriggerPlayerMousePosition() end    -- (native)
Дальше должен быть разбор устройства камеры. И вывод. Но не стал сюда выводить. Тк я не совсем уверен, и не знаю как конвертить экранные и мировые.

Содержание
`
ОЖИДАНИЕ РЕКЛАМЫ...