function Thumbpad.Enable(H)ThumbpadFrame.Visible=true end function Thumbpad.Disable(H)ThumbpadFrame.Visible=false OnInputEnded()end function Thumbpad.Create(W,H)if ThumbpadFrame then ThumbpadFrame:Destroy()ThumbpadFrame=nil if OnTouchChangedCn then OnTouchChangedCn:disconnect()OnTouchChangedCn=nil end if OnTouchEndedCn then OnTouchEndedCn:disconnect()OnTouchEndedCn=nil end end local A=math.min(H.AbsoluteSize.x,H.AbsoluteSize.y)local T=A<=500 local y=T and 70 or 120 local G=T and UDim2.new(0,y*1.25,1,-y-20)or UDim2.new(0,y/2-10,1,-y*1.75-10)ThumbpadFrame=Instance.new("\070\114\097\109\101")ThumbpadFrame.Name="\084\104\117\109\098\112\097\100\070\114\097\109\101"ThumbpadFrame.Visible=false ThumbpadFrame.Active=true ThumbpadFrame.Size=UDim2.new(0,y+20,0,y+20)ThumbpadFrame.Position=G ThumbpadFrame.BackgroundTransparency=1 local j=Instance.new("\073\109\097\103\101\076\097\098\101\108")j.Name="\079\117\116\101\114\073\109\097\103\101"j.Image=TOUCH_CONTROL_SHEET j.ImageRectOffset=Vector2.new(0,0)j.ImageRectSize=Vector2.new(220,220)j.BackgroundTransparency=1 j.Size=UDim2.new(0,y,0,y)j.Position=UDim2.new(0,10,0,10)j.Parent=ThumbpadFrame local B=T and UDim2.new(0,32,0,32)or UDim2.new(0,64,0,64)local V=UDim2.new(0,B.X.Offset*2,0,B.Y.Offset*2)local d=Vector2.new(110,110)local p=T and-4 or-9 local s=T and-28 or-55 local R=createArrowLabel("\068\111\119\110\065\114\114\111\119",j,UDim2.new(.5,-B.X.Offset/2,1,s),B,Vector2.new(8,8),d)local E=createArrowLabel("\085\112\065\114\114\111\119",j,UDim2.new(.5,-B.X.Offset/2,0,p),B,Vector2.new(8,266),d)local X=createArrowLabel("\076\101\102\116\065\114\114\111\119",j,UDim2.new(0,p,.5,-B.Y.Offset/2),B,Vector2.new(137,137),d)local n=createArrowLabel("\082\105\103\104\116\065\114\114\111\119",j,UDim2.new(1,s,.5,-B.Y.Offset/2),B,Vector2.new(8,137),d)local function P(H,W,A)H:TweenSizeAndPosition(W,A,Enum.EasingDirection.InOut,Enum.EasingStyle.Linear,.15,true)end local g=nil local l=.1 local L,Z,r,u=false,false,false,false local I=Vector3.new(0,0,-1)local f=Vector3.new(1,0,0)local function U(H)MasterControl:AddToPlayerMovement(-currentMoveVector)local W=Vector2.new(H.x,H.y)-g currentMoveVector=W/(y/2)local A=currentMoveVector.magnitude if A<l then currentMoveVector=Vector3.new(0,0,0)else currentMoveVector=currentMoveVector.unit*((A-l)/(1-l))if currentMoveVector.magnitude==0 then currentMoveVector=Vector3.new(0,0,0)else currentMoveVector=(Vector3.new(currentMoveVector.x,0,currentMoveVector.y)).unit end end MasterControl:AddToPlayerMovement(currentMoveVector)local T=currentMoveVector:Dot(I)local G=currentMoveVector:Dot(f)if T>.5 then if not r then r,u=true,false P(E,V,UDim2.new(.5,-B.X.Offset,0,p-B.Y.Offset*1.5))P(R,B,UDim2.new(.5,-B.X.Offset/2,1,s))end elseif T<-0.5 then if not u then u,r=true,false P(R,V,UDim2.new(.5,-B.X.Offset,1,s+B.Y.Offset/2))P(E,B,UDim2.new(.5,-B.X.Offset/2,0,p))end else r,u=false,false P(R,B,UDim2.new(.5,-B.X.Offset/2,1,s))P(E,B,UDim2.new(.5,-B.X.Offset/2,0,p))end if G>.5 then if not L then L,Z=true,false P(n,V,UDim2.new(1,s+B.X.Offset/2,.5,-B.Y.Offset))P(X,B,UDim2.new(0,p,.5,-B.Y.Offset/2))end elseif G<-0.5 then if not Z then Z,L=true,false P(X,V,UDim2.new(0,p-B.X.Offset*1.5,.5,-B.Y.Offset))P(n,B,UDim2.new(1,s,.5,-B.Y.Offset/2))end else L,Z=false,false P(X,B,UDim2.new(0,p,.5,-B.Y.Offset/2))P(n,B,UDim2.new(1,s,.5,-B.Y.Offset/2))end end ThumbpadFrame.InputBegan:connect(function(H)if TouchObject or H.UserInputType~=Enum.UserInputType.Touch or H.UserInputState~=Enum.UserInputState.Begin then return end ThumbpadFrame.Position=UDim2.new(0,H.Position.x-ThumbpadFrame.AbsoluteSize.x/2,0,H.Position.y-ThumbpadFrame.Size.Y.Offset/2)g=Vector2.new(ThumbpadFrame.AbsolutePosition.x+ThumbpadFrame.AbsoluteSize.x/2,ThumbpadFrame.AbsolutePosition.y+ThumbpadFrame.AbsoluteSize.y/2)U(H.Position)TouchObject=H end)OnTouchChangedCn=UserInputService.TouchMoved:connect(function(H,W)if H==TouchObject then U(TouchObject.Position)end end)OnInputEnded=function()MasterControl:AddToPlayerMovement(-currentMoveVector)currentMoveVector=Vector3.new(0,0,0)MasterControl:SetIsJumping(false)ThumbpadFrame.Position=G TouchObject=nil r,u,Z,L=false,false,false,false P(R,B,UDim2.new(.5,-B.X.Offset/2,1,s))P(E,B,UDim2.new(.5,-B.X.Offset/2,0,p))P(X,B,UDim2.new(0,p,.5,-B.Y.Offset/2))P(n,B,UDim2.new(1,s,.5,-B.Y.Offset/2))end OnTouchEndedCn=UserInputService.TouchEnded:connect(function(H)if H==TouchObject then OnInputEnded()end end)GuiService.MenuOpened:connect(function()if TouchObject then OnInputEnded()end end)ThumbpadFrame.Parent=H end return Thumbpad
--[[ Public API ]]
--
function Thumbpad:Enable()
	ThumbpadFrame.Visible = true
