function DynamicThumbstick.OnInputEnded(a)a.moveTouchObject=nil a.moveVector=ZERO_VECTOR3 a:FadeThumbstick(false)end function DynamicThumbstick.FadeThumbstick(U,a)if not a and U.moveTouchObject then return end if U.isFirstTouch then return end if U.startImageFadeTween then U.startImageFadeTween:Cancel()end if U.endImageFadeTween then U.endImageFadeTween:Cancel()end for a=1,#U.middleImages,1 do if U.middleImageFadeTweens[a]then U.middleImageFadeTweens[a]:Cancel()end end if a then U.startImageFadeTween=TweenService:Create(U.startImage,ThumbstickFadeTweenInfo,{ImageTransparency=0})U.startImageFadeTween:Play()U.endImageFadeTween=TweenService:Create(U.endImage,ThumbstickFadeTweenInfo,{ImageTransparency=.2})U.endImageFadeTween:Play()for a=1,#U.middleImages,1 do U.middleImageFadeTweens[a]=TweenService:Create(U.middleImages[a],ThumbstickFadeTweenInfo,{ImageTransparency=MIDDLE_TRANSPARENCIES[a]})U.middleImageFadeTweens[a]:Play()end else U.startImageFadeTween=TweenService:Create(U.startImage,ThumbstickFadeTweenInfo,{ImageTransparency=1})U.startImageFadeTween:Play()U.endImageFadeTween=TweenService:Create(U.endImage,ThumbstickFadeTweenInfo,{ImageTransparency=1})U.endImageFadeTween:Play()for a=1,#U.middleImages,1 do U.middleImageFadeTweens[a]=TweenService:Create(U.middleImages[a],ThumbstickFadeTweenInfo,{ImageTransparency=1})U.middleImageFadeTweens[a]:Play()end end end function DynamicThumbstick.FadeThumbstickFrame(q,a,U)q.fadeInAndOutHalfDuration=a*.5 q.fadeInAndOutBalance=U q.tweenInAlphaStart=tick()end function DynamicThumbstick.InputInFrame(U,a)local q=U.thumbstickFrame.AbsolutePosition local y=q+U.thumbstickFrame.AbsoluteSize local i=a.Position if i.X>=q.X and i.Y>=q.Y then if i.X<=y.X and i.Y<=y.Y then return true end end return false end function DynamicThumbstick.DoFadeInBackground(a)local U=LocalPlayer:FindFirstChildOfClass("\080\108\097\121\101\114\071\117\105")local q=false if U then if U.CurrentScreenOrientation==Enum.ScreenOrientation.LandscapeLeft or U.CurrentScreenOrientation==Enum.ScreenOrientation.LandscapeRight then q=a.hasFadedBackgroundInLandscape a.hasFadedBackgroundInLandscape=true elseif U.CurrentScreenOrientation==Enum.ScreenOrientation.Portrait then q=a.hasFadedBackgroundInPortrait a.hasFadedBackgroundInPortrait=true end end if not q then a.fadeInAndOutHalfDuration=FADE_IN_OUT_HALF_DURATION_DEFAULT a.fadeInAndOutBalance=FADE_IN_OUT_BALANCE_DEFAULT a.tweenInAlphaStart=tick()end end function DynamicThumbstick.DoMove(U,a)local q=a local y=q.magnitude if y<U.radiusOfDeadZone then q=ZERO_VECTOR3 else q=q.unit*(1-math.max(0,(U.radiusOfMaxSpeed-q.magnitude)/U.radiusOfMaxSpeed))q=Vector3.new(q.x,0,q.y)end U.moveVector=q end function DynamicThumbstick.LayoutMiddleImages(q,a,U)local y=q.thumbstickSize/2+q.middleSize local i=U-a local T=(i.magnitude-q.thumbstickRingSize/2)-q.middleSize local v=i.unit local C=q.middleSpacing*NUM_MIDDLE_IMAGES local s=q.middleSpacing if C<T then s=T/NUM_MIDDLE_IMAGES end for a=1,NUM_MIDDLE_IMAGES,1 do local i=q.middleImages[a]local C=y+s*(a-2)local K=y+s*(a-1)if C<T then local a=U-v*K local y=math.clamp(1-(K-T)/s,0,1)i.Visible=true i.Position=UDim2.new(0,a.X,0,a.Y)i.Size=UDim2.new(0,q.middleSize*y,0,q.middleSize*y)else i.Visible=false end end end function DynamicThumbstick.MoveStick(U,a)local q=Vector2.new(U.moveTouchStartPosition.X,U.moveTouchStartPosition.Y)local y=q-U.thumbstickFrame.AbsolutePosition local i=Vector2.new(a.X,a.Y)-U.thumbstickFrame.AbsolutePosition U.endImage.Position=UDim2.new(0,i.X,0,i.Y)U:LayoutMiddleImages(y,i)end function DynamicThumbstick.BindContextActions(a)local function U(U)if a.moveTouchObject then return Enum.ContextActionResult.Pass end if not a:InputInFrame(U)then return Enum.ContextActionResult.Pass end if a.isFirstTouch then a.isFirstTouch=false local U=TweenInfo.new(.5,Enum.EasingStyle.Quad,Enum.EasingDirection.Out,0,false,0);(TweenService:Create(a.startImage,U,{Size=UDim2.new(0,0,0,0)})):Play();(TweenService:Create(a.endImage,U,{Size=UDim2.new(0,a.thumbstickSize,0,a.thumbstickSize),ImageColor3=Color3.new(0,0,0)})):Play()end a.moveTouchLockedIn=false a.moveTouchObject=U a.moveTouchStartPosition=U.Position a.moveTouchFirstChanged=true if FADE_IN_OUT_BACKGROUND then a:DoFadeInBackground()end return Enum.ContextActionResult.Pass end local function q(U)if U==a.moveTouchObject then if a.moveTouchFirstChanged then a.moveTouchFirstChanged=false local q=Vector2.new(U.Position.X-a.thumbstickFrame.AbsolutePosition.X,U.Position.Y-a.thumbstickFrame.AbsolutePosition.Y)a.startImage.Visible=true a.startImage.Position=UDim2.new(0,q.X,0,q.Y)a.endImage.Visible=true a.endImage.Position=a.startImage.Position a:FadeThumbstick(true)a:MoveStick(U.Position)end a.moveTouchLockedIn=true local q=Vector2.new(U.Position.x-a.moveTouchStartPosition.x,U.Position.y-a.moveTouchStartPosition.y)if math.abs(q.x)>0 or math.abs(q.y)>0 then a:DoMove(q)a:MoveStick(U.Position)end return Enum.ContextActionResult.Sink end return Enum.ContextActionResult.Pass end local function y(U)if U==a.moveTouchObject then a:OnInputEnded()if a.moveTouchLockedIn then return Enum.ContextActionResult.Sink end end return Enum.ContextActionResult.Pass end local function i(i,T,v)if T==Enum.UserInputState.Begin then return U(v)elseif T==Enum.UserInputState.Change then return q(v)elseif T==Enum.UserInputState.End then return y(v)elseif T==Enum.UserInputState.Cancel then a:OnInputEnded()end end ContextActionService:BindActionAtPriority(DYNAMIC_THUMBSTICK_ACTION_NAME,i,false,DYNAMIC_THUMBSTICK_ACTION_PRIORITY,Enum.UserInputType.Touch)end function DynamicThumbstick.Create(U,a)if U.thumbstickFrame then U.thumbstickFrame:Destroy()U.thumbstickFrame=nil if U.onRenderSteppedConn then U.onRenderSteppedConn:Disconnect()U.onRenderSteppedConn=nil end end U.thumbstickSize=45 U.thumbstickRingSize=20 U.middleSize=10 U.middleSpacing=U.middleSize+4 U.radiusOfDeadZone=2 U.radiusOfMaxSpeed=20 local q=a.AbsoluteSize local y=math.min(q.x,q.y)>500 if y then U.thumbstickSize=U.thumbstickSize*2 U.thumbstickRingSize=U.thumbstickRingSize*2 U.middleSize=U.middleSize*2 U.middleSpacing=U.middleSpacing*2 U.radiusOfDeadZone=U.radiusOfDeadZone*2 U.radiusOfMaxSpeed=U.radiusOfMaxSpeed*2 end local function i(a)if a then U.thumbstickFrame.Size=UDim2.new(1,0,.4,0)U.thumbstickFrame.Position=UDim2.new(0,0,.6,0)else U.thumbstickFrame.Size=UDim2.new(.4,0,.66666666666667,0)U.thumbstickFrame.Position=UDim2.new(0,0,.33333333333333,0)end end U.thumbstickFrame=Instance.new("\070\114\097\109\101")U.thumbstickFrame.BorderSizePixel=0 U.thumbstickFrame.Name="\068\121\110\097\109\105\099\084\104\117\109\098\115\116\105\099\107\070\114\097\109\101"U.thumbstickFrame.Visible=false U.thumbstickFrame.BackgroundTransparency=1.0 U.thumbstickFrame.BackgroundColor3=Color3.fromRGB(0,0,0)U.thumbstickFrame.Active=false i(false)U.startImage=Instance.new("\073\109\097\103\101\076\097\098\101\108")U.startImage.Name="\084\104\117\109\098\115\116\105\099\107\083\116\097\114\116"U.startImage.Visible=true U.startImage.BackgroundTransparency=1 U.startImage.Image=TOUCH_CONTROLS_SHEET U.startImage.ImageRectOffset=Vector2.new(1,1)U.startImage.ImageRectSize=Vector2.new(144,144)U.startImage.ImageColor3=Color3.new(0,0,0)U.startImage.AnchorPoint=Vector2.new(.5,.5)U.startImage.Position=UDim2.new(0,U.thumbstickRingSize*3.3,1,-U.thumbstickRingSize*2.8)U.startImage.Size=UDim2.new(0,U.thumbstickRingSize*3.7,0,U.thumbstickRingSize*3.7)U.startImage.ZIndex=10 U.startImage.Parent=U.thumbstickFrame U.endImage=Instance.new("\073\109\097\103\101\076\097\098\101\108")U.endImage.Name="\084\104\117\109\098\115\116\105\099\107\069\110\100"U.endImage.Visible=true U.endImage.BackgroundTransparency=1 U.endImage.Image=TOUCH_CONTROLS_SHEET U.endImage.ImageRectOffset=Vector2.new(1,1)U.endImage.ImageRectSize=Vector2.new(144,144)U.endImage.AnchorPoint=Vector2.new(.5,.5)U.endImage.Position=U.startImage.Position U.endImage.Size=UDim2.new(0,U.thumbstickSize*.8,0,U.thumbstickSize*.8)U.endImage.ZIndex=10 U.endImage.Parent=U.thumbstickFrame for a=1,NUM_MIDDLE_IMAGES,1 do U.middleImages[a]=Instance.new("\073\109\097\103\101\076\097\098\101\108")U.middleImages[a].Name="\084\104\117\109\098\115\116\105\099\107\077\105\100\100\108\101"U.middleImages[a].Visible=false U.middleImages[a].BackgroundTransparency=1 U.middleImages[a].Image=TOUCH_CONTROLS_SHEET U.middleImages[a].ImageRectOffset=Vector2.new(1,1)U.middleImages[a].ImageRectSize=Vector2.new(144,144)U.middleImages[a].ImageTransparency=MIDDLE_TRANSPARENCIES[a]U.middleImages[a].AnchorPoint=Vector2.new(.5,.5)U.middleImages[a].ZIndex=9 U.middleImages[a].Parent=U.thumbstickFrame end local T=nil local function v()if T then T:Disconnect()T=nil end local a=workspace.CurrentCamera if a then local function U()local U=a.ViewportSize local q=U.X<U.Y i(q)end T=(a:GetPropertyChangedSignal("\086\105\101\119\112\111\114\116\083\105\122\101")):Connect(U)U()end end;(workspace:GetPropertyChangedSignal("\067\117\114\114\101\110\116\067\097\109\101\114\097")):Connect(v)if workspace.CurrentCamera then v()end U.moveTouchStartPosition=nil U.startImageFadeTween=nil U.endImageFadeTween=nil U.middleImageFadeTweens={}U.onRenderSteppedConn=RunService.RenderStepped:Connect(function()if U.tweenInAlphaStart~=nil then local a=tick()-U.tweenInAlphaStart local q=(U.fadeInAndOutHalfDuration*2)*U.fadeInAndOutBalance U.thumbstickFrame.BackgroundTransparency=1-FADE_IN_OUT_MAX_ALPHA*math.min(a/q,1)if a>q then U.tweenOutAlphaStart=tick()U.tweenInAlphaStart=nil end elseif U.tweenOutAlphaStart~=nil then local a=tick()-U.tweenOutAlphaStart local q=U.fadeInAndOutHalfDuration*2-(U.fadeInAndOutHalfDuration*2)*U.fadeInAndOutBalance U.thumbstickFrame.BackgroundTransparency=(1-FADE_IN_OUT_MAX_ALPHA)+FADE_IN_OUT_MAX_ALPHA*math.min(a/q,1)if a>q then U.tweenOutAlphaStart=nil end end end)U.onTouchEndedConn=UserInputService.TouchEnded:connect(function(a)if a==U.moveTouchObject then U:OnInputEnded()end end)GuiService.MenuOpened:connect(function()if U.moveTouchObject then U:OnInputEnded()end end)local C=LocalPlayer:FindFirstChildOfClass("\080\108\097\121\101\114\071\117\105")while not C do LocalPlayer.ChildAdded:wait()C=LocalPlayer:FindFirstChildOfClass("\080\108\097\121\101\114\071\117\105")end local s=nil local K=C.CurrentScreenOrientation==Enum.ScreenOrientation.LandscapeLeft or C.CurrentScreenOrientation==Enum.ScreenOrientation.LandscapeRight local function l()U.fadeInAndOutHalfDuration=2.5 U.fadeInAndOutBalance=.05 U.tweenInAlphaStart=tick()end s=(C:GetPropertyChangedSignal("\067\117\114\114\101\110\116\083\099\114\101\101\110\079\114\105\101\110\116\097\116\105\111\110")):Connect(function()if K and C.CurrentScreenOrientation==Enum.ScreenOrientation.Portrait or not K and C.CurrentScreenOrientation~=Enum.ScreenOrientation.Portrait then s:disconnect()l()if K then U.hasFadedBackgroundInPortrait=true else U.hasFadedBackgroundInLandscape=true end end end)U.thumbstickFrame.Parent=a if game:IsLoaded()then l()else(coroutine.wrap(function()game.Loaded:Wait()l()end))()end end return DynamicThumbstick

