function Thumbstick.Enable(R)ThumbstickFrame.Visible=true end function Thumbstick.Disable(R)ThumbstickFrame.Visible=false OnTouchEnded()end function Thumbstick.Create(j,R)if ThumbstickFrame then ThumbstickFrame:Destroy()ThumbstickFrame=nil if OnTouchMovedCn then OnTouchMovedCn:disconnect()OnTouchMovedCn=nil end if OnTouchEndedCn then OnTouchEndedCn:disconnect()OnTouchEndedCn=nil end end local h=R.AbsoluteSize.y<=500 local q=h and 70 or 120 local y=h and UDim2.new(0,q/2-10,1,-q-20)or UDim2.new(0,q/2,1,-q*1.75)ThumbstickFrame=Instance.new("\070\114\097\109\101")ThumbstickFrame.Name="\084\104\117\109\098\115\116\105\099\107\070\114\097\109\101"ThumbstickFrame.Active=true ThumbstickFrame.Visible=false ThumbstickFrame.Size=UDim2.new(0,q,0,q)ThumbstickFrame.Position=y ThumbstickFrame.BackgroundTransparency=1 local b=Instance.new("\073\109\097\103\101\076\097\098\101\108")b.Name="\079\117\116\101\114\073\109\097\103\101"b.Image=TOUCH_CONTROL_SHEET b.ImageRectOffset=Vector2.new()b.ImageRectSize=Vector2.new(220,220)b.BackgroundTransparency=1 b.Size=UDim2.new(0,q,0,q)b.Position=UDim2.new(0,0,0,0)b.Parent=ThumbstickFrame StickImage=Instance.new("\073\109\097\103\101\076\097\098\101\108")StickImage.Name="\083\116\105\099\107\073\109\097\103\101"StickImage.Image=TOUCH_CONTROL_SHEET StickImage.ImageRectOffset=Vector2.new(220,0)StickImage.ImageRectSize=Vector2.new(111,111)StickImage.BackgroundTransparency=1 StickImage.Size=UDim2.new(0,q/2,0,q/2)StickImage.Position=UDim2.new(0,q/2-q/4,0,q/2-q/4)StickImage.ZIndex=2 StickImage.Parent=ThumbstickFrame local P=nil local v=.05 local function z(R)local j=R/(q/2)local h=j.magnitude if h<v then j=Vector3.new()else j=j.unit*((h-v)/(1-v))j=Vector3.new(j.x,0,j.y)end local y=getHumanoid()if y then y:Move(j,true)end end local function O(R)local j=Vector2.new(R.x-P.x,R.y-P.y)local h=j.magnitude local q=ThumbstickFrame.AbsoluteSize.x/2 if IsFollowStick and h>q then local h=j.unit*q ThumbstickFrame.Position=UDim2.new(0,(R.x-ThumbstickFrame.AbsoluteSize.x/2)-h.x,0,(R.y-ThumbstickFrame.AbsoluteSize.y/2)-h.y)else h=math.min(h,q)j=j.unit*h end StickImage.Position=UDim2.new(0,j.x+StickImage.AbsoluteSize.x/2,0,j.y+StickImage.AbsoluteSize.y/2)end ThumbstickFrame.InputBegan:connect(function(R)if MoveTouchObject or R.UserInputType~=Enum.UserInputType.Touch then return end MoveTouchObject=R ThumbstickFrame.Position=UDim2.new(0,R.Position.x-ThumbstickFrame.Size.X.Offset/2,0,R.Position.y-ThumbstickFrame.Size.Y.Offset/2)P=Vector2.new(ThumbstickFrame.AbsolutePosition.x+ThumbstickFrame.AbsoluteSize.x/2,ThumbstickFrame.AbsolutePosition.y+ThumbstickFrame.AbsoluteSize.y/2)local j=Vector2.new(R.Position.x-P.x,R.Position.y-P.y)O(R.Position)end)OnTouchMovedCn=UserInputService.TouchMoved:connect(function(R,j)if R==MoveTouchObject then P=Vector2.new(ThumbstickFrame.AbsolutePosition.x+ThumbstickFrame.AbsoluteSize.x/2,ThumbstickFrame.AbsolutePosition.y+ThumbstickFrame.AbsoluteSize.y/2)local j=Vector2.new(R.Position.x-P.x,R.Position.y-P.y)z(j)O(R.Position)end end)OnTouchEnded=function()ThumbstickFrame.Position=y StickImage.Position=UDim2.new(0,ThumbstickFrame.Size.X.Offset/2-q/4,0,ThumbstickFrame.Size.Y.Offset/2-q/4)MoveTouchObject=nil local R=getHumanoid()if R then R:Move(Vector3.new(0,0,0),true)end end OnTouchEndedCn=UserInputService.TouchEnded:connect(function(R,j)if R==MoveTouchObject then OnTouchEnded()end end)ThumbstickFrame.Parent=R end return Thumbstick
--[[ Public API ]]
--
function Thumbstick:Enable()
	ThumbstickFrame.Visible = true
