I made a frame movement system in vJass. It works perfectly smoothly in single-player mode, but if I launch it alone in a multiplayer game, all the smoothness is lost—even though I have 300+ FPS. However, if I lower the FPS to 270, the movement almost becomes as smooth as in single-player.
This is the first time I’ve encountered a case where visual performance depends on FPS in a multiplayer game, and the lower the FPS, the better the movement looks.
Help me solve the issue: at high FPS (300+), this code performs poorly in multiplayer mode—even when the map is launched with just 1 player.
Setting:
This is the first time I’ve encountered a case where visual performance depends on FPS in a multiplayer game, and the lower the FPS, the better the movement looks.
Help me solve the issue: at high FPS (300+), this code performs poorly in multiplayer mode—even when the map is launched with just 1 player.
Setting:
JASS:
globals
boolean RIGHT_MOUSE_BUTTON_FRAME_DRAG_ENABLE = false
boolean DRAG_TIMER_ENABLE = true
endglobals
JASS:
library MoveAbleFrame requires World2Screen
globals
real targetX = 0.0
real targetY = 0.0
real currentX = 0.0
real currentY = 0.0
real moveSpeed = 0.0125
real prevTargetX = 0.0
real prevTargetY = 0.0
real deltaX = 0.0
real deltaY = 0.0
boolean wasMoving
boolean PolledMoving = false
timer array PlayerTimer
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 BlzFrameClearAllPoints(MoveAbleFrame.Frame)
call BlzFrameSetAbsPoint(MoveAbleFrame.Frame, MoveAbleFrame.FramePoint, x, y)
endfunction
function GetTriggerPlayerHoveredFrame takes nothing returns nothing
local real x = BlzGetTriggerPlayerMouseX()
local real y = BlzGetTriggerPlayerMouseY()
//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 TempFrameSetting takes nothing returns nothing
call BlzFrameSetEnable(MoveAbleFrame.PlayerHoveredFrame, false)
call BlzFrameSetLevel(MoveAbleFrame.PlayerHoveredFrame, 9)
call BlzFrameSetScale(MoveAbleFrame.PlayerHoveredFrame, 0.8)
endfunction
function NormalFrameSetting takes nothing returns nothing
call BlzFrameSetScale(MoveAbleFrame.Frame, 1.0)
call BlzFrameSetEnable(MoveAbleFrame.Frame, true)
call BlzFrameSetLevel(MoveAbleFrame.Frame, 6)
set MoveAbleFrame.Frame = null
endfunction
globals
real mouseX = 0.0
real mouseY = 0.0
real mouseX_prev = 0.0
real mouseY_prev = 0.0
real mouseX_interp = 0.0
real mouseY_interp = 0.0
real interpProgress = 1.0
real interpSpeed = 0
endglobals
function UpdateTargetXYInstant takes nothing returns nothing
local real x = BlzGetTriggerPlayerMouseX()
local real y = BlzGetTriggerPlayerMouseY()
local real z
call MoveLocation(moveLoc, x, y)
set z = GetLocationZ(moveLoc)
call World2Screen(x, y, z)
// не трогаем prev/interp — сразу задаём target
set targetX = ScreenX
set targetY = ScreenY
endfunction
function UpdateMouseScreenCoords takes nothing returns nothing
local real x = BlzGetTriggerPlayerMouseX()
local real y = BlzGetTriggerPlayerMouseY()
local real z
call MoveLocation(moveLoc, x, y)
set z = GetLocationZ(moveLoc)
call World2Screen(x, y, z)
set mouseX_prev = mouseX
set mouseY_prev = mouseY
set mouseX = ScreenX
set mouseY = ScreenY
set mouseX_interp = mouseX
set mouseY_interp = mouseY
set interpProgress = 1.0
set targetX = mouseX
set targetY = mouseY
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 GetWorld2Screen takes nothing returns real
local real x = BlzGetTriggerPlayerMouseX()
local real y = BlzGetTriggerPlayerMouseY()
local real z
call MoveLocation(moveLoc, x, y)
set z = GetLocationZ(moveLoc)
call World2Screen(x, y, z)
return SquareRoot((currentX - ScreenX)*(currentX - ScreenX) + (currentY - ScreenY)*(currentY - ScreenY))
endfunction
function update2 takes nothing returns nothing
local real dx
local real dy
local real distMouse
local real dist
local real dynamicSpeed
local real speed = moveSpeed
set up = up + 1
call BJDebugMsg("update2 = " + I2S(up))
if MoveAbleFrame.Frame == null then
return
endif
if flag or wasMoving then
set dx = mouseX - mouseX_prev
set dy = mouseY - mouseY_prev
set distMouse = SquareRoot(dx * dx + dy * dy)
set interpSpeed = 0.1 + distMouse * 0.6
if interpSpeed > 0.3 then
set interpSpeed = 0.3
endif
set interpProgress = interpProgress + interpSpeed
if interpProgress > 1.0 then
set interpProgress = 1.0
endif
set mouseX_interp = mouseX_prev + (mouseX - mouseX_prev) * interpProgress
set mouseY_interp = mouseY_prev + (mouseY - mouseY_prev) * interpProgress
set targetX = mouseX_interp
set targetY = mouseY_interp
set dist = SquareRoot((targetX - currentX)*(targetX - currentX) + (targetY - currentY)*(targetY - currentY))
if dist < 0.05 then
set speed = moveSpeed + (0.05 - dist) * 2.0
if speed > 0.025 then
set speed = 0.025
endif
endif
set currentX = currentX * (1.0 - speed) + targetX * speed
set currentY = currentY * (1.0 - speed) + targetY * speed
call moveFrame(currentX, currentY)
if not flag and dist < 0.001 then
set wasMoving = false
call BlzFrameSetScale(MoveAbleFrame.Frame, 1.0)
call BlzFrameSetEnable(MoveAbleFrame.Frame, true)
call BlzFrameSetLevel(MoveAbleFrame.Frame, 6)
endif
endif
endfunction
globals
integer up = 0
endglobals
function MouseClick takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p) + 1
local real dist
local timer t
local boolean b = GetLocalPlayer() == p
if BlzGetTriggerPlayerMouseButton() == MOUSE_BUTTON_TYPE_RIGHT then
if MoveAbleFrame.Enabled then
if RIGHT_MOUSE_BUTTON_FRAME_DRAG_ENABLE then
if MoveAbleFrame.PlayerHoveredFrame != null then
call TimerStart(PlayerTimer[id], 0.001, b, function update2)
set flag = true
call startMoving(MoveAbleFrame.PlayerHoveredFrame, FRAMEPOINT_CENTER)
call TempFrameSetting()
call UpdateMouseScreenCoords()
set currentX = targetX
set currentY = targetY
call moveFrame(currentX, currentY)
else
set flag = false
set MoveAbleFrame.Frame = null
call PauseTimer(PlayerTimer[id])
endif
else
if MoveAbleFrame.PlayerHoveredFrame != null then
call TimerStart(PlayerTimer[id], 0.001, b, function update2)
set flag = not flag
set PolledMoving = not PolledMoving
if flag then
call startMoving(MoveAbleFrame.PlayerHoveredFrame, FRAMEPOINT_CENTER)
call UpdateMouseScreenCoords()
set currentX = targetX
set currentY = targetY
call moveFrame(currentX, currentY)
call TempFrameSetting()
else
call NormalFrameSetting()
call PauseTimer(PlayerTimer[id])
endif
else
if DRAG_TIMER_ENABLE then
if PolledMoving then
set PolledMoving = not PolledMoving
if GetWorld2Screen() > 0.0029 then
set t = CreateTimer()
call TimerStart(t, 0.15, false, null)
loop
set dist = GetWorld2Screen()
exitwhen dist < 0.002 or TimerGetRemaining(t) <= 0.
call TriggerSleepAction(0.01)
endloop
call DestroyTimer(t)
set t = null
endif
endif
endif
call PauseTimer(PlayerTimer[id])
set b = false
set flag = false
call NormalFrameSetting()
endif
endif
endif
endif
endfunction
function MouseRelease takes nothing returns nothing
local player p = GetTriggerPlayer()
local integer id = GetPlayerId(p) + 1
local real dist
if MoveAbleFrame.Frame == null then
return
endif
if RIGHT_MOUSE_BUTTON_FRAME_DRAG_ENABLE then
set dist = GetWorld2Screen()
if dist < 0.003 then
set flag = false
set wasMoving = true
set targetX = ScreenX
set targetY = ScreenY
else
if DRAG_TIMER_ENABLE then
call PolledWait2(0.15)
endif
set flag = false
set wasMoving = true
call UpdateTargetXYInstant()
endif
call PauseTimer(PlayerTimer[id])
call NormalFrameSetting()
endif
endfunction
function OnMouseMove takes nothing returns nothing
local real newX = BlzGetTriggerPlayerMouseX()
local real newY = BlzGetTriggerPlayerMouseY()
//set GetFunctionName_DEBUG = "OnMouseMove"
set mouseX_prev = mouseX
set mouseY_prev = mouseY
set mouseX = newX
set mouseY = newY
set interpProgress = 0.0
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)
set mouseX_prev = mouseX
set mouseY_prev = mouseY
set mouseX = ScreenX
set mouseY = ScreenY
set interpProgress = 0.0
endif
endfunction
function onTriggerInit takes nothing returns nothing
local integer playerIndex = 0
//local timer Timer = CreateTimer()
local integer i = 1
loop
exitwhen i == 13
set PlayerTimer[i] = CreateTimer()
set i = i + 1
endloop
//local timer Timer2 = 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("Init")
//call TimerStart(Timer, 0.001, true, function update2)
endfunction
endlibrary
JASS:
library Testb requires MoveAbleFrame
private function click takes nothing returns nothing
//call updateDebugFrame()
endfunction
private function enter takes nothing returns nothing
//call updateDebugFrame()
endfunction
function onGameStart takes nothing returns nothing
local framehandle gameUI = BlzGetFrameByName("ConsoleUIBackdrop", 0)
local trigger t = CreateTrigger()
local trigger t2 = CreateTrigger()
local framehandle b
local real size = 0.04
call TriggerAddAction(t, function click)
call TriggerAddAction(t2, function enter)
set b = BlzCreateFrameByType("GLUETEXTBUTTON", "b 1", gameUI, "ScriptDialogButton", 0)
call BlzFrameSetAbsPoint(b, FRAMEPOINT_CENTER, 0.55, 0.4)
call BlzFrameSetSize(b,size,size)
call BlzFrameSetText(b, "b 1")
call setup(b)
call BlzTriggerRegisterFrameEvent(t, b, FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(t2, b, FRAMEEVENT_MOUSE_ENTER)
set b = BlzCreateFrameByType("GLUETEXTBUTTON", "b 2", gameUI, "ScriptDialogButton", 0)
call BlzFrameSetAbsPoint(b, FRAMEPOINT_CENTER, 0.55, 0.35)
call BlzFrameSetSize(b,size,size)
call BlzFrameSetText(b, "b 2")
call setup(b)
call BlzTriggerRegisterFrameEvent(t, b, FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(t2, b, FRAMEEVENT_MOUSE_ENTER)
set b = BlzCreateFrameByType("GLUETEXTBUTTON", "b 3", gameUI, "ScriptDialogButton", 0)
call BlzFrameSetAbsPoint(b, FRAMEPOINT_CENTER, 0.55, 0.45)
call BlzFrameSetSize(b,size,size)
call BlzFrameSetText(b, "b 3")
call setup(b)
call BlzTriggerRegisterFrameEvent(t, b, FRAMEEVENT_CONTROL_CLICK)
call BlzTriggerRegisterFrameEvent(t2, b, FRAMEEVENT_MOUSE_ENTER)
//call enable(GetLocalPlayer(),true)
call BJDebugMsg(GetPlayerName(GetLocalPlayer()))
call BJDebugMsg("onGameStart END")
endfunction
endlibrary