function DynamicThumbstick:OnInputEnded()
	self.moveTouchObject = nil
	self.moveVector = ZERO_VECTOR3
	self:FadeThumbstick(false)
end

function DynamicThumbstick:FadeThumbstick(visible)
	if not visible and self.moveTouchObject then
		return
	end
	if self.isFirstTouch then return end

	if self.startImageFadeTween then
		self.startImageFadeTween:Cancel()
	end
	if self.endImageFadeTween then
		self.endImageFadeTween:Cancel()
	end
	for i = 1, #self.middleImages do
		if self.middleImageFadeTweens[i] then
			self.middleImageFadeTweens[i]:Cancel()
		end
	end

	if visible then
		self.startImageFadeTween = TweenService:Create(self.startImage, ThumbstickFadeTweenInfo, { ImageTransparency = 0 })
		self.startImageFadeTween:Play()

		self.endImageFadeTween = TweenService:Create(self.endImage, ThumbstickFadeTweenInfo, { ImageTransparency = 0.2 })
		self.endImageFadeTween:Play()

		for i = 1, #self.middleImages do
			self.middleImageFadeTweens[i] = TweenService:Create(self.middleImages[i], ThumbstickFadeTweenInfo, { ImageTransparency = MIDDLE_TRANSPARENCIES[i] })
			self.middleImageFadeTweens[i]:Play()
		end
	else
		self.startImageFadeTween = TweenService:Create(self.startImage, ThumbstickFadeTweenInfo, { ImageTransparency = 1 })
		self.startImageFadeTween:Play()

		self.endImageFadeTween = TweenService:Create(self.endImage, ThumbstickFadeTweenInfo, { ImageTransparency = 1 })
		self.endImageFadeTween:Play()

		for i = 1, #self.middleImages do
			self.middleImageFadeTweens[i] = TweenService:Create(self.middleImages[i], ThumbstickFadeTweenInfo, { ImageTransparency = 1 })
			self.middleImageFadeTweens[i]:Play()
		end
	end