end

function Thumbstick:Disable()
	ThumbstickFrame.Visible = false
	OnTouchEnded()
end

function Thumbstick:Create(parentFrame)
	if ThumbstickFrame then
		ThumbstickFrame:Destroy()
		ThumbstickFrame = nil
		if OnTouchMovedCn then
			OnTouchMovedCn:disconnect()
			OnTouchMovedCn = nil
		end
		if OnTouchEndedCn then
			OnTouchEndedCn:disconnect()
			OnTouchEndedCn = nil
		end
	end

	local isSmallScreen = parentFrame.AbsoluteSize.y <= 500
	local thumbstickSize = isSmallScreen and 70 or 120
	local position = isSmallScreen and UDim2.new(0, (thumbstickSize / 2) - 10, 1, -thumbstickSize - 20)
		or UDim2.new(0, thumbstickSize / 2, 1, -thumbstickSize * 1.75)

	ThumbstickFrame = Instance.new("Frame")
	ThumbstickFrame.Name = "ThumbstickFrame"
	ThumbstickFrame.Active = true
	ThumbstickFrame.Visible = false
	ThumbstickFrame.Size = UDim2.new(0, thumbstickSize, 0, thumbstickSize)
	ThumbstickFrame.Position = position
	ThumbstickFrame.BackgroundTransparency = 1

	local outerImage = Instance.new("ImageLabel")
	outerImage.Name = "OuterImage"
	outerImage.Image = TOUCH_CONTROL_SHEET
	outerImage.ImageRectOffset = Vector2.new()
	outerImage.ImageRectSize = Vector2.new(220, 220)
	outerImage.BackgroundTransparency = 1
	outerImage.Size = UDim2.new(0, thumbstickSize, 0, thumbstickSize)
	outerImage.Position = UDim2.new(0, 0, 0, 0)
	outerImage.Parent = ThumbstickFrame

	StickImage = Instance.new("ImageLabel")
	StickImage.Name = "StickImage"
	StickImage.Image = TOUCH_CONTROL_SHEET
	StickImage.ImageRectOffset = Vector2.new(220, 0)
	StickImage.ImageRectSize = Vector2.new(111, 111)
	StickImage.BackgroundTransparency = 1
	StickImage.Size = UDim2.new(0, thumbstickSize / 2, 0, thumbstickSize / 2)
	StickImage.Position =
		UDim2.new(0, thumbstickSize / 2 - thumbstickSize / 4, 0, thumbstickSize / 2 - thumbstickSize / 4)
	StickImage.ZIndex = 2
	StickImage.Parent = ThumbstickFrame

	local centerPosition = nil
	local deadZone = 0.05
	local function doMove(direction)
		local inputAxis = direction / (thumbstickSize / 2)

		-- Scaled Radial Dead Zone
		local inputAxisMagnitude = inputAxis.magnitude
		if inputAxisMagnitude < deadZone then
			inputAxis = Vector3.new()
		else
			inputAxis = inputAxis.unit * ((inputAxisMagnitude - deadZone) / (1 - deadZone))
			-- NOTE: Making inputAxis a unit vector will cause the player to instantly go max speed
			-- must check for zero length vector is using unit
			inputAxis = Vector3.new(inputAxis.x, 0, inputAxis.y)
		end

		local humanoid = getHumanoid()
		if humanoid then
			humanoid:Move(inputAxis, true)
		end
	end

	local function moveStick(pos)
		local relativePosition = Vector2.new(pos.x - centerPosition.x, pos.y - centerPosition.y)
		local length = relativePosition.magnitude
		local maxLength = ThumbstickFrame.AbsoluteSize.x / 2
		if IsFollowStick and length > maxLength then
			local offset = relativePosition.unit * maxLength
			ThumbstickFrame.Position = UDim2.new(
				0,
				pos.x - ThumbstickFrame.AbsoluteSize.x / 2 - offset.x,
				0,
				pos.y - ThumbstickFrame.AbsoluteSize.y / 2 - offset.y
			)
		else
			length = math.min(length, maxLength)
			relativePosition = relativePosition.unit * length
		end
		StickImage.Position = UDim2.new(
			0,
			relativePosition.x + StickImage.AbsoluteSize.x / 2,
			0,
			relativePosition.y + StickImage.AbsoluteSize.y / 2
		)
	end

	-- input connections
	ThumbstickFrame.InputBegan:connect(function(inputObject)
		if MoveTouchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch then
			return
		end

		MoveTouchObject = inputObject
		ThumbstickFrame.Position = UDim2.new(
			0,
			inputObject.Position.x - ThumbstickFrame.Size.X.Offset / 2,
			0,
			inputObject.Position.y - ThumbstickFrame.Size.Y.Offset / 2
		)
		centerPosition = Vector2.new(
			ThumbstickFrame.AbsolutePosition.x + ThumbstickFrame.AbsoluteSize.x / 2,
			ThumbstickFrame.AbsolutePosition.y + ThumbstickFrame.AbsoluteSize.y / 2
		)
		local direction =
			Vector2.new(inputObject.Position.x - centerPosition.x, inputObject.Position.y - centerPosition.y)
		moveStick(inputObject.Position)
	end)

	OnTouchMovedCn = UserInputService.TouchMoved:connect(function(inputObject, isProcessed)
		if inputObject == MoveTouchObject then
			centerPosition = Vector2.new(
				ThumbstickFrame.AbsolutePosition.x + ThumbstickFrame.AbsoluteSize.x / 2,
				ThumbstickFrame.AbsolutePosition.y + ThumbstickFrame.AbsoluteSize.y / 2
			)
			local direction =
				Vector2.new(inputObject.Position.x - centerPosition.x, inputObject.Position.y - centerPosition.y)
			doMove(direction)
			moveStick(inputObject.Position)
		end
	end)

	OnTouchEnded = function()
		ThumbstickFrame.Position = position
		StickImage.Position = UDim2.new(
			0,
			ThumbstickFrame.Size.X.Offset / 2 - thumbstickSize / 4,
			0,
			ThumbstickFrame.Size.Y.Offset / 2 - thumbstickSize / 4
		)
		MoveTouchObject = nil
		local humanoid = getHumanoid()
		if humanoid then
			humanoid:Move(Vector3.new(0, 0, 0), true)
		end
	end

	OnTouchEndedCn = UserInputService.TouchEnded:connect(function(inputObject, isProcessed)
		if inputObject == MoveTouchObject then
			OnTouchEnded()
		end
	end)

	ThumbstickFrame.Parent = parentFrame
end

return Thumbstick
