229 lines
8.4 KiB
Lua
229 lines
8.4 KiB
Lua
--[[
|
|
// FileName: Thumbpad
|
|
// Version 1.0
|
|
// Written by: jmargh
|
|
// Description: Implements thumbpad controls for touch devices
|
|
--]]
|
|
|
|
local Players = game:GetService('Players')
|
|
local UserInputService = game:GetService('UserInputService')
|
|
local GuiService = game:GetService('GuiService')
|
|
|
|
local Thumbpad = {}
|
|
|
|
local MasterControl = require(script.Parent)
|
|
|
|
--[[ Script Variables ]]--
|
|
while not Players.LocalPlayer do
|
|
wait()
|
|
end
|
|
local LocalPlayer = Players.LocalPlayer
|
|
local ThumbpadFrame = nil
|
|
local TouchObject = nil
|
|
local OnInputEnded = nil -- is defined in Create()
|
|
local OnTouchChangedCn = nil
|
|
local OnTouchEndedCn = nil
|
|
local currentMoveVector = Vector3.new(0,0,0)
|
|
|
|
--[[ Constants ]]--
|
|
local DPAD_SHEET = "rbxasset://textures/ui/DPadSheet.png"
|
|
local TOUCH_CONTROL_SHEET = "rbxasset://textures/ui/TouchControlsSheet.png"
|
|
|
|
--[[ Local Functions ]]--
|
|
local function createArrowLabel(name, parent, position, size, rectOffset, rectSize)
|
|
local image = Instance.new('ImageLabel')
|
|
image.Name = name
|
|
image.Image = DPAD_SHEET
|
|
image.ImageRectOffset = rectOffset
|
|
image.ImageRectSize = rectSize
|
|
image.BackgroundTransparency = 1
|
|
image.ImageColor3 = Color3.new(190/255, 190/255, 190/255)
|
|
image.Size = size
|
|
image.Position = position
|
|
image.Parent = parent
|
|
|
|
return image
|
|
end
|
|
|
|
--[[ 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
|