end

function DynamicThumbstick:FadeThumbstickFrame(fadeDuration, fadeRatio)
	self.fadeInAndOutHalfDuration = fadeDuration * 0.5
	self.fadeInAndOutBalance = fadeRatio
	self.tweenInAlphaStart = tick()
end

function DynamicThumbstick:InputInFrame(inputObject)
	local frameCornerTopLeft = self.thumbstickFrame.AbsolutePosition
	local frameCornerBottomRight = frameCornerTopLeft + self.thumbstickFrame.AbsoluteSize
	local inputPosition = inputObject.Position
	if inputPosition.X >= frameCornerTopLeft.X and inputPosition.Y >= frameCornerTopLeft.Y then
		if inputPosition.X <= frameCornerBottomRight.X and inputPosition.Y <= frameCornerBottomRight.Y then
			return true
		end
	end
	return false
end

function DynamicThumbstick:DoFadeInBackground()
	local playerGui = LocalPlayer:FindFirstChildOfClass("PlayerGui")
	local hasFadedBackgroundInOrientation = false

	-- only fade in/out the background once per orientation
	if playerGui then
		if playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.LandscapeLeft or
			playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.LandscapeRight then
				hasFadedBackgroundInOrientation = self.hasFadedBackgroundInLandscape
				self.hasFadedBackgroundInLandscape = true
		elseif playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.Portrait then
				hasFadedBackgroundInOrientation = self.hasFadedBackgroundInPortrait
				self.hasFadedBackgroundInPortrait = true
		end
	end

	if not hasFadedBackgroundInOrientation then
		self.fadeInAndOutHalfDuration = FADE_IN_OUT_HALF_DURATION_DEFAULT
		self.fadeInAndOutBalance = FADE_IN_OUT_BALANCE_DEFAULT
		self.tweenInAlphaStart = tick()
	end
