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

	self.thumbstickFrame.Parent = parentFrame

	spawn(function()
		if game:IsLoaded() then
			longShowBackground()
		else
			game.Loaded:wait()
			longShowBackground()
		end
	end)
end

return DynamicThumbstick
