ContextActionService
is definitely your friend in these scenarios! Whenever you want to work with making sure an input is treated correctly in a certain environment, you can bind actions to events that change the environment, even at specific priorities, and even across multiple local scripts!
e.g, let’s use your example of making the mouse lock in place when on-screen, but drag a viewport gui when you mouse over it.
Let’s call this the CameraScript
:
local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
-- set up camera stuff
local x = 0 --camera's lateral movement
local y = 0 --camera's vertical movement
ContextActionService:BindActionAtPriority("CameraControls",function(name,state,input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
x = x + input.Delta.X
y = y + input.Delta.Y
elseif input.UserInputType == Enum.UserInputType.MouseButton2 then
if state == Enum.UserInputState.Begin then
UserInputService.MouseBehavior = Enum.MouseBehavior.LockCurrentPosition
elseif state == Enum.UserInputState.End then
UserInputService.MouseBehavior = Enum.MouseBehavior.Default
end
end
end, false, 0,
Enum.UserInputType.MouseMovement,
Enum.UserInputType.MouseButton2
)
And this would be in your gui script:
local ContextActionService = game:GetService("ContextActionService")
local viewport = --viewport frame
local function BindDrag(frame, mousePos)
local offset = Vector2.new(mousePos.X, mousePos.Y) - frame.AbsolutePosition
ContextActionService:BindActionAtPriority("StartDrag"..frame.Name, function(name, state, input)
--type will always = movement and state wil always = change
--might not be correct, just an example.
frame.Position = UDim2.new(0, input.X + offset.X, 0, input.Y + offset.Y)
end, false, 1, Enum.UserInputType.MouseMovement)
end
local function UnbindDrag(frame)
ContextActionService:UnbindAction("StartDrag"..frame.Name)
end
viewport.MouseEnter:Connect(function()
ContextActionService:BindActionAtPriority("DetectDrag"..viewport.Name, function(name,state,input)
--since we know it will always be MouseButton2, we don't account for type
if state == Enum.UserInputState.Begin then
BindDrag(viewport,input.Position)
elseif state == Enum.UserInputState.End then
UnbindDrag(viewport)
end
--default response if nil is returned, but just for good measure!
return Enum.ContextActionResult.Sink
end, false, 1, Enum.UserInputType.MouseButton2)
end)
viewport.MouseLeave:Connect(function()
ContextActionService:UnbindAction("DetectDrag"..viewport.Name)
end)
If you implement this into your game, MouseButton2
will be overridden by the DetectDrag
action whenever the viewport frame is hovering over, but will be unbound whenever you leave the frame, and similarly for MouseMovement
.
In more general terms, however, when dealing with priorities for changing a property, it’s better to:
-
Create an object for each script to control, instead of one object that every script controls
-
Force the getting and setting of properties to be handled from a single module script
-
Combine all reason for getting and setting that object’s properties into one module script/ normal script. This is the most common one.