end

function DynamicThumbstick:DoMove(direction)
	local currentMoveVector = direction

	-- Scaled Radial Dead Zone
	local inputAxisMagnitude = currentMoveVector.magnitude
	if inputAxisMagnitude < self.radiusOfDeadZone then
		currentMoveVector = ZERO_VECTOR3
	else
		currentMoveVector = currentMoveVector.unit*(
			1 - math.max(0, (self.radiusOfMaxSpeed - currentMoveVector.magnitude)/self.radiusOfMaxSpeed)
		)
		currentMoveVector = Vector3.new(currentMoveVector.x, 0, currentMoveVector.y)
	end

	self.moveVector = currentMoveVector
end


function DynamicThumbstick:LayoutMiddleImages(startPos, endPos)
	local startDist = (self.thumbstickSize / 2) + self.middleSize
	local vector = endPos - startPos
	local distAvailable = vector.magnitude - (self.thumbstickRingSize / 2) - self.middleSize
	local direction = vector.unit

	local distNeeded = self.middleSpacing * NUM_MIDDLE_IMAGES
	local spacing = self.middleSpacing

	if distNeeded < distAvailable then
		spacing = distAvailable / NUM_MIDDLE_IMAGES
	end

	for i = 1, NUM_MIDDLE_IMAGES do
		local image = self.middleImages[i]
		local distWithout = startDist + (spacing * (i - 2))
		local currentDist = startDist + (spacing * (i - 1))

		if distWithout < distAvailable then
			local pos = endPos - direction * currentDist
			local exposedFraction = math.clamp(1 - ((currentDist - distAvailable) / spacing), 0, 1)

			image.Visible = true
			image.Position = UDim2.new(0, pos.X, 0, pos.Y)
			image.Size = UDim2.new(0, self.middleSize * exposedFraction, 0, self.middleSize * exposedFraction)
		else
			image.Visible = false
		end
	end
