I recently noticed while making a long annoying interaction script, that using RunService to Bind and Unbind ContextActionService functions creates the problem where it works properly for PC but doesn’t work at all for mobile.
Small script example showcasing the problem:
RunService = game:GetService("RunService")
CAS = game:GetService("ContextActionService")
function ClickInteract(actionName, inputState)
if inputState == Enum.UserInputState.Begin then
print("something cool")
end
end
RunService.Heartbeat:Connect(function()
CAS:BindAction("Interact",ClickInteract,true, Enum.KeyCode.C)
CAS:SetPosition("Interact", UDim2.new(1, -70, 0, 10))
end)
My only option is to use a loop since the interactive script needs to always check what objects the player is near, when they’re close enough the action is binded and when they arent the action is unbinded.
Heres the actual script:
local plr = game.Players.LocalPlayer
repeat wait() until plr.Character
--Services--
local runService = game:GetService("RunService")
local CAS = game:GetService("ContextActionService")
local storage = game:GetService("ReplicatedStorage")
local RemoteEvents = storage:WaitForChild("RemoteEvents")
--Locals--
local char = plr.Character
local plrPosition = char.PrimaryPart.Position
local hrp = char:WaitForChild("HumanoidRootPart")
local InteractiveImage = script:WaitForChild("InteractiveImage")
--Bools--
local Interactive = nil
local DB = true
--[[=============================================================================================
I N T E R A C T I V E M A I N S C R I P T
===============================================================================================]]
local radius = 7
--[[----------------------------------------
Interactive Sorter
-------------------------------------------]]--
local function GetCloseInteractives(PartsNearPlayer)
local CloseInteractives = {}
---- Get Parts Near Player ----
for _,part in pairs(PartsNearPlayer) do
local Pickable = part.Parent:FindFirstChild("Pickable")
local PickablePart = part.Parent:FindFirstChild("PickablePart")
if PickablePart then
if Pickable.Value == true then
local mag = (part.Parent:FindFirstChild("PickablePart").Position - plr.Character.HumanoidRootPart.Position).Magnitude
table.insert(CloseInteractives, {Mag = mag, Part = part}) -- Put Part + Distance From Player in table
end
end
end
---- Sort Parts & Magnitudes ----
if #CloseInteractives == 1 then -- If only 1 close part then continue
return CloseInteractives[1].Part
elseif #CloseInteractives > 1 then -- If multiple close parts get closest part
table.sort(CloseInteractives, function(closest, other)
return closest.Mag < other.Mag
end)
return CloseInteractives[1].Part -- The first index in the table will be the closest part.
else
return nil
end
--------------------------------
end
--[[----------------------------------------
Interactive Module
-------------------------------------------]]--
runService.Heartbeat:Connect(function()
---- Create Region3 Field ----
local min = hrp.Position + radius * Vector3.new(-1,-1,-1)
local max = hrp.Position + radius * Vector3.new(1,1,1)
local region = Region3.new(min, max)
local PartsNearPlayer = workspace:FindPartsInRegion3WithIgnoreList(region,{char}, 100)
------------------------------
---- Close Interactives Manager ----
local ClosestInteractive = GetCloseInteractives(PartsNearPlayer)
if ClosestInteractive ~= nil and ClosestInteractive ~= Interactive then -- If there is an interactive close enough and it isnt the current interactive.
if Interactive == nil then -- If there is not an old interactive
Interactive = ClosestInteractive
else -- If there IS an old interactive
local PickablePart = Interactive.Parent:FindFirstChild("PickablePart")
if PickablePart:FindFirstChild("ShowingInteractive") then
PickablePart.ShowingInteractive:Destroy() -- Make the old interactive invisible.
end
Interactive = ClosestInteractive
end
local PickablePart = ClosestInteractive.Parent:FindFirstChild("PickablePart")
local ShowImage = InteractiveImage:Clone() -- Make the new interactive visible.
ShowImage.Parent = PickablePart
ShowImage.Enabled = true
ShowImage.Name = "ShowingInteractive"
elseif ClosestInteractive == nil then
if Interactive ~= nil then
local PickablePart = Interactive.Parent:FindFirstChild("PickablePart")
if PickablePart:FindFirstChild("ShowingInteractive") then
PickablePart.ShowingInteractive:Destroy() -- Make the old interactive invisible.
end
Interactive = nil
end
end
---- Binding Action ----
if Interactive ~= nil then
CAS:BindAction("Interact",ClickInteract,true, Enum.KeyCode.C)
CAS:SetPosition("Interact", UDim2.new(1, -70, 0, 10))
else
CAS:UnbindAction("Interact")
end
-------------------------
end)
-----------------------------------------------
function ClickInteract(actionName, inputState)
if inputState == Enum.UserInputState.Begin then
Interactive.Parent.PickablePart.ShowingInteractive:Destroy()
local InteractiveHub = require(storage.InteractiveHub)
InteractiveHub.FindEventToFire(plr, Interactive.Parent)
end
end