end

function Thumbpad:Disable()
	ThumbpadFrame.Visible = false
	OnInputEnded()
end

function Thumbpad:Create(parentFrame)
	if ThumbpadFrame then
		ThumbpadFrame:Destroy()
		ThumbpadFrame = nil
		if OnTouchChangedCn then
			OnTouchChangedCn:disconnect()
			OnTouchChangedCn = nil
		end
		if OnTouchEndedCn then
			OnTouchEndedCn:disconnect()
			OnTouchEndedCn = nil
		end
	end

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

	ThumbpadFrame = Instance.new("Frame")
	ThumbpadFrame.Name = "ThumbpadFrame"
	ThumbpadFrame.Visible = false
	ThumbpadFrame.Active = true
	ThumbpadFrame.Size = UDim2.new(0, thumbpadSize + 20, 0, thumbpadSize + 20)
	ThumbpadFrame.Position = position
	ThumbpadFrame.BackgroundTransparency = 1

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

	local smArrowSize = isSmallScreen and UDim2.new(0, 32, 0, 32) or UDim2.new(0, 64, 0, 64)
	local lgArrowSize = UDim2.new(0, smArrowSize.X.Offset * 2, 0, smArrowSize.Y.Offset * 2)
	local imgRectSize = Vector2.new(110, 110)
	local smImgOffset = isSmallScreen and -4 or -9
	local lgImgOffset = isSmallScreen and -28 or -55

	local dArrow = createArrowLabel(
		"DownArrow",
		outerImage,
		UDim2.new(0.5, -smArrowSize.X.Offset / 2, 1, lgImgOffset),
		smArrowSize,
		Vector2.new(8, 8),
		imgRectSize
	)
	local uArrow = createArrowLabel(
		"UpArrow",
		outerImage,
		UDim2.new(0.5, -smArrowSize.X.Offset / 2, 0, smImgOffset),
		smArrowSize,
		Vector2.new(8, 266),
		imgRectSize
	)
	local lArrow = createArrowLabel(
		"LeftArrow",
		outerImage,
		UDim2.new(0, smImgOffset, 0.5, -smArrowSize.Y.Offset / 2),
		smArrowSize,
		Vector2.new(137, 137),
		imgRectSize
	)
	local rArrow = createArrowLabel(
		"RightArrow",
		outerImage,
		UDim2.new(1, lgImgOffset, 0.5, -smArrowSize.Y.Offset / 2),
		smArrowSize,
		Vector2.new(8, 137),
		imgRectSize
	)

	local function doTween(guiObject, endSize, endPosition)
		guiObject:TweenSizeAndPosition(
			endSize,
			endPosition,
			Enum.EasingDirection.InOut,
			Enum.EasingStyle.Linear,
			0.15,
			true
		)
	end

	local padOrigin = nil
	local deadZone = 0.1
	local isRight, isLeft, isUp, isDown = false, false, false, false
	local vForward = Vector3.new(0, 0, -1)
	local vRight = Vector3.new(1, 0, 0)
	local function doMove(pos)
		MasterControl:AddToPlayerMovement(-currentMoveVector)

		local delta = Vector2.new(pos.x, pos.y) - padOrigin
		currentMoveVector = delta / (thumbpadSize / 2)

		-- Scaled Radial Dead Zone
		local inputAxisMagnitude = currentMoveVector.magnitude
		if inputAxisMagnitude < deadZone then
			currentMoveVector = Vector3.new(0, 0, 0)
		else
			currentMoveVector = currentMoveVector.unit * ((inputAxisMagnitude - deadZone) / (1 - deadZone))
			-- catch possible NAN Vector
			if currentMoveVector.magnitude == 0 then
				currentMoveVector = Vector3.new(0, 0, 0)
			else
				currentMoveVector = Vector3.new(currentMoveVector.x, 0, currentMoveVector.y).unit
			end
		end

		MasterControl:AddToPlayerMovement(currentMoveVector)

		local forwardDot = currentMoveVector:Dot(vForward)
		local rightDot = currentMoveVector:Dot(vRight)
		if forwardDot > 0.5 then -- UP
			if not isUp then
				isUp, isDown = true, false
				doTween(
					uArrow,
					lgArrowSize,
					UDim2.new(0.5, -smArrowSize.X.Offset, 0, smImgOffset - smArrowSize.Y.Offset * 1.5)
				)
				doTween(dArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset / 2, 1, lgImgOffset))
			end
		elseif forwardDot < -0.5 then -- DOWN
			if not isDown then
				isDown, isUp = true, false
				doTween(
					dArrow,
					lgArrowSize,
					UDim2.new(0.5, -smArrowSize.X.Offset, 1, lgImgOffset + smArrowSize.Y.Offset / 2)
				)
				doTween(uArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset / 2, 0, smImgOffset))
			end
		else
			isUp, isDown = false, false
			doTween(dArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset / 2, 1, lgImgOffset))
			doTween(uArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset / 2, 0, smImgOffset))
		end

		if rightDot > 0.5 then
			if not isRight then
				isRight, isLeft = true, false
				doTween(
					rArrow,
					lgArrowSize,
					UDim2.new(1, lgImgOffset + smArrowSize.X.Offset / 2, 0.5, -smArrowSize.Y.Offset)
				)
				doTween(lArrow, smArrowSize, UDim2.new(0, smImgOffset, 0.5, -smArrowSize.Y.Offset / 2))
			end
		elseif rightDot < -0.5 then
			if not isLeft then
				isLeft, isRight = true, false
				doTween(
					lArrow,
					lgArrowSize,
					UDim2.new(0, smImgOffset - smArrowSize.X.Offset * 1.5, 0.5, -smArrowSize.Y.Offset)
				)
				doTween(rArrow, smArrowSize, UDim2.new(1, lgImgOffset, 0.5, -smArrowSize.Y.Offset / 2))
			end
		else
			isRight, isLeft = false, false
			doTween(lArrow, smArrowSize, UDim2.new(0, smImgOffset, 0.5, -smArrowSize.Y.Offset / 2))
			doTween(rArrow, smArrowSize, UDim2.new(1, lgImgOffset, 0.5, -smArrowSize.Y.Offset / 2))
		end
	end

	--input connections
	ThumbpadFrame.InputBegan:connect(function(inputObject)
		--A touch that starts elsewhere on the screen will be sent to a frame's InputBegan event
		--if it moves over the frame. So we check that this is actually a new touch (inputObject.UserInputState ~= Enum.UserInputState.Begin)
		if
			TouchObject
			or inputObject.UserInputType ~= Enum.UserInputType.Touch
			or inputObject.UserInputState ~= Enum.UserInputState.Begin
		then
			return
		end

		ThumbpadFrame.Position = UDim2.new(
			0,
			inputObject.Position.x - ThumbpadFrame.AbsoluteSize.x / 2,
			0,
			inputObject.Position.y - ThumbpadFrame.Size.Y.Offset / 2
		)
		padOrigin = Vector2.new(
			ThumbpadFrame.AbsolutePosition.x + ThumbpadFrame.AbsoluteSize.x / 2,
			ThumbpadFrame.AbsolutePosition.y + ThumbpadFrame.AbsoluteSize.y / 2
		)
		doMove(inputObject.Position)
		TouchObject = inputObject
	end)

	OnTouchChangedCn = UserInputService.TouchMoved:connect(function(inputObject, isProcessed)
		if inputObject == TouchObject then
			doMove(TouchObject.Position)
		end
	end)

	OnInputEnded = function()
		MasterControl:AddToPlayerMovement(-currentMoveVector)
		currentMoveVector = Vector3.new(0, 0, 0)
		MasterControl:SetIsJumping(false)

		ThumbpadFrame.Position = position
		TouchObject = nil
		isUp, isDown, isLeft, isRight = false, false, false, false
		doTween(dArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset / 2, 1, lgImgOffset))
		doTween(uArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset / 2, 0, smImgOffset))
		doTween(lArrow, smArrowSize, UDim2.new(0, smImgOffset, 0.5, -smArrowSize.Y.Offset / 2))
		doTween(rArrow, smArrowSize, UDim2.new(1, lgImgOffset, 0.5, -smArrowSize.Y.Offset / 2))
	end

	OnTouchEndedCn = UserInputService.TouchEnded:connect(function(inputObject)
		if inputObject == TouchObject then
			OnInputEnded()
		end
	end)

	GuiService.MenuOpened:connect(function()
		if TouchObject then
			OnInputEnded()
		end
	end)

	ThumbpadFrame.Parent = parentFrame
end

return Thumbpad