end

function DynamicThumbstick:MoveStick(pos)
	local vector2StartPosition = Vector2.new(self.moveTouchStartPosition.X, self.moveTouchStartPosition.Y)
	local startPos = vector2StartPosition - self.thumbstickFrame.AbsolutePosition
	local endPos = Vector2.new(pos.X, pos.Y) - self.thumbstickFrame.AbsolutePosition
	self.endImage.Position = UDim2.new(0, endPos.X, 0, endPos.Y)
	self:LayoutMiddleImages(startPos, endPos)
end

function DynamicThumbstick:BindContextActions()
	local function inputBegan(inputObject)
		if self.moveTouchObject then
			return Enum.ContextActionResult.Pass
		end

		if not self:InputInFrame(inputObject) then
			return Enum.ContextActionResult.Pass
		end

		if self.isFirstTouch then
			self.isFirstTouch = false
			local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out,0,false,0)
			TweenService:Create(self.startImage, tweenInfo, {Size = UDim2.new(0, 0, 0, 0)}):Play()
			TweenService:Create(
				self.endImage,
				tweenInfo,
				{Size = UDim2.new(0, self.thumbstickSize, 0, self.thumbstickSize), ImageColor3 = Color3.new(0,0,0)}
			):Play()
		end

		self.moveTouchLockedIn = false
		self.moveTouchObject = inputObject
		self.moveTouchStartPosition = inputObject.Position
		self.moveTouchFirstChanged = true

		if FADE_IN_OUT_BACKGROUND then
			self:DoFadeInBackground()
		end

		return Enum.ContextActionResult.Pass
	end

	local function inputChanged(inputObject)
		if inputObject == self.moveTouchObject then
			if self.moveTouchFirstChanged then
				self.moveTouchFirstChanged = false

				local startPosVec2 = Vector2.new(
					inputObject.Position.X - self.thumbstickFrame.AbsolutePosition.X,
					inputObject.Position.Y - self.thumbstickFrame.AbsolutePosition.Y
				)
				self.startImage.Visible = true
				self.startImage.Position = UDim2.new(0, startPosVec2.X, 0, startPosVec2.Y)
				self.endImage.Visible = true
				self.endImage.Position = self.startImage.Position

				self:FadeThumbstick(true)
				self:MoveStick(inputObject.Position)
			end

			self.moveTouchLockedIn = true

			local direction = Vector2.new(
				inputObject.Position.x - self.moveTouchStartPosition.x,
				inputObject.Position.y - self.moveTouchStartPosition.y
			)
			if math.abs(direction.x) > 0 or math.abs(direction.y) > 0 then
				self:DoMove(direction)
				self:MoveStick(inputObject.Position)
			end
			return Enum.ContextActionResult.Sink
		end
		return Enum.ContextActionResult.Pass
	end

	local function inputEnded(inputObject)
		if inputObject == self.moveTouchObject then
			self:OnInputEnded()
			if self.moveTouchLockedIn then
				return Enum.ContextActionResult.Sink
			end
		end
		return Enum.ContextActionResult.Pass
	end

	local function handleInput(actionName, inputState, inputObject)
		if inputState == Enum.UserInputState.Begin then
			return inputBegan(inputObject)
		elseif inputState == Enum.UserInputState.Change then
			return inputChanged(inputObject)
		elseif inputState == Enum.UserInputState.End then
			return inputEnded(inputObject)
		elseif inputState == Enum.UserInputState.Cancel then
			self:OnInputEnded()
		end
	end

	ContextActionService:BindActionAtPriority(
		DYNAMIC_THUMBSTICK_ACTION_NAME,
		handleInput,
		false,
		DYNAMIC_THUMBSTICK_ACTION_PRIORITY,
		Enum.UserInputType.Touch)
