--[[ --]] local Players = game:GetService("Players") local GuiService = game:GetService("GuiService") --[[ Constants ]]-- local DPAD_SHEET = "rbxasset://textures/ui/DPadSheet.png" local ZERO_VECTOR3 = Vector3.new(0,0,0) local COMPASS_DIR = { Vector3.new(1, 0, 0), -- E Vector3.new(1, 0, 1).unit, -- SE Vector3.new(0, 0, 1), -- S Vector3.new(-1, 0, 1).unit, -- SW Vector3.new(-1, 0, 0), -- W Vector3.new(-1, 0, -1).unit, -- NW Vector3.new(0, 0, -1), -- N Vector3.new(1, 0, -1).unit, -- NE } --[[ The Module ]]-- local BaseCharacterController = require(script.Parent:WaitForChild("BaseCharacterController")) local TouchDPad = setmetatable({}, BaseCharacterController) TouchDPad.__index = TouchDPad function TouchDPad.new() local self = setmetatable(BaseCharacterController.new(), TouchDPad) self.DPadFrame = nil self.touchObject = nil self.flBtn = nil self.frBtn = nil return self end --[[ Local Functions ]]-- local function CreateArrowLabel(name, position, size, rectOffset, rectSize, parent) local image = Instance.new("ImageLabel") image.Name = name image.Image = DPAD_SHEET image.ImageRectOffset = rectOffset image.ImageRectSize = rectSize image.BackgroundTransparency = 1 image.Size = size image.Position = position image.Parent = parent return image end function TouchDPad:GetCenterPosition() return Vector2.new(self.DPadFrame.AbsolutePosition.x + self.DPadFrame.AbsoluteSize.x * 0.5, self.DPadFrame.AbsolutePosition.y + self.DPadFrame.AbsoluteSize.y * 0.5) end --[[ Public API ]]-- function TouchDPad:Enable(enable, uiParentFrame) if enable == nil then return false end -- If nil, return false (invalid argument) enable = enable and true or false -- Force anything non-nil to boolean before comparison if self.enabled == enable then return true end -- If no state change, return true indicating already in requested state if enable then -- Enable if not self.DPadFrame then self:Create(uiParentFrame) end self.DPadFrame.Visible = true else -- Disable self.DPadFrame.Visible = false self:OnInputEnded() end self.enabled = enable end -- Note: Overrides base class GetIsJumping with get-and-clear behavior to do a single jump -- rather than sustained jumping. This is only to preserve the current behavior through the refactor. function TouchDPad:GetIsJumping() local wasJumping = self.isJumping self.isJumping = false return wasJumping end function TouchDPad:OnInputEnded() self.touchObject =nil if self.flBtn then self.flBtn.Visible = false end if self.frBtn then self.frBtn.Visible = false end self.moveVector = ZERO_VECTOR3 end function TouchDPad:Create(parentFrame) if self.DPadFrame then self.DPadFrame:Destroy() self.DPadFrame = nil end local position = UDim2.new(0, 10, 1, -230) self.DPadFrame = Instance.new("Frame") self.DPadFrame.Name = "DPadFrame" self.DPadFrame.Active = true self.DPadFrame.Visible = false self.DPadFrame.Size = UDim2.new(0, 192, 0, 192) self.DPadFrame.Position = position self.DPadFrame.BackgroundTransparency = 1 local smArrowSize = UDim2.new(0, 23, 0, 23) local lgArrowSize = UDim2.new(0, 64, 0, 64) local smImgOffset = Vector2.new(46, 46) local lgImgOffset = Vector2.new(128, 128) local bBtn = CreateArrowLabel("BackButton", UDim2.new(0.5, -32, 1, -64), lgArrowSize, Vector2.new(0, 0), lgImgOffset, self.DPadFrame) local fBtn = CreateArrowLabel("ForwardButton", UDim2.new(0.5, -32, 0, 0), lgArrowSize, Vector2.new(0, 258), lgImgOffset, self.DPadFrame) local lBtn = CreateArrowLabel("LeftButton", UDim2.new(0, 0, 0.5, -32), lgArrowSize, Vector2.new(129, 129), lgImgOffset, self.DPadFrame) local rBtn = CreateArrowLabel("RightButton", UDim2.new(1, -64, 0.5, -32), lgArrowSize, Vector2.new(0, 129), lgImgOffset, self.DPadFrame) local jumpBtn = CreateArrowLabel("JumpButton", UDim2.new(0.5, -32, 0.5, -32), lgArrowSize, Vector2.new(129, 0), lgImgOffset, self.DPadFrame) self.flBtn = CreateArrowLabel("ForwardLeftButton", UDim2.new(0, 35, 0, 35), smArrowSize, Vector2.new(129, 258), smImgOffset, self.DPadFrame) self.frBtn = CreateArrowLabel("ForwardRightButton", UDim2.new(1, -55, 0, 35), smArrowSize, Vector2.new(176, 258), smImgOffset, self.DPadFrame) self.flBtn.Visible = false self.frBtn.Visible = false -- input connections jumpBtn.InputBegan:Connect(function(inputObject) self.isJumping = true end) local function normalizeDirection(inputPosition) local jumpRadius = jumpBtn.AbsoluteSize.x*0.5 local centerPosition = self:GetCenterPosition() local direction = Vector2.new(inputPosition.x - centerPosition.x, inputPosition.y - centerPosition.y) if direction.magnitude > jumpRadius then local angle = math.atan2(direction.y, direction.x) local octant = (math.floor(8 * angle / (2 * math.pi) + 8.5)%8) + 1 self.moveVector = COMPASS_DIR[octant] end if not self.flBtn.Visible and self.moveVector == COMPASS_DIR[7] then self.flBtn.Visible = true self.frBtn.Visible = true end end self.DPadFrame.InputBegan:Connect(function(inputObject) if self.touchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch then return end self.touchObject = inputObject normalizeDirection(self.touchObject.Position) end) self.DPadFrame.InputChanged:Connect(function(inputObject) if inputObject == self.touchObject then normalizeDirection(self.touchObject.Position) self.isJumping = false end end) self.DPadFrame.InputEnded:connect(function(inputObject) if inputObject == self.touchObject then self:OnInputEnded() end end) GuiService.MenuOpened:Connect(function() if self.touchObject then self:OnInputEnded() end end) self.DPadFrame.Parent = parentFrame end return TouchDPad