Приветствую, не могу понять, как реализовать:
У нас создан фрейм, когда зажата правая кнопка мыши на фрейме его можно перетаскивать, то есть фрейм следует за мышкой ?
Предпочтительно на jass.

Костылями. Воспользоваться любой существующей наработкой на определение экранных координат курсора (например, вот одна на математике камеры, вот вторая на тултипах), и двигать фрейм в координаты курсора по событию или по таймеру.
Но так чётко и синхронизировано как у близзов с инвентарём не получится, там вообще не фрейм, а текстура в модели курсора на иконку предмета меняется.
`
ОЖИДАНИЕ РЕКЛАМЫ...
38
Посмотри как делают на js draggable и сделай на жасс
Только события отличаются
Ответы (2)
11
ScorpioT1000, что то похожее попытался сделать по твоему примеру + все же по первому предложенному способу Makeba
Мне кажется нужно повысить ещё сильнее плавность или скорость перемещения, но уже выглядит хорошо и не нагружено
real moveSpeed = 0.2:
real moveSpeed = 0.1:
MoveAbleFrame
library MoveAbleFrame initializer onTriggerInit requires World2Screen
globals
real targetX = 0.0
real targetY = 0.0
real currentX = 0.0
real currentY = 0.0
real moveSpeed = 0.2 При скорости ниже 0.2 получаю сильное отставание от иконки, но невероятную плавность
endglobals
struct structMoveAbleFrame
boolean Enabled = true

framehandle Frame = null
framehandle PlayerHoveredFrame
framepointtype FramePoint
trigger TriggerFrameEnter
triggeraction TriggerFrameEnterAction
trigger TriggerFrameLeave
triggeraction TriggerFrameLeaveAction
trigger MouseClickTrigger
triggeraction MouseClickTriggerAction
trigger MouseReleaseTrigger
triggeraction MouseReleaseTriggerAction
trigger MOUSE_MOVE_Trigger
triggeraction MOUSE_MOVE_TriggerAction
endstruct
globals
structMoveAbleFrame MoveAbleFrame
endglobals
function enable takes player p, boolean flag returns boolean
if GetLocalPlayer() == p then
if flag == null then
set MoveAbleFrame.Enabled = not MoveAbleFrame.Enabled
else
set MoveAbleFrame.Enabled = flag
endif
endif
return MoveAbleFrame.Enabled
endfunction
function setup takes framehandle frame returns nothing
call BlzTriggerRegisterFrameEvent(MoveAbleFrame.TriggerFrameEnter, frame, FRAMEEVENT_MOUSE_ENTER)
call BlzTriggerRegisterFrameEvent(MoveAbleFrame.TriggerFrameLeave , frame, FRAMEEVENT_MOUSE_LEAVE)
endfunction
function startMoving takes framehandle frame, framepointtype framePoint returns nothing
set MoveAbleFrame.Frame = frame
if framePoint == null then
set framePoint = FRAMEPOINT_CENTER
endif
set MoveAbleFrame.FramePoint = framePoint
endfunction
function moveFrame takes real x, real y returns nothing
call BJDebugMsg("moveFrame: called x=" + R2S(x) + " y=" + R2S(y))
call BlzFrameClearAllPoints(MoveAbleFrame.Frame)
call BlzFrameSetAbsPoint(MoveAbleFrame.Frame, MoveAbleFrame.FramePoint, x, y)
endfunction
function GetTriggerPlayerHoveredFrame takes nothing returns nothing
if GetLocalPlayer() == GetTriggerPlayer() then
set MoveAbleFrame.PlayerHoveredFrame = BlzGetTriggerFrame()
endif
endfunction
function GetTriggerPlayerHoveredFrameNull takes nothing returns nothing
if GetLocalPlayer() == GetTriggerPlayer() then
set MoveAbleFrame.PlayerHoveredFrame = null
endif
endfunction
globals
location moveLoc = Location(0, 0)
boolean flag = false
endglobals
function MouseClick takes nothing returns nothing
local player p = GetTriggerPlayer()
local real x = BlzGetTriggerPlayerMouseX()
local real y = BlzGetTriggerPlayerMouseY()
local real z
call MoveLocation(moveLoc, x, y)
set z = GetLocationZ(moveLoc) Получаем Z-координату
call BJDebugMsg("MouseClick")
if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
if MoveAbleFrame.PlayerHoveredFrame != null then
call BJDebugMsg("MouseClick: frame is not null: " + BlzFrameGetName(MoveAbleFrame.PlayerHoveredFrame))
if MoveAbleFrame.Enabled then
if GetLocalPlayer() == p then
set flag = true Перемещение только если действительно кликнули по фрейму
call startMoving(MoveAbleFrame.PlayerHoveredFrame, FRAMEPOINT_CENTER)
call BlzFrameSetEnable(MoveAbleFrame.PlayerHoveredFrame, false)
call World2Screen(x,y,z)
call moveFrame(ScreenX,ScreenY)
endif
endif
else
call BJDebugMsg("MouseClick: PlayerHoveredFrame is null")
endif
endif
endfunction
function MouseRelease takes nothing returns nothing
call BJDebugMsg("MouseRelease")
set flag = false
if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
if MoveAbleFrame.Frame != null then
call BlzFrameSetEnable(MoveAbleFrame.Frame, true)
endif
endif
endfunction
function PolledWait2 takes real time returns nothing
local timer t
local real R
if time>0. then
set t = CreateTimer()
call TimerStart(t,time,false,null)
loop
set R=TimerGetRemaining(t)
exitwhen R<=0.
call TriggerSleepAction(R)
endloop
call DestroyTimer(t)
set t=null
endif
endfunction
function update2 takes nothing returns nothing
if flag == true then
Плавное приближение к целевой позиции
set currentX = currentX + (targetX - currentX) * moveSpeed
set currentY = currentY + (targetY - currentY) * moveSpeed
call moveFrame(currentX, currentY)
endif
endfunction
function CoordsMouse takes nothing returns nothing
local real x = BlzGetTriggerPlayerMouseX()
local real y = BlzGetTriggerPlayerMouseY()
local real z
if flag == true then
call MoveLocation(moveLoc, x, y)
set z = GetLocationZ(moveLoc)
call World2Screen(x,y,z)
call moveFrame(ScreenX,ScreenY)
set targetX = ScreenX
set targetY = ScreenY
endif
endfunction
function onTriggerInit takes nothing returns nothing
local integer playerIndex = 0
local timer Timer = CreateTimer()
call PolledWait2(0.01)
set MoveAbleFrame = structMoveAbleFrame.create()

set MoveAbleFrame.TriggerFrameEnter = CreateTrigger()
set MoveAbleFrame.TriggerFrameEnterAction = TriggerAddAction(MoveAbleFrame.TriggerFrameEnter,function GetTriggerPlayerHoveredFrame)

set MoveAbleFrame.TriggerFrameLeave = CreateTrigger()
set MoveAbleFrame.TriggerFrameLeaveAction = TriggerAddAction(MoveAbleFrame.TriggerFrameLeave, function GetTriggerPlayerHoveredFrameNull)
set MoveAbleFrame.MouseClickTrigger = CreateTrigger()
set MoveAbleFrame.MouseClickTriggerAction = TriggerAddAction(MoveAbleFrame.MouseClickTrigger, function MouseClick)

set MoveAbleFrame.MouseReleaseTrigger = CreateTrigger()
set MoveAbleFrame.MouseReleaseTriggerAction = TriggerAddAction(MoveAbleFrame.MouseReleaseTrigger, function MouseRelease)

set MoveAbleFrame.MOUSE_MOVE_Trigger = CreateTrigger()
set MoveAbleFrame.MOUSE_MOVE_TriggerAction = TriggerAddAction(MoveAbleFrame.MOUSE_MOVE_Trigger, function CoordsMouse)
loop
exitwhen playerIndex == GetBJMaxPlayers()
call TriggerRegisterPlayerEvent(MoveAbleFrame.MouseClickTrigger, Player(playerIndex), EVENT_PLAYER_MOUSE_DOWN)
call TriggerRegisterPlayerEvent(MoveAbleFrame.MouseReleaseTrigger, Player(playerIndex), EVENT_PLAYER_MOUSE_UP)
call TriggerRegisterPlayerEvent(MoveAbleFrame.MOUSE_MOVE_Trigger, Player(playerIndex), EVENT_PLAYER_MOUSE_MOVE)
set playerIndex = playerIndex + 1
endloop
call ExecuteFunc("onGameStart")
call TimerStart(Timer, 0.01, true, function update2)
endfunction
endlibrary
38
Smeto, попробуй экстраполяцию чутка добавить) просто прогноз, куда он подвинет через 0.01 или 0.05 сек. Тоесть двигаешь чуть дальше, чем надо, в зависимости от скорости движения мыши (delta = p2 - p1), delta - разница от предыдущей и текущей точки мыши
26
Принятый ответ
Костылями. Воспользоваться любой существующей наработкой на определение экранных координат курсора (например, вот одна на математике камеры, вот вторая на тултипах), и двигать фрейм в координаты курсора по событию или по таймеру.
Но так чётко и синхронизировано как у близзов с инвентарём не получится, там вообще не фрейм, а текстура в модели курсора на иконку предмета меняется.
Ответы (3)
11
Makeba, вторая система работает "Быстрее", но как по нагрузке не ясно
26
Smeto, у тултипов есть весомый плюс: они позволяют ловить курсор в мёртвой зоне в самом верху экрана (близзовская нативка там возвращает (0.0, 0.0) вместо мировых координат. В остальном там куча проблем, ибо в игре сходу нужно создать тысячи объектов, их нужно пересоздавать при загрузке сохранений и ещё придётся отслеживать разрешение игрока, чтобы заполнить весь экран клетками.
И координаты она возвращает грубые, так как используется сетка, а не реальные координаты, там прям мастхев lerp добавлять, чтобы не двигать фрейм лесенкой.

В спейс шуторе решал эту задачу более простым способом: я сразу фиксировал намертво игровую камеру перпендикулярно земле, и благодаря этому знал какие мировые координаты находятся на краях 0.8 x 0.6 экрана, но это специфический случай, применимый только к карте фул на фреймах.
38
Makeba, в DGUI можно в win2world и world2win в 3d, из минусов - ты обязан сам задавать камеру через его апи, чтобы это работало
11
Попробую ваши варианты, вернусь с ответом если выйдет, что то более качественное, спасибо!
Чтобы оставить комментарий, пожалуйста, войдите на сайт.