end

function DynamicThumbstick:Create(parentFrame)
	if self.thumbstickFrame then
		self.thumbstickFrame:Destroy()
		self.thumbstickFrame = nil
		if self.onRenderSteppedConn then
			self.onRenderSteppedConn:Disconnect()
			self.onRenderSteppedConn = nil
		end
	end

	self.thumbstickSize = 45
	self.thumbstickRingSize = 20
	self.middleSize = 10
	self.middleSpacing = self.middleSize + 4
	self.radiusOfDeadZone = 2
	self.radiusOfMaxSpeed = 20

	local screenSize = parentFrame.AbsoluteSize
	local isBigScreen = math.min(screenSize.x, screenSize.y) > 500
	if isBigScreen then
		self.thumbstickSize = self.thumbstickSize * 2
		self.thumbstickRingSize = self.thumbstickRingSize * 2
		self.middleSize = self.middleSize * 2
		self.middleSpacing = self.middleSpacing * 2
		self.radiusOfDeadZone = self.radiusOfDeadZone * 2
		self.radiusOfMaxSpeed = self.radiusOfMaxSpeed * 2
	end

	local function layoutThumbstickFrame(portraitMode)
		if portraitMode then
			self.thumbstickFrame.Size = UDim2.new(1, 0, 0.4, 0)
			self.thumbstickFrame.Position = UDim2.new(0, 0, 0.6, 0)
		else
			self.thumbstickFrame.Size = UDim2.new(0.4, 0, 2/3, 0)
			self.thumbstickFrame.Position = UDim2.new(0, 0, 1/3, 0)
		end
	end

	self.thumbstickFrame = Instance.new("Frame")
	self.thumbstickFrame.BorderSizePixel = 0
	self.thumbstickFrame.Name = "DynamicThumbstickFrame"
	self.thumbstickFrame.Visible = false
	self.thumbstickFrame.BackgroundTransparency = 1.0
	self.thumbstickFrame.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
	self.thumbstickFrame.Active = false
	layoutThumbstickFrame(false)

	self.startImage = Instance.new("ImageLabel")
	self.startImage.Name = "ThumbstickStart"
	self.startImage.Visible = true
	self.startImage.BackgroundTransparency = 1
	self.startImage.Image = TOUCH_CONTROLS_SHEET
	self.startImage.ImageRectOffset = Vector2.new(1,1)
	self.startImage.ImageRectSize = Vector2.new(144, 144)
	self.startImage.ImageColor3 = Color3.new(0, 0, 0)
	self.startImage.AnchorPoint = Vector2.new(0.5, 0.5)
	self.startImage.Position = UDim2.new(0, self.thumbstickRingSize * 3.3, 1, -self.thumbstickRingSize  * 2.8)
	self.startImage.Size = UDim2.new(0, self.thumbstickRingSize  * 3.7, 0, self.thumbstickRingSize  * 3.7)
	self.startImage.ZIndex = 10
	self.startImage.Parent = self.thumbstickFrame

	self.endImage = Instance.new("ImageLabel")
	self.endImage.Name = "ThumbstickEnd"
	self.endImage.Visible = true
	self.endImage.BackgroundTransparency = 1
	self.endImage.Image = TOUCH_CONTROLS_SHEET
	self.endImage.ImageRectOffset = Vector2.new(1,1)
	self.endImage.ImageRectSize =  Vector2.new(144, 144)
	self.endImage.AnchorPoint = Vector2.new(0.5, 0.5)
	self.endImage.Position = self.startImage.Position
	self.endImage.Size = UDim2.new(0, self.thumbstickSize * 0.8, 0, self.thumbstickSize * 0.8)
	self.endImage.ZIndex = 10
	self.endImage.Parent = self.thumbstickFrame

	for i = 1, NUM_MIDDLE_IMAGES do
		self.middleImages[i] = Instance.new("ImageLabel")
		self.middleImages[i].Name = "ThumbstickMiddle"
		self.middleImages[i].Visible = false
		self.middleImages[i].BackgroundTransparency = 1
		self.middleImages[i].Image = TOUCH_CONTROLS_SHEET
		self.middleImages[i].ImageRectOffset = Vector2.new(1,1)
		self.middleImages[i].ImageRectSize = Vector2.new(144, 144)
		self.middleImages[i].ImageTransparency = MIDDLE_TRANSPARENCIES[i]
		self.middleImages[i].AnchorPoint = Vector2.new(0.5, 0.5)
		self.middleImages[i].ZIndex = 9
		self.middleImages[i].Parent = self.thumbstickFrame
	end

	local CameraChangedConn = nil
	local function onCurrentCameraChanged()
		if CameraChangedConn then
			CameraChangedConn:Disconnect()
			CameraChangedConn = nil
		end
		local newCamera = workspace.CurrentCamera
		if newCamera then
			local function onViewportSizeChanged()
				local size = newCamera.ViewportSize
				local portraitMode = size.X < size.Y
				layoutThumbstickFrame(portraitMode)
			end
			CameraChangedConn = newCamera:GetPropertyChangedSignal("ViewportSize"):Connect(onViewportSizeChanged)
			onViewportSizeChanged()
		end
	end
	workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(onCurrentCameraChanged)
	if workspace.CurrentCamera then
		onCurrentCameraChanged()
	end

	self.moveTouchStartPosition = nil

	self.startImageFadeTween = nil
	self.endImageFadeTween = nil
	self.middleImageFadeTweens = {}

	self.onRenderSteppedConn = RunService.RenderStepped:Connect(function()
		if self.tweenInAlphaStart ~= nil then
			local delta = tick() - self.tweenInAlphaStart
			local fadeInTime = (self.fadeInAndOutHalfDuration * 2 * self.fadeInAndOutBalance)
			self.thumbstickFrame.BackgroundTransparency = 1 - FADE_IN_OUT_MAX_ALPHA*math.min(delta/fadeInTime, 1)
			if delta > fadeInTime then
				self.tweenOutAlphaStart = tick()
				self.tweenInAlphaStart = nil
			end
		elseif self.tweenOutAlphaStart ~= nil then
			local delta = tick() - self.tweenOutAlphaStart
			local fadeOutTime = (self.fadeInAndOutHalfDuration * 2) - (self.fadeInAndOutHalfDuration * 2 * self.fadeInAndOutBalance)
			self.thumbstickFrame.BackgroundTransparency = 1 - FADE_IN_OUT_MAX_ALPHA + FADE_IN_OUT_MAX_ALPHA*math.min(delta/fadeOutTime, 1)
			if delta > fadeOutTime  then
				self.tweenOutAlphaStart = nil
			end
		end
	end)

	self.onTouchEndedConn = UserInputService.TouchEnded:connect(function(inputObject)
		if inputObject == self.moveTouchObject then
			self:OnInputEnded()
		end
	end)

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

	local playerGui = LocalPlayer:FindFirstChildOfClass("PlayerGui")
	while not playerGui do
		LocalPlayer.ChildAdded:wait()
		playerGui = LocalPlayer:FindFirstChildOfClass("PlayerGui")
	end

	local playerGuiChangedConn = nil
	local originalScreenOrientationWasLandscape =	playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.LandscapeLeft or
													playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.LandscapeRight

	local function longShowBackground()
		self.fadeInAndOutHalfDuration = 2.5
		self.fadeInAndOutBalance = 0.05
		self.tweenInAlphaStart = tick()
	end

	playerGuiChangedConn = playerGui:GetPropertyChangedSignal("CurrentScreenOrientation"):Connect(function()
		if (originalScreenOrientationWasLandscape and playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.Portrait) or
			(not originalScreenOrientationWasLandscape and playerGui.CurrentScreenOrientation ~= Enum.ScreenOrientation.Portrait) then

			playerGuiChangedConn:disconnect()
			longShowBackground()

			if originalScreenOrientationWasLandscape then
				self.hasFadedBackgroundInPortrait = true
			else
				self.hasFadedBackgroundInLandscape = true
			end
		end
	end)

	self.thumbstickFrame.Parent = parentFrame

	if game:IsLoaded() then
		longShowBackground()
	else
		coroutine.wrap(function()
			game.Loaded:Wait()
			longShowBackground()
		end)()
	end
end

return DynamicThumbstick
