add gs
This commit is contained in:
+1172
File diff suppressed because it is too large
Load Diff
+170
@@ -0,0 +1,170 @@
|
||||
--[[
|
||||
// FileName: DPad
|
||||
// Version 1.0
|
||||
// Written by: jmargh
|
||||
// Description: Implements DPad controls for touch devices
|
||||
--]]
|
||||
|
||||
local Players = game:GetService('Players')
|
||||
local GuiService = game:GetService('GuiService')
|
||||
|
||||
local DPad = {}
|
||||
|
||||
local MasterControl = require(script.Parent)
|
||||
|
||||
--[[ Script Variables ]]--
|
||||
while not Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
local DPadFrame = nil
|
||||
local TouchObject = nil
|
||||
local OnInputEnded = nil -- defined in Create()
|
||||
|
||||
--[[ Constants ]]--
|
||||
local DPAD_SHEET = "rbxasset://textures/ui/DPadSheet.png"
|
||||
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
|
||||
}
|
||||
|
||||
--[[ lua Function Cache ]]--
|
||||
local ATAN2 = math.atan2
|
||||
local FLOOR = math.floor
|
||||
local PI = math.pi
|
||||
|
||||
--[[ Local Functions ]]--
|
||||
local function createArrowLabel(name, 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.Size = size
|
||||
image.Position = position
|
||||
image.Parent = DPadFrame
|
||||
|
||||
return image
|
||||
end
|
||||
|
||||
local function getCenterPosition()
|
||||
return Vector2.new(DPadFrame.AbsolutePosition.x + DPadFrame.AbsoluteSize.x/2, DPadFrame.AbsolutePosition.y + DPadFrame.AbsoluteSize.y/2)
|
||||
end
|
||||
|
||||
--[[ Public API ]]--
|
||||
function DPad:Enable()
|
||||
DPadFrame.Visible = true
|
||||
end
|
||||
|
||||
function DPad:Disable()
|
||||
DPadFrame.Visible = false
|
||||
OnInputEnded()
|
||||
end
|
||||
|
||||
function DPad:Create(parentFrame)
|
||||
if DPadFrame then
|
||||
DPadFrame:Destroy()
|
||||
DPadFrame = nil
|
||||
end
|
||||
|
||||
local position = UDim2.new(0, 10, 1, -230)
|
||||
DPadFrame = Instance.new('Frame')
|
||||
DPadFrame.Name = "DPadFrame"
|
||||
DPadFrame.Active = true
|
||||
DPadFrame.Visible = false
|
||||
DPadFrame.Size = UDim2.new(0, 192, 0, 192)
|
||||
DPadFrame.Position = position
|
||||
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)
|
||||
local fBtn = createArrowLabel("ForwardButton", UDim2.new(0.5, -32, 0, 0), lgArrowSize, Vector2.new(0, 258), lgImgOffset)
|
||||
local lBtn = createArrowLabel("LeftButton", UDim2.new(0, 0, 0.5, -32), lgArrowSize, Vector2.new(129, 129), lgImgOffset)
|
||||
local rBtn = createArrowLabel("RightButton", UDim2.new(1, -64, 0.5, -32), lgArrowSize, Vector2.new(0, 129), lgImgOffset)
|
||||
local jumpBtn = createArrowLabel("JumpButton", UDim2.new(0.5, -32, 0.5, -32), lgArrowSize, Vector2.new(129, 0), lgImgOffset)
|
||||
local flBtn = createArrowLabel("ForwardLeftButton", UDim2.new(0, 35, 0, 35), smArrowSize, Vector2.new(129, 258), smImgOffset)
|
||||
local frBtn = createArrowLabel("ForwardRightButton", UDim2.new(1, -55, 0, 35), smArrowSize, Vector2.new(176, 258), smImgOffset)
|
||||
flBtn.Visible = false
|
||||
frBtn.Visible = false
|
||||
|
||||
-- input connections
|
||||
jumpBtn.InputBegan:connect(function(inputObject)
|
||||
MasterControl:DoJump()
|
||||
end)
|
||||
|
||||
local movementVector = Vector3.new(0,0,0)
|
||||
local function normalizeDirection(inputPosition)
|
||||
local jumpRadius = jumpBtn.AbsoluteSize.x/2
|
||||
local centerPosition = getCenterPosition()
|
||||
local direction = Vector2.new(inputPosition.x - centerPosition.x, inputPosition.y - centerPosition.y)
|
||||
|
||||
if direction.magnitude > jumpRadius then
|
||||
local angle = ATAN2(direction.y, direction.x)
|
||||
local octant = (FLOOR(8 * angle / (2 * PI) + 8.5)%8) + 1
|
||||
movementVector = COMPASS_DIR[octant]
|
||||
end
|
||||
|
||||
if not flBtn.Visible and movementVector == COMPASS_DIR[7] then
|
||||
flBtn.Visible = true
|
||||
frBtn.Visible = true
|
||||
end
|
||||
end
|
||||
|
||||
DPadFrame.InputBegan:connect(function(inputObject)
|
||||
if TouchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch then
|
||||
return
|
||||
end
|
||||
|
||||
MasterControl:AddToPlayerMovement(-movementVector)
|
||||
|
||||
TouchObject = inputObject
|
||||
normalizeDirection(TouchObject.Position)
|
||||
|
||||
MasterControl:AddToPlayerMovement(movementVector)
|
||||
end)
|
||||
|
||||
DPadFrame.InputChanged:connect(function(inputObject)
|
||||
if inputObject == TouchObject then
|
||||
MasterControl:AddToPlayerMovement(-movementVector)
|
||||
normalizeDirection(TouchObject.Position)
|
||||
MasterControl:AddToPlayerMovement(movementVector)
|
||||
MasterControl:SetIsJumping(false)
|
||||
end
|
||||
end)
|
||||
|
||||
OnInputEnded = function()
|
||||
TouchObject = nil
|
||||
flBtn.Visible = false
|
||||
frBtn.Visible = false
|
||||
|
||||
MasterControl:AddToPlayerMovement(-movementVector)
|
||||
movementVector = Vector3.new(0, 0, 0)
|
||||
end
|
||||
|
||||
DPadFrame.InputEnded:connect(function(inputObject)
|
||||
if inputObject == TouchObject then
|
||||
OnInputEnded()
|
||||
end
|
||||
end)
|
||||
|
||||
GuiService.MenuOpened:connect(function()
|
||||
if TouchObject then
|
||||
OnInputEnded()
|
||||
end
|
||||
end)
|
||||
|
||||
DPadFrame.Parent = parentFrame
|
||||
end
|
||||
|
||||
return DPad
|
||||
+559
@@ -0,0 +1,559 @@
|
||||
--[[
|
||||
// FileName: DynamicThumbstick
|
||||
// Version 0.9
|
||||
// Written by: jhelms
|
||||
// Description: Implements dynamic thumbstick controls for touch devices
|
||||
--]]
|
||||
local Players = game:GetService("Players")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local GuiService = game:GetService("GuiService")
|
||||
local RunService = game:GetService("RunService")
|
||||
local TweenService = game:GetService("TweenService")
|
||||
local Settings = UserSettings()
|
||||
local GameSettings = Settings.GameSettings
|
||||
|
||||
local MasterControl = require(script.Parent)
|
||||
|
||||
local Thumbstick = {}
|
||||
local Enabled = false
|
||||
|
||||
--[[ Script Variables ]]--
|
||||
while not Players.LocalPlayer do
|
||||
Players.PlayerAdded:wait()
|
||||
end
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
|
||||
local Tools = {}
|
||||
local ToolEquipped = nil
|
||||
|
||||
local RevertAutoJumpEnabledToFalse = false
|
||||
|
||||
local ThumbstickFrame = nil
|
||||
local GestureArea = nil
|
||||
local StartImage = nil
|
||||
local EndImage = nil
|
||||
local MiddleImages = {}
|
||||
|
||||
local MoveTouchObject = nil
|
||||
local IsFollowStick = false
|
||||
local ThumbstickFrame = nil
|
||||
local OnMoveTouchEnded = nil -- defined in Create()
|
||||
local OnTouchMovedCn = nil
|
||||
local OnTouchEndedCn = nil
|
||||
local TouchActivateCn = nil
|
||||
local OnRenderSteppedCn = nil
|
||||
local currentMoveVector = Vector3.new(0,0,0)
|
||||
local IsFirstTouch = true
|
||||
|
||||
--[[ Constants ]]--
|
||||
|
||||
local TOUCH_CONTROLS_SHEET = "rbxasset://textures/ui/Input/TouchControlsSheetV2.png"
|
||||
|
||||
local MIDDLE_TRANSPARENCIES = {
|
||||
1 - 0.89,
|
||||
1 - 0.70,
|
||||
1 - 0.60,
|
||||
1 - 0.50,
|
||||
1 - 0.40,
|
||||
1 - 0.30,
|
||||
1 - 0.25
|
||||
}
|
||||
local NUM_MIDDLE_IMAGES = #MIDDLE_TRANSPARENCIES
|
||||
|
||||
local TOUCH_IS_TAP_TIME_THRESHOLD = 0.5
|
||||
local TOUCH_IS_TAP_DISTANCE_THRESHOLD = 25
|
||||
|
||||
local HasFadedBackgroundInPortrait = false
|
||||
local HasFadedBackgroundInLandscape = false
|
||||
local FadeInAndOutBackground = true
|
||||
local FadeInAndOutMaxAlpha = 0.35
|
||||
local TweenInAlphaStart = nil
|
||||
local TweenOutAlphaStart = nil
|
||||
|
||||
local FADE_IN_OUT_HALF_DURATION_DEFAULT = 0.3
|
||||
local FADE_IN_OUT_HALF_DURATION_ORIENTATION_CHANGE = 2
|
||||
local FADE_IN_OUT_BALANCE_DEFAULT = 0.5
|
||||
local FadeInAndOutHalfDuration = FADE_IN_OUT_HALF_DURATION_DEFAULT
|
||||
local FadeInAndOutBalance = FADE_IN_OUT_BALANCE_DEFAULT
|
||||
|
||||
local ThumbstickFadeTweenInfo = TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
|
||||
|
||||
--[[ Local functionality ]]--
|
||||
|
||||
local function isDynamicThumbstickEnabled()
|
||||
return ThumbstickFrame and ThumbstickFrame.Visible
|
||||
end
|
||||
|
||||
local function enableAutoJump(humanoid)
|
||||
if humanoid and isDynamicThumbstickEnabled() then
|
||||
local shouldRevert = humanoid.AutoJumpEnabled == false
|
||||
shouldRevert = shouldRevert and LocalPlayer.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice
|
||||
RevertAutoJumpEnabledToFalse = shouldRevert
|
||||
humanoid.AutoJumpEnabled = true
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local function onCharacterAdded(character)
|
||||
for _, child in ipairs(LocalPlayer.Character:GetChildren()) do
|
||||
if child:IsA("Tool") then
|
||||
ToolEquipped = child
|
||||
end
|
||||
end
|
||||
character.ChildAdded:Connect(function(child)
|
||||
if child:IsA("Tool") then
|
||||
ToolEquipped = child
|
||||
elseif child:IsA("Humanoid") then
|
||||
enableAutoJump(child)
|
||||
end
|
||||
end)
|
||||
character.ChildRemoved:Connect(function(child)
|
||||
if child:IsA("Tool") then
|
||||
if child == ToolEquipped then
|
||||
ToolEquipped = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local humanoid = character:FindFirstChildOfClass("Humanoid")
|
||||
if humanoid then
|
||||
enableAutoJump(humanoid)
|
||||
end
|
||||
end
|
||||
LocalPlayer.CharacterAdded:Connect(onCharacterAdded)
|
||||
if LocalPlayer.Character then
|
||||
onCharacterAdded(LocalPlayer.Character)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--[[ Public API ]]--
|
||||
function Thumbstick:Enable()
|
||||
Enabled = true
|
||||
ThumbstickFrame.Visible = true
|
||||
local humanoid = MasterControl:GetHumanoid()
|
||||
enableAutoJump(humanoid)
|
||||
end
|
||||
|
||||
function Thumbstick:Disable()
|
||||
Enabled = false
|
||||
if RevertAutoJumpEnabledToFalse then
|
||||
local humanoid = MasterControl:GetHumanoid()
|
||||
if humanoid then
|
||||
humanoid.AutoJumpEnabled = false
|
||||
end
|
||||
end
|
||||
ThumbstickFrame.Visible = false
|
||||
OnMoveTouchEnded()
|
||||
end
|
||||
|
||||
function Thumbstick:GetInputObject()
|
||||
return MoveTouchObject
|
||||
end
|
||||
|
||||
function Thumbstick:Create(parentFrame)
|
||||
if ThumbstickFrame then
|
||||
ThumbstickFrame:Destroy()
|
||||
ThumbstickFrame = nil
|
||||
if OnTouchMovedCn then
|
||||
OnTouchMovedCn:disconnect()
|
||||
OnTouchMovedCn = nil
|
||||
end
|
||||
if OnTouchEndedCn then
|
||||
OnTouchEndedCn:disconnect()
|
||||
OnTouchEndedCn = nil
|
||||
end
|
||||
if OnRenderSteppedCn then
|
||||
OnRenderSteppedCn:disconnect()
|
||||
OnRenderSteppedCn = nil
|
||||
end
|
||||
if TouchActivateCn then
|
||||
TouchActivateCn:disconnect()
|
||||
TouchActivateCn = nil
|
||||
end
|
||||
end
|
||||
|
||||
local ThumbstickSize = 45
|
||||
local ThumbstickRingSize = 20
|
||||
local MiddleSize = 10
|
||||
local MiddleSpacing = MiddleSize + 4
|
||||
local RadiusOfDeadZone = 2
|
||||
local RadiusOfMaxSpeed = 50
|
||||
|
||||
local screenSize = parentFrame.AbsoluteSize
|
||||
local isBigScreen = math.min(screenSize.x, screenSize.y) > 500
|
||||
if isBigScreen then
|
||||
ThumbstickSize = ThumbstickSize * 2
|
||||
ThumbstickRingSize = ThumbstickRingSize * 2
|
||||
MiddleSize = MiddleSize * 2
|
||||
MiddleSpacing = MiddleSpacing * 2
|
||||
RadiusOfDeadZone = RadiusOfDeadZone * 2
|
||||
RadiusOfMaxSpeed = RadiusOfMaxSpeed * 2
|
||||
end
|
||||
|
||||
local color = Color3.fromRGB(255, 255, 255)
|
||||
|
||||
local function layoutThumbstickFrame(portraitMode)
|
||||
if portraitMode then
|
||||
ThumbstickFrame.Size = UDim2.new(1, 0, 0.4, 0)
|
||||
ThumbstickFrame.Position = UDim2.new(0, 0, 0.6, 0)
|
||||
GestureArea.Size = UDim2.new(1, 0, 0.6, 0)
|
||||
GestureArea.Position = UDim2.new(0, 0, 0, 0)
|
||||
else
|
||||
ThumbstickFrame.Size = UDim2.new(0.4, 0, 2/3, 0)
|
||||
ThumbstickFrame.Position = UDim2.new(0, 0, 1/3, 0)
|
||||
GestureArea.Size = UDim2.new(1, 0, 1, 0)
|
||||
GestureArea.Position = UDim2.new(0, 0, 0, 0)
|
||||
end
|
||||
end
|
||||
|
||||
GestureArea = Instance.new("Frame")
|
||||
GestureArea.Name = "GestureArea"
|
||||
GestureArea.Active = false
|
||||
GestureArea.Visible = true
|
||||
GestureArea.BackgroundTransparency = 1
|
||||
GestureArea.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||||
|
||||
ThumbstickFrame = Instance.new('Frame')
|
||||
ThumbstickFrame.Name = "DynamicThumbstickFrame"
|
||||
ThumbstickFrame.Active = false
|
||||
ThumbstickFrame.Visible = false
|
||||
ThumbstickFrame.BackgroundTransparency = 1.0
|
||||
ThumbstickFrame.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||||
layoutThumbstickFrame()
|
||||
|
||||
StartImage = Instance.new("ImageLabel")
|
||||
StartImage.Name = "ThumbstickStart"
|
||||
StartImage.Visible = true
|
||||
StartImage.BackgroundTransparency = 1
|
||||
|
||||
StartImage.Image = TOUCH_CONTROLS_SHEET
|
||||
StartImage.ImageRectOffset = Vector2.new(1,1)
|
||||
StartImage.ImageRectSize = Vector2.new(144, 144)
|
||||
StartImage.ImageColor3 = Color3.new(0, 0, 0)
|
||||
StartImage.AnchorPoint = Vector2.new(0.5, 0.5)
|
||||
StartImage.Position = UDim2.new(0, ThumbstickRingSize * 3.3, 1, -ThumbstickRingSize * 2.8)
|
||||
StartImage.Size = UDim2.new(0, ThumbstickRingSize * 3.7, 0, ThumbstickRingSize * 3.7)
|
||||
StartImage.ZIndex = 10
|
||||
StartImage.Parent = ThumbstickFrame
|
||||
|
||||
EndImage = Instance.new("ImageLabel")
|
||||
EndImage.Name = "ThumbstickEnd"
|
||||
EndImage.Visible = true
|
||||
EndImage.BackgroundTransparency = 1
|
||||
EndImage.Image = TOUCH_CONTROLS_SHEET
|
||||
EndImage.ImageRectOffset = Vector2.new(1,1)
|
||||
EndImage.ImageRectSize = Vector2.new(144, 144)
|
||||
EndImage.AnchorPoint = Vector2.new(0.5, 0.5)
|
||||
EndImage.Position = StartImage.Position
|
||||
EndImage.Size = UDim2.new(0, ThumbstickSize * 0.8, 0, ThumbstickSize * 0.8)
|
||||
EndImage.ZIndex = 10
|
||||
EndImage.Parent = ThumbstickFrame
|
||||
|
||||
for i = 1, NUM_MIDDLE_IMAGES do
|
||||
MiddleImages[i] = Instance.new("ImageLabel")
|
||||
MiddleImages[i].Name = "ThumbstickMiddle"
|
||||
MiddleImages[i].Visible = false
|
||||
MiddleImages[i].BackgroundTransparency = 1
|
||||
MiddleImages[i].Image = TOUCH_CONTROLS_SHEET
|
||||
MiddleImages[i].ImageRectOffset = Vector2.new(1,1)
|
||||
MiddleImages[i].ImageRectSize = Vector2.new(144, 144)
|
||||
MiddleImages[i].ImageTransparency = MIDDLE_TRANSPARENCIES[i]
|
||||
MiddleImages[i].AnchorPoint = Vector2.new(0.5, 0.5)
|
||||
MiddleImages[i].ZIndex = 9
|
||||
MiddleImages[i].Parent = 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
|
||||
|
||||
MoveTouchObject = nil
|
||||
local MoveTouchStartTime = nil
|
||||
local MoveTouchStartPosition = nil
|
||||
|
||||
local startImageFadeTween, endImageFadeTween, middleImageFadeTweens = nil, nil, {}
|
||||
local function fadeThumbstick(visible)
|
||||
if not visible and MoveTouchObject then
|
||||
return
|
||||
end
|
||||
if IsFirstTouch then return end
|
||||
|
||||
if startImageFadeTween then
|
||||
startImageFadeTween:Cancel()
|
||||
end
|
||||
if endImageFadeTween then
|
||||
endImageFadeTween:Cancel()
|
||||
end
|
||||
for i = 1, #MiddleImages do
|
||||
if middleImageFadeTweens[i] then
|
||||
middleImageFadeTweens[i]:Cancel()
|
||||
end
|
||||
end
|
||||
|
||||
if visible then
|
||||
startImageFadeTween = TweenService:Create(StartImage, ThumbstickFadeTweenInfo, { ImageTransparency = 0 })
|
||||
startImageFadeTween:Play()
|
||||
|
||||
endImageFadeTween = TweenService:Create(EndImage, ThumbstickFadeTweenInfo, { ImageTransparency = 0.2 })
|
||||
endImageFadeTween:Play()
|
||||
|
||||
for i = 1, #MiddleImages do
|
||||
middleImageFadeTweens[i] = TweenService:Create(MiddleImages[i], ThumbstickFadeTweenInfo, { ImageTransparency = MIDDLE_TRANSPARENCIES[i] })
|
||||
middleImageFadeTweens[i]:Play()
|
||||
end
|
||||
else
|
||||
startImageFadeTween = TweenService:Create(StartImage, ThumbstickFadeTweenInfo, { ImageTransparency = 1 })
|
||||
startImageFadeTween:Play()
|
||||
|
||||
endImageFadeTween = TweenService:Create(EndImage, ThumbstickFadeTweenInfo, { ImageTransparency = 1 })
|
||||
endImageFadeTween:Play()
|
||||
|
||||
for i = 1, #MiddleImages do
|
||||
middleImageFadeTweens[i] = TweenService:Create(MiddleImages[i], ThumbstickFadeTweenInfo, { ImageTransparency = 1 })
|
||||
middleImageFadeTweens[i]:Play()
|
||||
end
|
||||
end
|
||||
end
|
||||
local function fadeThumbstickFrame(fadeDuration, fadeRatio)
|
||||
FadeInAndOutHalfDuration = fadeDuration * 0.5
|
||||
FadeInAndOutBalance = fadeRatio
|
||||
TweenInAlphaStart = tick()
|
||||
end
|
||||
|
||||
local function doMove(direction)
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
|
||||
currentMoveVector = direction
|
||||
|
||||
-- Scaled Radial Dead Zone
|
||||
local inputAxisMagnitude = currentMoveVector.magnitude
|
||||
if inputAxisMagnitude < RadiusOfDeadZone then
|
||||
currentMoveVector = Vector3.new()
|
||||
else
|
||||
currentMoveVector = currentMoveVector.unit*(1 - math.max(0, (RadiusOfMaxSpeed - currentMoveVector.magnitude)/RadiusOfMaxSpeed))
|
||||
currentMoveVector = Vector3.new(currentMoveVector.x, 0, currentMoveVector.y)
|
||||
end
|
||||
|
||||
MasterControl:AddToPlayerMovement(currentMoveVector)
|
||||
end
|
||||
|
||||
local function layoutMiddleImages(startPos, endPos)
|
||||
local startDist = (ThumbstickSize / 2) + MiddleSize
|
||||
local vector = endPos - startPos
|
||||
local distAvailable = vector.magnitude - (ThumbstickRingSize / 2) - MiddleSize
|
||||
local direction = vector.unit
|
||||
|
||||
local distNeeded = MiddleSpacing * NUM_MIDDLE_IMAGES
|
||||
local spacing = MiddleSpacing
|
||||
|
||||
if distNeeded < distAvailable then
|
||||
spacing = distAvailable / NUM_MIDDLE_IMAGES
|
||||
end
|
||||
|
||||
for i = 1, NUM_MIDDLE_IMAGES do
|
||||
local image = 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, MiddleSize * exposedFraction, 0, MiddleSize * exposedFraction)
|
||||
else
|
||||
image.Visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function moveStick(pos)
|
||||
local startPos = Vector2.new(MoveTouchStartPosition.X, MoveTouchStartPosition.Y) - ThumbstickFrame.AbsolutePosition
|
||||
local endPos = Vector2.new(pos.X, pos.Y) - ThumbstickFrame.AbsolutePosition
|
||||
local relativePosition = endPos - startPos
|
||||
local length = relativePosition.magnitude
|
||||
local maxLength = ThumbstickFrame.AbsoluteSize.X
|
||||
|
||||
length = math.min(length, maxLength)
|
||||
relativePosition = relativePosition*length
|
||||
|
||||
EndImage.Position = UDim2.new(0, endPos.X, 0, endPos.Y)
|
||||
|
||||
layoutMiddleImages(startPos, endPos)
|
||||
end
|
||||
|
||||
-- input connections
|
||||
ThumbstickFrame.InputBegan:connect(function(inputObject)
|
||||
if inputObject.UserInputType ~= Enum.UserInputType.Touch or inputObject.UserInputState ~= Enum.UserInputState.Begin then
|
||||
return
|
||||
end
|
||||
if MoveTouchObject then
|
||||
return
|
||||
end
|
||||
|
||||
if IsFirstTouch then
|
||||
IsFirstTouch = false
|
||||
local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out,0,false,0)
|
||||
TweenService:Create(StartImage, tweenInfo, {Size = UDim2.new(0, 0, 0, 0)}):Play()
|
||||
TweenService:Create(EndImage, tweenInfo, {Size = UDim2.new(0, ThumbstickSize, 0, ThumbstickSize), ImageColor3 = Color3.new(0,0,0)}):Play()
|
||||
end
|
||||
|
||||
MoveTouchObject = inputObject
|
||||
MoveTouchStartTime = tick()
|
||||
MoveTouchStartPosition = inputObject.Position
|
||||
local startPosVec2 = Vector2.new(inputObject.Position.X - ThumbstickFrame.AbsolutePosition.X, inputObject.Position.Y - ThumbstickFrame.AbsolutePosition.Y)
|
||||
|
||||
StartImage.Visible = true
|
||||
StartImage.Position = UDim2.new(0, startPosVec2.X, 0, startPosVec2.Y)
|
||||
EndImage.Visible = true
|
||||
EndImage.Position = StartImage.Position
|
||||
|
||||
fadeThumbstick(true)
|
||||
moveStick(inputObject.Position)
|
||||
|
||||
if FadeInAndOutBackground then
|
||||
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 = HasFadedBackgroundInLandscape
|
||||
HasFadedBackgroundInLandscape = true
|
||||
elseif playerGui.CurrentScreenOrientation == Enum.ScreenOrientation.Portrait then
|
||||
hasFadedBackgroundInOrientation = HasFadedBackgroundInPortrait
|
||||
HasFadedBackgroundInPortrait = true
|
||||
end
|
||||
end
|
||||
|
||||
if not hasFadedBackgroundInOrientation then
|
||||
FadeInAndOutHalfDuration = FADE_IN_OUT_HALF_DURATION_DEFAULT
|
||||
FadeInAndOutBalance = FADE_IN_OUT_BALANCE_DEFAULT
|
||||
TweenInAlphaStart = tick()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
OnTouchMovedCn = UserInputService.TouchMoved:connect(function(inputObject, isProcessed)
|
||||
if inputObject == MoveTouchObject then
|
||||
|
||||
local direction = Vector2.new(inputObject.Position.x - MoveTouchStartPosition.x, inputObject.Position.y - MoveTouchStartPosition.y)
|
||||
if math.abs(direction.x) > 0 or math.abs(direction.y) > 0 then
|
||||
doMove(direction)
|
||||
moveStick(inputObject.Position)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
OnMoveTouchEnded = function(inputObject)
|
||||
if inputObject then
|
||||
local direction = Vector2.new(inputObject.Position.x - MoveTouchStartPosition.x, inputObject.Position.y - MoveTouchStartPosition.y)
|
||||
end
|
||||
|
||||
MoveTouchObject = nil
|
||||
fadeThumbstick(false)
|
||||
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
end
|
||||
|
||||
OnRenderSteppedCn = RunService.RenderStepped:Connect(function(step)
|
||||
if TweenInAlphaStart ~= nil then
|
||||
local delta = tick() - TweenInAlphaStart
|
||||
local fadeInTime = (FadeInAndOutHalfDuration * 2 * FadeInAndOutBalance)
|
||||
ThumbstickFrame.BackgroundTransparency = 1 - FadeInAndOutMaxAlpha*math.min(delta/fadeInTime, 1)
|
||||
if delta > fadeInTime then
|
||||
TweenOutAlphaStart = tick()
|
||||
TweenInAlphaStart = nil
|
||||
end
|
||||
elseif TweenOutAlphaStart ~= nil then
|
||||
local delta = tick() - TweenOutAlphaStart
|
||||
local fadeOutTime = (FadeInAndOutHalfDuration * 2) - (FadeInAndOutHalfDuration * 2 * FadeInAndOutBalance)
|
||||
ThumbstickFrame.BackgroundTransparency = 1 - FadeInAndOutMaxAlpha + FadeInAndOutMaxAlpha*math.min(delta/fadeOutTime, 1)
|
||||
if delta > fadeOutTime then
|
||||
TweenOutAlphaStart = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
OnTouchEndedCn = UserInputService.TouchEnded:connect(function(inputObject, isProcessed)
|
||||
if inputObject == MoveTouchObject then
|
||||
OnMoveTouchEnded(inputObject)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
GuiService.MenuOpened:connect(function()
|
||||
if MoveTouchObject then
|
||||
OnMoveTouchEnded(nil)
|
||||
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()
|
||||
FadeInAndOutHalfDuration = 2.5
|
||||
FadeInAndOutBalance = 0.05
|
||||
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
|
||||
HasFadedBackgroundInPortrait = true
|
||||
else
|
||||
HasFadedBackgroundInLandscape = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
GestureArea.Parent = parentFrame.Parent
|
||||
ThumbstickFrame.Parent = parentFrame
|
||||
|
||||
spawn(function()
|
||||
if game:IsLoaded() then
|
||||
longShowBackground()
|
||||
else
|
||||
game.Loaded:wait()
|
||||
longShowBackground()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return Thumbstick
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
--[[
|
||||
// FileName: Gamepad
|
||||
// Written by: jeditkacheff
|
||||
// Description: Implements movement controls for gamepad devices (XBox, PS4, MFi, etc.)
|
||||
--]]
|
||||
local Gamepad = {}
|
||||
|
||||
local MasterControl = require(script.Parent)
|
||||
|
||||
local Players = game:GetService('Players')
|
||||
local RunService = game:GetService('RunService')
|
||||
local UserInputService = game:GetService('UserInputService')
|
||||
local ContextActionService = game:GetService('ContextActionService')
|
||||
local StarterPlayer = game:GetService('StarterPlayer')
|
||||
local Settings = UserSettings()
|
||||
local GameSettings = Settings.GameSettings
|
||||
local currentMoveVector = Vector3.new(0,0,0)
|
||||
local activateGamepad = nil
|
||||
|
||||
local gamepadConnectedCon = nil
|
||||
local gamepadDisconnectedCon = nil
|
||||
|
||||
while not Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
|
||||
--[[ Constants ]]--
|
||||
local thumbstickDeadzone = 0.22 --raised from 14% on 3/1/16 to accommodate looser XB360 controllers
|
||||
|
||||
function assignActivateGamepad()
|
||||
local connectedGamepads = UserInputService:GetConnectedGamepads()
|
||||
if #connectedGamepads > 0 then
|
||||
for i = 1, #connectedGamepads do
|
||||
if activateGamepad == nil then
|
||||
activateGamepad = connectedGamepads[i]
|
||||
elseif connectedGamepads[i].Value < activateGamepad.Value then
|
||||
activateGamepad = connectedGamepads[i]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if activateGamepad == nil then -- nothing is connected, at least set up for gamepad1
|
||||
activateGamepad = Enum.UserInputType.Gamepad1
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Public API ]]--
|
||||
function Gamepad:Enable()
|
||||
local forwardValue = 0
|
||||
local backwardValue = 0
|
||||
local leftValue = 0
|
||||
local rightValue = 0
|
||||
|
||||
local moveFunc = LocalPlayer.Move
|
||||
local gamepadSupports = UserInputService.GamepadSupports
|
||||
|
||||
local controlCharacterGamepad = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.Cancel then
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
return
|
||||
end
|
||||
|
||||
if activateGamepad ~= inputObject.UserInputType then return end
|
||||
if inputObject.KeyCode ~= Enum.KeyCode.Thumbstick1 then return end
|
||||
|
||||
if inputObject.Position.magnitude > thumbstickDeadzone then
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(inputObject.Position.X, 0, -inputObject.Position.Y)
|
||||
MasterControl:AddToPlayerMovement(currentMoveVector)
|
||||
else
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
end
|
||||
end
|
||||
|
||||
local jumpCharacterGamepad = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.Cancel then
|
||||
MasterControl:SetIsJumping(false)
|
||||
return
|
||||
end
|
||||
|
||||
if activateGamepad ~= inputObject.UserInputType then return end
|
||||
if inputObject.KeyCode ~= Enum.KeyCode.ButtonA then return end
|
||||
|
||||
MasterControl:SetIsJumping(inputObject.UserInputState == Enum.UserInputState.Begin)
|
||||
end
|
||||
|
||||
local doDpadMoveUpdate = function(userInputType)
|
||||
if LocalPlayer and LocalPlayer.Character then
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(leftValue + rightValue,0,forwardValue + backwardValue)
|
||||
MasterControl:AddToPlayerMovement(currentMoveVector)
|
||||
end
|
||||
end
|
||||
|
||||
local moveForwardFunc = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.End then
|
||||
forwardValue = -1
|
||||
elseif inputState == Enum.UserInputState.Begin or inputState == Enum.UserInputState.Cancel then
|
||||
forwardValue = 0
|
||||
end
|
||||
|
||||
doDpadMoveUpdate(inputObject.UserInputType)
|
||||
end
|
||||
|
||||
local moveBackwardFunc = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.End then
|
||||
backwardValue = 1
|
||||
elseif inputState == Enum.UserInputState.Begin or inputState == Enum.UserInputState.Cancel then
|
||||
backwardValue = 0
|
||||
end
|
||||
|
||||
doDpadMoveUpdate(inputObject.UserInputType)
|
||||
end
|
||||
|
||||
local moveLeftFunc = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.End then
|
||||
leftValue = -1
|
||||
elseif inputState == Enum.UserInputState.Begin or inputState == Enum.UserInputState.Cancel then
|
||||
leftValue = 0
|
||||
end
|
||||
|
||||
doDpadMoveUpdate(inputObject.UserInputType)
|
||||
end
|
||||
|
||||
local moveRightFunc = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.End then
|
||||
rightValue = 1
|
||||
elseif inputState == Enum.UserInputState.Begin or inputState == Enum.UserInputState.Cancel then
|
||||
rightValue = 0
|
||||
end
|
||||
|
||||
doDpadMoveUpdate(inputObject.UserInputType)
|
||||
end
|
||||
|
||||
local function setActivateGamepad()
|
||||
if activateGamepad then
|
||||
ContextActionService:UnbindActivate(activateGamepad, Enum.KeyCode.ButtonR2)
|
||||
end
|
||||
assignActivateGamepad()
|
||||
if activateGamepad then
|
||||
ContextActionService:BindActivate(activateGamepad, Enum.KeyCode.ButtonR2)
|
||||
end
|
||||
end
|
||||
|
||||
ContextActionService:BindAction("JumpButton",jumpCharacterGamepad, false, Enum.KeyCode.ButtonA)
|
||||
ContextActionService:BindAction("MoveThumbstick",controlCharacterGamepad, false, Enum.KeyCode.Thumbstick1)
|
||||
|
||||
setActivateGamepad()
|
||||
|
||||
if not gamepadSupports(UserInputService, activateGamepad, Enum.KeyCode.Thumbstick1) then
|
||||
-- if the gamepad supports thumbsticks, theres no point in having the dpad buttons getting eaten up by these actions
|
||||
ContextActionService:BindAction("forwardDpad", moveForwardFunc, false, Enum.KeyCode.DPadUp)
|
||||
ContextActionService:BindAction("backwardDpad", moveBackwardFunc, false, Enum.KeyCode.DPadDown)
|
||||
ContextActionService:BindAction("leftDpad", moveLeftFunc, false, Enum.KeyCode.DPadLeft)
|
||||
ContextActionService:BindAction("rightDpad", moveRightFunc, false, Enum.KeyCode.DPadRight)
|
||||
end
|
||||
|
||||
gamepadConnectedCon = UserInputService.GamepadDisconnected:connect(function(gamepadEnum)
|
||||
if activateGamepad ~= gamepadEnum then return end
|
||||
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
|
||||
activateGamepad = nil
|
||||
setActivateGamepad()
|
||||
end)
|
||||
|
||||
gamepadDisconnectedCon = UserInputService.GamepadConnected:connect(function(gamepadEnum)
|
||||
if activateGamepad == nil then
|
||||
setActivateGamepad()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function Gamepad:Disable()
|
||||
|
||||
ContextActionService:UnbindAction("forwardDpad")
|
||||
ContextActionService:UnbindAction("backwardDpad")
|
||||
ContextActionService:UnbindAction("leftDpad")
|
||||
ContextActionService:UnbindAction("rightDpad")
|
||||
|
||||
ContextActionService:UnbindAction("MoveThumbstick")
|
||||
ContextActionService:UnbindAction("JumpButton")
|
||||
ContextActionService:UnbindActivate(activateGamepad, Enum.KeyCode.ButtonR2)
|
||||
|
||||
if gamepadConnectedCon then gamepadConnectedCon:disconnect() end
|
||||
if gamepadDisconnectedCon then gamepadDisconnectedCon:disconnect() end
|
||||
|
||||
activateGamepad = nil
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
MasterControl:SetIsJumping(false)
|
||||
end
|
||||
|
||||
return Gamepad
|
||||
+175
@@ -0,0 +1,175 @@
|
||||
--[[
|
||||
// FileName: ComputerMovementKeyboardMovement
|
||||
// Version 1.2
|
||||
// Written by: jeditkacheff/jmargh
|
||||
// Description: Implements movement controls for keyboard devices
|
||||
--]]
|
||||
local Players = game:GetService('Players')
|
||||
local UserInputService = game:GetService('UserInputService')
|
||||
local ContextActionService = game:GetService('ContextActionService')
|
||||
local StarterPlayer = game:GetService('StarterPlayer')
|
||||
local Settings = UserSettings()
|
||||
local GameSettings = Settings.GameSettings
|
||||
|
||||
local KeyboardMovement = {}
|
||||
|
||||
while not Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
local CachedHumanoid = nil
|
||||
local SeatJumpCn = nil
|
||||
local TextFocusReleasedCn = nil
|
||||
local TextFocusGainedCn = nil
|
||||
local WindowFocusReleasedCn = nil
|
||||
|
||||
local MasterControl = require(script.Parent)
|
||||
local currentMoveVector = Vector3.new(0,0,0)
|
||||
|
||||
--[[ Local Functions ]]--
|
||||
local function getHumanoid()
|
||||
local character = LocalPlayer and LocalPlayer.Character
|
||||
if character then
|
||||
if CachedHumanoid and CachedHumanoid.Parent == character then
|
||||
return CachedHumanoid
|
||||
else
|
||||
CachedHumanoid = nil
|
||||
for _,child in pairs(character:GetChildren()) do
|
||||
if child:IsA('Humanoid') then
|
||||
CachedHumanoid = child
|
||||
return CachedHumanoid
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Public API ]]--
|
||||
function KeyboardMovement:Enable()
|
||||
if not UserInputService.KeyboardEnabled then
|
||||
return
|
||||
end
|
||||
|
||||
local forwardValue = 0
|
||||
local backwardValue = 0
|
||||
local leftValue = 0
|
||||
local rightValue = 0
|
||||
|
||||
local updateMovement = function(inputState)
|
||||
if inputState == Enum.UserInputState.Cancel then
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0, 0, 0)
|
||||
else
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(leftValue + rightValue,0,forwardValue + backwardValue)
|
||||
MasterControl:AddToPlayerMovement(currentMoveVector)
|
||||
end
|
||||
end
|
||||
|
||||
local moveForwardFunc = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.Begin then
|
||||
forwardValue = -1
|
||||
elseif inputState == Enum.UserInputState.End or inputState == Enum.UserInputState.Cancel then
|
||||
forwardValue = 0
|
||||
end
|
||||
updateMovement(inputState)
|
||||
end
|
||||
|
||||
local moveBackwardFunc = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.Begin then
|
||||
backwardValue = 1
|
||||
elseif inputState == Enum.UserInputState.End or inputState == Enum.UserInputState.Cancel then
|
||||
backwardValue = 0
|
||||
end
|
||||
updateMovement(inputState)
|
||||
end
|
||||
|
||||
local moveLeftFunc = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.Begin then
|
||||
leftValue = -1
|
||||
elseif inputState == Enum.UserInputState.End or inputState == Enum.UserInputState.Cancel then
|
||||
leftValue = 0
|
||||
end
|
||||
updateMovement(inputState)
|
||||
end
|
||||
|
||||
local moveRightFunc = function(actionName, inputState, inputObject)
|
||||
if inputState == Enum.UserInputState.Begin then
|
||||
rightValue = 1
|
||||
elseif inputState == Enum.UserInputState.End or inputState == Enum.UserInputState.Cancel then
|
||||
rightValue = 0
|
||||
end
|
||||
updateMovement(inputState)
|
||||
end
|
||||
|
||||
local jumpFunc = function(actionName, inputState, inputObject)
|
||||
MasterControl:SetIsJumping(inputState == Enum.UserInputState.Begin)
|
||||
end
|
||||
|
||||
-- TODO: remove up and down arrows, these seem unnecessary
|
||||
ContextActionService:BindActionToInputTypes("forwardMovement", moveForwardFunc, false, Enum.PlayerActions.CharacterForward)
|
||||
ContextActionService:BindActionToInputTypes("backwardMovement", moveBackwardFunc, false, Enum.PlayerActions.CharacterBackward)
|
||||
ContextActionService:BindActionToInputTypes("leftMovement", moveLeftFunc, false, Enum.PlayerActions.CharacterLeft)
|
||||
ContextActionService:BindActionToInputTypes("rightMovement", moveRightFunc, false, Enum.PlayerActions.CharacterRight)
|
||||
ContextActionService:BindActionToInputTypes("jumpAction", jumpFunc, false, Enum.PlayerActions.CharacterJump)
|
||||
-- TODO: make sure we check key state before binding to check if key is already down
|
||||
|
||||
local function onFocusReleased()
|
||||
local humanoid = getHumanoid()
|
||||
if humanoid then
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0, 0, 0)
|
||||
forwardValue, backwardValue, leftValue, rightValue = 0, 0, 0, 0
|
||||
MasterControl:SetIsJumping(false)
|
||||
end
|
||||
end
|
||||
|
||||
local function onTextFocusGained(textboxFocused)
|
||||
MasterControl:SetIsJumping(false)
|
||||
end
|
||||
|
||||
SeatJumpCn = UserInputService.InputBegan:connect(function(inputObject, isProcessed)
|
||||
if inputObject.KeyCode == Enum.KeyCode.Backspace and not isProcessed then
|
||||
local humanoid = getHumanoid()
|
||||
if humanoid and (humanoid.Sit or humanoid.PlatformStand) then
|
||||
MasterControl:DoJump()
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
TextFocusReleasedCn = UserInputService.TextBoxFocusReleased:connect(onFocusReleased)
|
||||
TextFocusGainedCn = UserInputService.TextBoxFocused:connect(onTextFocusGained)
|
||||
-- TODO: remove pcall when API is live
|
||||
WindowFocusReleasedCn = UserInputService.WindowFocusReleased:connect(onFocusReleased)
|
||||
end
|
||||
|
||||
function KeyboardMovement:Disable()
|
||||
ContextActionService:UnbindAction("forwardMovement")
|
||||
ContextActionService:UnbindAction("backwardMovement")
|
||||
ContextActionService:UnbindAction("leftMovement")
|
||||
ContextActionService:UnbindAction("rightMovement")
|
||||
ContextActionService:UnbindAction("jumpAction")
|
||||
|
||||
if SeatJumpCn then
|
||||
SeatJumpCn:disconnect()
|
||||
SeatJumpCn = nil
|
||||
end
|
||||
if TextFocusReleasedCn then
|
||||
TextFocusReleasedCn:disconnect()
|
||||
TextFocusReleasedCn = nil
|
||||
end
|
||||
if TextFocusGainedCn then
|
||||
TextFocusGainedCn:disconnect()
|
||||
TextFocusGainedCn = nil
|
||||
end
|
||||
if WindowFocusReleasedCn then
|
||||
WindowFocusReleasedCn:disconnect()
|
||||
WindowFocusReleasedCn = nil
|
||||
end
|
||||
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
MasterControl:SetIsJumping(false)
|
||||
end
|
||||
|
||||
return KeyboardMovement
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
--[[
|
||||
// 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
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
--[[
|
||||
// FileName: Thumbstick
|
||||
// Version 1.0
|
||||
// Written by: jmargh
|
||||
// Description: Implements thumbstick controls for touch devices
|
||||
--]]
|
||||
local Players = game:GetService('Players')
|
||||
local UserInputService = game:GetService('UserInputService')
|
||||
local GuiService = game:GetService('GuiService')
|
||||
|
||||
local MasterControl = require(script.Parent)
|
||||
|
||||
local Thumbstick = {}
|
||||
|
||||
--[[ Script Variables ]]--
|
||||
while not Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
local IsFollowStick = false
|
||||
local ThumbstickFrame = nil
|
||||
local MoveTouchObject = nil
|
||||
local OnTouchEnded = nil -- defined in Create()
|
||||
local OnTouchMovedCn = nil
|
||||
local OnTouchEndedCn = nil
|
||||
local currentMoveVector = Vector3.new(0,0,0)
|
||||
|
||||
--[[ Constants ]]--
|
||||
local TOUCH_CONTROL_SHEET = "rbxasset://textures/ui/TouchControlsSheet.png"
|
||||
|
||||
--[[ Public API ]]--
|
||||
function Thumbstick:Enable()
|
||||
ThumbstickFrame.Visible = true
|
||||
end
|
||||
|
||||
function Thumbstick:Disable()
|
||||
ThumbstickFrame.Visible = false
|
||||
OnTouchEnded()
|
||||
end
|
||||
|
||||
function Thumbstick:Create(parentFrame)
|
||||
if ThumbstickFrame then
|
||||
ThumbstickFrame:Destroy()
|
||||
ThumbstickFrame = nil
|
||||
if OnTouchMovedCn then
|
||||
OnTouchMovedCn:disconnect()
|
||||
OnTouchMovedCn = 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 thumbstickSize = isSmallScreen and 70 or 120
|
||||
local position = isSmallScreen and UDim2.new(0, (thumbstickSize/2) - 10, 1, -thumbstickSize - 20) or
|
||||
UDim2.new(0, thumbstickSize/2, 1, -thumbstickSize * 1.75)
|
||||
|
||||
ThumbstickFrame = Instance.new('Frame')
|
||||
ThumbstickFrame.Name = "ThumbstickFrame"
|
||||
ThumbstickFrame.Active = true
|
||||
ThumbstickFrame.Visible = false
|
||||
ThumbstickFrame.Size = UDim2.new(0, thumbstickSize, 0, thumbstickSize)
|
||||
ThumbstickFrame.Position = position
|
||||
ThumbstickFrame.BackgroundTransparency = 1
|
||||
|
||||
local outerImage = Instance.new('ImageLabel')
|
||||
outerImage.Name = "OuterImage"
|
||||
outerImage.Image = TOUCH_CONTROL_SHEET
|
||||
outerImage.ImageRectOffset = Vector2.new()
|
||||
outerImage.ImageRectSize = Vector2.new(220, 220)
|
||||
outerImage.BackgroundTransparency = 1
|
||||
outerImage.Size = UDim2.new(0, thumbstickSize, 0, thumbstickSize)
|
||||
outerImage.Position = UDim2.new(0, 0, 0, 0)
|
||||
outerImage.Parent = ThumbstickFrame
|
||||
|
||||
local StickImage = Instance.new('ImageLabel')
|
||||
StickImage.Name = "StickImage"
|
||||
StickImage.Image = TOUCH_CONTROL_SHEET
|
||||
StickImage.ImageRectOffset = Vector2.new(220, 0)
|
||||
StickImage.ImageRectSize = Vector2.new(111, 111)
|
||||
StickImage.BackgroundTransparency = 1
|
||||
StickImage.Size = UDim2.new(0, thumbstickSize/2, 0, thumbstickSize/2)
|
||||
StickImage.Position = UDim2.new(0, thumbstickSize/2 - thumbstickSize/4, 0, thumbstickSize/2 - thumbstickSize/4)
|
||||
StickImage.ZIndex = 2
|
||||
StickImage.Parent = ThumbstickFrame
|
||||
|
||||
local centerPosition = nil
|
||||
local deadZone = 0.05
|
||||
local function doMove(direction)
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
|
||||
currentMoveVector = direction / (thumbstickSize/2)
|
||||
|
||||
-- Scaled Radial Dead Zone
|
||||
local inputAxisMagnitude = currentMoveVector.magnitude
|
||||
if inputAxisMagnitude < deadZone then
|
||||
currentMoveVector = Vector3.new()
|
||||
else
|
||||
currentMoveVector = currentMoveVector.unit * ((inputAxisMagnitude - deadZone) / (1 - deadZone))
|
||||
-- NOTE: Making currentMoveVector a unit vector will cause the player to instantly go max speed
|
||||
-- must check for zero length vector is using unit
|
||||
currentMoveVector = Vector3.new(currentMoveVector.x, 0, currentMoveVector.y)
|
||||
end
|
||||
|
||||
MasterControl:AddToPlayerMovement(currentMoveVector)
|
||||
end
|
||||
|
||||
local function moveStick(pos)
|
||||
local relativePosition = Vector2.new(pos.x - centerPosition.x, pos.y - centerPosition.y)
|
||||
local length = relativePosition.magnitude
|
||||
local maxLength = ThumbstickFrame.AbsoluteSize.x/2
|
||||
if IsFollowStick and length > maxLength then
|
||||
local offset = relativePosition.unit * maxLength
|
||||
ThumbstickFrame.Position = UDim2.new(
|
||||
0, pos.x - ThumbstickFrame.AbsoluteSize.x/2 - offset.x,
|
||||
0, pos.y - ThumbstickFrame.AbsoluteSize.y/2 - offset.y)
|
||||
else
|
||||
length = math.min(length, maxLength)
|
||||
relativePosition = relativePosition.unit * length
|
||||
end
|
||||
StickImage.Position = UDim2.new(0, relativePosition.x + StickImage.AbsoluteSize.x/2, 0, relativePosition.y + StickImage.AbsoluteSize.y/2)
|
||||
end
|
||||
|
||||
-- input connections
|
||||
ThumbstickFrame.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 MoveTouchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch
|
||||
or inputObject.UserInputState ~= Enum.UserInputState.Begin then
|
||||
return
|
||||
end
|
||||
|
||||
MoveTouchObject = inputObject
|
||||
ThumbstickFrame.Position = UDim2.new(0, inputObject.Position.x - ThumbstickFrame.Size.X.Offset/2, 0, inputObject.Position.y - ThumbstickFrame.Size.Y.Offset/2)
|
||||
centerPosition = Vector2.new(ThumbstickFrame.AbsolutePosition.x + ThumbstickFrame.AbsoluteSize.x/2,
|
||||
ThumbstickFrame.AbsolutePosition.y + ThumbstickFrame.AbsoluteSize.y/2)
|
||||
local direction = Vector2.new(inputObject.Position.x - centerPosition.x, inputObject.Position.y - centerPosition.y)
|
||||
end)
|
||||
|
||||
OnTouchMovedCn = UserInputService.TouchMoved:connect(function(inputObject, isProcessed)
|
||||
if inputObject == MoveTouchObject then
|
||||
centerPosition = Vector2.new(ThumbstickFrame.AbsolutePosition.x + ThumbstickFrame.AbsoluteSize.x/2,
|
||||
ThumbstickFrame.AbsolutePosition.y + ThumbstickFrame.AbsoluteSize.y/2)
|
||||
local direction = Vector2.new(inputObject.Position.x - centerPosition.x, inputObject.Position.y - centerPosition.y)
|
||||
doMove(direction)
|
||||
moveStick(inputObject.Position)
|
||||
end
|
||||
end)
|
||||
|
||||
OnTouchEnded = function()
|
||||
ThumbstickFrame.Position = position
|
||||
StickImage.Position = UDim2.new(0, ThumbstickFrame.Size.X.Offset/2 - thumbstickSize/4, 0, ThumbstickFrame.Size.Y.Offset/2 - thumbstickSize/4)
|
||||
MoveTouchObject = nil
|
||||
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
MasterControl:SetIsJumping(false)
|
||||
end
|
||||
|
||||
OnTouchEndedCn = UserInputService.TouchEnded:connect(function(inputObject, isProcessed)
|
||||
if inputObject == MoveTouchObject then
|
||||
OnTouchEnded()
|
||||
end
|
||||
end)
|
||||
|
||||
GuiService.MenuOpened:connect(function()
|
||||
if MoveTouchObject then
|
||||
OnTouchEnded()
|
||||
end
|
||||
end)
|
||||
|
||||
ThumbstickFrame.Parent = parentFrame
|
||||
end
|
||||
|
||||
return Thumbstick
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
--[[
|
||||
// FileName: TouchJump
|
||||
// Version 1.0
|
||||
// Written by: jmargh
|
||||
// Description: Implements jump controls for touch devices. Use with Thumbstick and Thumbpad
|
||||
--]]
|
||||
|
||||
local Players = game:GetService('Players')
|
||||
local GuiService = game:GetService('GuiService')
|
||||
|
||||
local TouchJump = {}
|
||||
|
||||
local MasterControl = require(script.Parent)
|
||||
|
||||
--[[ Script Variables ]]--
|
||||
while not Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
local Humanoid = MasterControl:GetHumanoid()
|
||||
local JumpButton = nil
|
||||
local OnInputEnded = nil -- defined in Create()
|
||||
local CharacterAddedConnection = nil
|
||||
local HumStateConnection = nil
|
||||
local HumChangeConnection = nil
|
||||
local ExternallyEnabled = false
|
||||
local JumpPower = 0
|
||||
local JumpStateEnabled = true
|
||||
|
||||
--[[ Constants ]]--
|
||||
local TOUCH_CONTROL_SHEET = "rbxasset://textures/ui/Input/TouchControlsSheetV2.png"
|
||||
|
||||
--[[ Private Functions ]]--
|
||||
|
||||
local function disableButton()
|
||||
JumpButton.Visible = false
|
||||
OnInputEnded()
|
||||
end
|
||||
|
||||
local function enableButton()
|
||||
if Humanoid and ExternallyEnabled then
|
||||
if ExternallyEnabled then
|
||||
if Humanoid.JumpPower > 0 then
|
||||
JumpButton.Visible = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function updateEnabled()
|
||||
if JumpPower > 0 and JumpStateEnabled then
|
||||
enableButton()
|
||||
else
|
||||
disableButton()
|
||||
end
|
||||
end
|
||||
|
||||
local function humanoidChanged(prop)
|
||||
if prop == "JumpPower" then
|
||||
JumpPower = Humanoid.JumpPower
|
||||
updateEnabled()
|
||||
elseif prop == "Parent" then
|
||||
if not Humanoid.Parent then
|
||||
HumChangeConnection:disconnect()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function humandoidStateEnabledChanged(state, isEnabled)
|
||||
if state == Enum.HumanoidStateType.Jumping then
|
||||
JumpStateEnabled = isEnabled
|
||||
updateEnabled()
|
||||
end
|
||||
end
|
||||
|
||||
local function characterAdded(newCharacter)
|
||||
if HumChangeConnection then
|
||||
HumChangeConnection:disconnect()
|
||||
end
|
||||
-- rebind event to new Humanoid
|
||||
Humanoid = nil
|
||||
repeat
|
||||
Humanoid = MasterControl:GetHumanoid()
|
||||
wait()
|
||||
until Humanoid and Humanoid.Parent == newCharacter
|
||||
HumChangeConnection = Humanoid.Changed:connect(humanoidChanged)
|
||||
HumStateConnection = Humanoid.StateEnabledChanged:connect(humandoidStateEnabledChanged)
|
||||
JumpPower = Humanoid.JumpPower
|
||||
JumpStateEnabled = Humanoid:GetStateEnabled(Enum.HumanoidStateType.Jumping)
|
||||
updateEnabled()
|
||||
end
|
||||
|
||||
local function setupCharacterAddedFunction()
|
||||
CharacterAddedConnection = LocalPlayer.CharacterAdded:connect(characterAdded)
|
||||
if LocalPlayer.Character then
|
||||
characterAdded(LocalPlayer.Character)
|
||||
end
|
||||
end
|
||||
|
||||
--[[ Public API ]]--
|
||||
function TouchJump:Enable()
|
||||
ExternallyEnabled = true
|
||||
enableButton()
|
||||
end
|
||||
|
||||
function TouchJump:Disable()
|
||||
ExternallyEnabled = false
|
||||
disableButton()
|
||||
end
|
||||
|
||||
function TouchJump:Create(parentFrame)
|
||||
if JumpButton then
|
||||
JumpButton:Destroy()
|
||||
JumpButton = nil
|
||||
end
|
||||
|
||||
local minAxis = math.min(parentFrame.AbsoluteSize.x, parentFrame.AbsoluteSize.y)
|
||||
local isSmallScreen = minAxis <= 500
|
||||
local jumpButtonSize = isSmallScreen and 70 or 120
|
||||
|
||||
JumpButton = Instance.new('ImageButton')
|
||||
JumpButton.Name = "JumpButton"
|
||||
JumpButton.Visible = false
|
||||
JumpButton.BackgroundTransparency = 1
|
||||
JumpButton.Image = TOUCH_CONTROL_SHEET
|
||||
JumpButton.ImageRectOffset = Vector2.new(1, 146)
|
||||
JumpButton.ImageRectSize = Vector2.new(144, 144)
|
||||
JumpButton.Size = UDim2.new(0, jumpButtonSize, 0, jumpButtonSize)
|
||||
|
||||
JumpButton.Position = isSmallScreen and UDim2.new(1, -(jumpButtonSize*1.5-10), 1, -jumpButtonSize - 20) or
|
||||
UDim2.new(1, -(jumpButtonSize*1.5-10), 1, -jumpButtonSize * 1.75)
|
||||
|
||||
local touchObject = nil
|
||||
JumpButton.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
|
||||
|
||||
touchObject = inputObject
|
||||
JumpButton.ImageRectOffset = Vector2.new(146, 146)
|
||||
MasterControl:SetIsJumping(true)
|
||||
end)
|
||||
|
||||
OnInputEnded = function()
|
||||
touchObject = nil
|
||||
MasterControl:SetIsJumping(false)
|
||||
JumpButton.ImageRectOffset = Vector2.new(1, 146)
|
||||
end
|
||||
|
||||
JumpButton.InputEnded:connect(function(inputObject)
|
||||
if inputObject == touchObject then
|
||||
OnInputEnded()
|
||||
end
|
||||
end)
|
||||
|
||||
GuiService.MenuOpened:connect(function()
|
||||
if touchObject then
|
||||
OnInputEnded()
|
||||
end
|
||||
end)
|
||||
|
||||
if not CharacterAddedConnection then
|
||||
setupCharacterAddedFunction()
|
||||
end
|
||||
|
||||
JumpButton.Parent = parentFrame
|
||||
end
|
||||
|
||||
return TouchJump
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
local VRService = game:GetService("VRService")
|
||||
local UserInputService = game:GetService("UserInputService")
|
||||
local RunService = game:GetService("RunService")
|
||||
local Players = game:GetService("Players")
|
||||
local PathfindingService = game:GetService("PathfindingService")
|
||||
local ContextActionService = game:GetService("ContextActionService")
|
||||
local StarterGui = game:GetService("StarterGui")
|
||||
|
||||
local MasterControl = require(script.Parent)
|
||||
local PathDisplay = nil
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
|
||||
local VRNavigation = {}
|
||||
|
||||
local RECALCULATE_PATH_THRESHOLD = 4
|
||||
local NO_PATH_THRESHOLD = 12
|
||||
local MAX_PATHING_DISTANCE = 200
|
||||
local POINT_REACHED_THRESHOLD = 1
|
||||
local STOPPING_DISTANCE = 4
|
||||
local OFFTRACK_TIME_THRESHOLD = 2
|
||||
|
||||
local ZERO_VECTOR3 = Vector3.new(0, 0, 0)
|
||||
local XZ_VECTOR3 = Vector3.new(1, 0, 1)
|
||||
|
||||
local THUMBSTICK_DEADZONE = 0.22
|
||||
|
||||
local navigationRequestedConn = nil
|
||||
local heartbeatConn = nil
|
||||
|
||||
local currentDestination = nil
|
||||
local currentPath = nil
|
||||
local currentPoints = nil
|
||||
local currentPointIdx = 0
|
||||
local currentMoveVector = Vector3.new(0, 0, 0)
|
||||
|
||||
local expectedTimeToNextPoint = 0
|
||||
local timeReachedLastPoint = tick()
|
||||
|
||||
local movementUpdateEvent = Instance.new("BindableEvent")
|
||||
movementUpdateEvent.Name = "MovementUpdate"
|
||||
movementUpdateEvent.Parent = script
|
||||
|
||||
coroutine.wrap(function()
|
||||
local PathDisplayModule = script.Parent.Parent:WaitForChild("PathDisplay")
|
||||
if PathDisplayModule then
|
||||
PathDisplay = require(PathDisplayModule)
|
||||
end
|
||||
end)()
|
||||
|
||||
local function setLaserPointerMode(mode)
|
||||
pcall(function()
|
||||
StarterGui:SetCore("VRLaserPointerMode", mode)
|
||||
end)
|
||||
end
|
||||
|
||||
local function getLocalHumanoid()
|
||||
local character = LocalPlayer.Character
|
||||
if not character then
|
||||
return
|
||||
end
|
||||
|
||||
for _, child in pairs(character:GetChildren()) do
|
||||
if child:IsA("Humanoid") then
|
||||
return child
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function hasBothHandControllers()
|
||||
return VRService:GetUserCFrameEnabled(Enum.UserCFrame.RightHand) and VRService:GetUserCFrameEnabled(Enum.UserCFrame.LeftHand)
|
||||
end
|
||||
|
||||
local function hasAnyHandControllers()
|
||||
return VRService:GetUserCFrameEnabled(Enum.UserCFrame.RightHand) or VRService:GetUserCFrameEnabled(Enum.UserCFrame.LeftHand)
|
||||
end
|
||||
|
||||
local function isMobileVR()
|
||||
return UserInputService.TouchEnabled
|
||||
end
|
||||
|
||||
local function hasGamepad()
|
||||
return UserInputService.GamepadEnabled
|
||||
end
|
||||
|
||||
local function shouldUseNavigationLaser()
|
||||
--Places where we use the navigation laser:
|
||||
-- mobile VR with any number of hands tracked
|
||||
-- desktop VR with only one hand tracked
|
||||
-- desktop VR with no hands and no gamepad (i.e. with Oculus remote?)
|
||||
--using an Xbox controller with a desktop VR headset means no laser since the user has a thumbstick.
|
||||
--in the future, we should query thumbstick presence with a features API
|
||||
if isMobileVR() then
|
||||
return true
|
||||
else
|
||||
if hasBothHandControllers() then
|
||||
return false
|
||||
end
|
||||
if not hasAnyHandControllers() then
|
||||
return not hasGamepad()
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function IsFinite(num)
|
||||
return num == num and num ~= 1/0 and num ~= -1/0
|
||||
end
|
||||
|
||||
local function IsFiniteVector3(vec3)
|
||||
return IsFinite(vec3.x) and IsFinite(vec3.y) and IsFinite(vec3.z)
|
||||
end
|
||||
|
||||
local moving = false
|
||||
|
||||
local function startFollowingPath(newPath)
|
||||
currentPath = newPath
|
||||
currentPoints = currentPath:GetPointCoordinates()
|
||||
currentPointIdx = 1
|
||||
moving = true
|
||||
|
||||
timeReachedLastPoint = tick()
|
||||
|
||||
local humanoid = getLocalHumanoid()
|
||||
if humanoid and humanoid.Torso and #currentPoints >= 1 then
|
||||
local dist = (currentPoints[1] - humanoid.Torso.Position).magnitude
|
||||
expectedTimeToNextPoint = dist / humanoid.WalkSpeed
|
||||
end
|
||||
|
||||
movementUpdateEvent:Fire("targetPoint", currentDestination)
|
||||
end
|
||||
|
||||
local function goToPoint(point)
|
||||
currentPath = true
|
||||
currentPoints = { point }
|
||||
currentPointIdx = 1
|
||||
moving = true
|
||||
|
||||
local humanoid = getLocalHumanoid()
|
||||
local distance = (humanoid.Torso.Position - point).magnitude
|
||||
local estimatedTimeRemaining = distance / humanoid.WalkSpeed
|
||||
|
||||
timeReachedLastPoint = tick()
|
||||
expectedTimeToNextPoint = estimatedTimeRemaining
|
||||
|
||||
movementUpdateEvent:Fire("targetPoint", point)
|
||||
end
|
||||
|
||||
local function stopFollowingPath()
|
||||
currentPath = nil
|
||||
currentPoints = nil
|
||||
currentPointIdx = 0
|
||||
moving = false
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = ZERO_VECTOR3
|
||||
end
|
||||
|
||||
local function tryComputePath(startPos, destination)
|
||||
local numAttempts = 0
|
||||
local newPath = nil
|
||||
|
||||
while not newPath and numAttempts < 5 do
|
||||
newPath = PathfindingService:ComputeSmoothPathAsync(startPos, destination, MAX_PATHING_DISTANCE)
|
||||
numAttempts = numAttempts + 1
|
||||
|
||||
if newPath.Status == Enum.PathStatus.ClosestNoPath or newPath.Status == Enum.PathStatus.ClosestOutOfRange then
|
||||
newPath = nil
|
||||
break
|
||||
end
|
||||
|
||||
if newPath and newPath.Status == Enum.PathStatus.FailStartNotEmpty then
|
||||
startPos = startPos + (destination - startPos).unit
|
||||
newPath = nil
|
||||
end
|
||||
|
||||
if newPath and newPath.Status == Enum.PathStatus.FailFinishNotEmpty then
|
||||
destination = destination + Vector3.new(0, 1, 0)
|
||||
newPath = nil
|
||||
end
|
||||
end
|
||||
|
||||
return newPath
|
||||
end
|
||||
|
||||
local function onNavigationRequest(destinationCFrame, requestedWith)
|
||||
local destinationPosition = destinationCFrame.p
|
||||
local lastDestination = currentDestination
|
||||
|
||||
if not IsFiniteVector3(destinationPosition) then
|
||||
return
|
||||
end
|
||||
|
||||
currentDestination = destinationPosition
|
||||
|
||||
local humanoid = getLocalHumanoid()
|
||||
if not humanoid or not humanoid.Torso then
|
||||
return
|
||||
end
|
||||
|
||||
local currentPosition = humanoid.Torso.Position
|
||||
local distanceToDestination = (currentDestination - currentPosition).magnitude
|
||||
|
||||
if distanceToDestination < NO_PATH_THRESHOLD then
|
||||
goToPoint(currentDestination)
|
||||
return
|
||||
end
|
||||
|
||||
if not lastDestination or (currentDestination - lastDestination).magnitude > RECALCULATE_PATH_THRESHOLD then
|
||||
local newPath = tryComputePath(currentPosition, currentDestination)
|
||||
if newPath then
|
||||
startFollowingPath(newPath)
|
||||
if PathDisplay then
|
||||
PathDisplay.setCurrentPoints(currentPoints)
|
||||
PathDisplay.renderPath()
|
||||
end
|
||||
else
|
||||
stopFollowingPath()
|
||||
if PathDisplay then
|
||||
PathDisplay.clearRenderedPath()
|
||||
end
|
||||
end
|
||||
else
|
||||
if moving then
|
||||
currentPoints[#currentPoints] = currentDestination
|
||||
else
|
||||
goToPoint(currentDestination)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local isJumpBound = false
|
||||
local function onJumpAction(actionName, inputState, inputObj)
|
||||
if inputState == Enum.UserInputState.Begin then
|
||||
MasterControl:DoJump()
|
||||
end
|
||||
end
|
||||
|
||||
local function bindJumpAction(active)
|
||||
if active then
|
||||
if not isJumpBound then
|
||||
isJumpBound = true
|
||||
ContextActionService:BindAction("VRJumpAction", onJumpAction, false, Enum.KeyCode.ButtonA)
|
||||
end
|
||||
else
|
||||
if isJumpBound then
|
||||
isJumpBound = false
|
||||
ContextActionService:UnbindAction("VRJumpAction")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local moveLatch = false
|
||||
local controlCharacterGamepad = function(actionName, inputState, inputObject)
|
||||
if inputObject.KeyCode ~= Enum.KeyCode.Thumbstick1 then return end
|
||||
|
||||
if inputState == Enum.UserInputState.Cancel then
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
return
|
||||
end
|
||||
|
||||
if inputState ~= Enum.UserInputState.End then
|
||||
stopFollowingPath()
|
||||
if PathDisplay then
|
||||
PathDisplay.clearRenderedPath()
|
||||
end
|
||||
|
||||
if shouldUseNavigationLaser() then
|
||||
bindJumpAction(true)
|
||||
setLaserPointerMode("Hidden")
|
||||
end
|
||||
|
||||
if inputObject.Position.magnitude > THUMBSTICK_DEADZONE then
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(inputObject.Position.X, 0, -inputObject.Position.Y)
|
||||
if currentMoveVector.magnitude > 0 then
|
||||
currentMoveVector = currentMoveVector.unit * math.min(1, inputObject.Position.magnitude)
|
||||
end
|
||||
MasterControl:AddToPlayerMovement(currentMoveVector)
|
||||
|
||||
moveLatch = true
|
||||
end
|
||||
else
|
||||
MasterControl:AddToPlayerMovement(-currentMoveVector)
|
||||
currentMoveVector = Vector3.new(0,0,0)
|
||||
|
||||
if shouldUseNavigationLaser() then
|
||||
bindJumpAction(false)
|
||||
setLaserPointerMode("Navigation")
|
||||
end
|
||||
|
||||
if moveLatch then
|
||||
moveLatch = false
|
||||
movementUpdateEvent:Fire("offtrack")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onHeartbeat(dt)
|
||||
local newMoveVector = currentMoveVector
|
||||
local humanoid = getLocalHumanoid()
|
||||
if not humanoid or not humanoid.Torso then
|
||||
return
|
||||
end
|
||||
|
||||
if moving and currentPoints then
|
||||
local currentPosition = humanoid.Torso.Position
|
||||
local goalPosition = currentPoints[1]
|
||||
local vectorToGoal = (goalPosition - currentPosition) * XZ_VECTOR3
|
||||
local moveDist = vectorToGoal.magnitude
|
||||
local moveDir = vectorToGoal / moveDist
|
||||
|
||||
if moveDist < POINT_REACHED_THRESHOLD then
|
||||
local estimatedTimeRemaining = 0
|
||||
local prevPoint = currentPoints[1]
|
||||
for i, point in pairs(currentPoints) do
|
||||
if i ~= 1 then
|
||||
local dist = (point - prevPoint).magnitude
|
||||
prevPoint = point
|
||||
estimatedTimeRemaining = estimatedTimeRemaining + (dist / humanoid.WalkSpeed)
|
||||
end
|
||||
end
|
||||
|
||||
table.remove(currentPoints, 1)
|
||||
currentPointIdx = currentPointIdx + 1
|
||||
|
||||
if #currentPoints == 0 then
|
||||
stopFollowingPath()
|
||||
if PathDisplay then
|
||||
PathDisplay.clearRenderedPath()
|
||||
end
|
||||
return
|
||||
else
|
||||
if PathDisplay then
|
||||
PathDisplay.setCurrentPoints(currentPoints)
|
||||
PathDisplay.renderPath()
|
||||
end
|
||||
|
||||
local newGoal = currentPoints[1]
|
||||
local distanceToGoal = (newGoal - currentPosition).magnitude
|
||||
expectedTimeToNextPoint = distanceToGoal / humanoid.WalkSpeed
|
||||
timeReachedLastPoint = tick()
|
||||
end
|
||||
else
|
||||
local ignoreTable = {
|
||||
game.Players.LocalPlayer.Character,
|
||||
workspace.CurrentCamera
|
||||
}
|
||||
local obstructRay = Ray.new(currentPosition - Vector3.new(0, 1, 0), moveDir * 3)
|
||||
local obstructPart, obstructPoint, obstructNormal = workspace:FindPartOnRayWithIgnoreList(obstructRay, ignoreTable)
|
||||
|
||||
if obstructPart then
|
||||
local heightOffset = Vector3.new(0, 100, 0)
|
||||
local jumpCheckRay = Ray.new(obstructPoint + moveDir * 0.5 + heightOffset, -heightOffset)
|
||||
local jumpCheckPart, jumpCheckPoint, jumpCheckNormal = workspace:FindPartOnRayWithIgnoreList(jumpCheckRay, ignoreTable)
|
||||
|
||||
local heightDifference = jumpCheckPoint.Y - currentPosition.Y
|
||||
if heightDifference < 6 and heightDifference > -2 then
|
||||
humanoid.Jump = true
|
||||
end
|
||||
end
|
||||
|
||||
local timeSinceLastPoint = tick() - timeReachedLastPoint
|
||||
if timeSinceLastPoint > expectedTimeToNextPoint + OFFTRACK_TIME_THRESHOLD then
|
||||
stopFollowingPath()
|
||||
if PathDisplay then
|
||||
PathDisplay.clearRenderedPath()
|
||||
end
|
||||
|
||||
movementUpdateEvent:Fire("offtrack")
|
||||
end
|
||||
|
||||
newMoveVector = currentMoveVector:Lerp(moveDir, dt * 10)
|
||||
end
|
||||
end
|
||||
|
||||
if IsFiniteVector3(newMoveVector) then
|
||||
MasterControl:AddToPlayerMovement(newMoveVector - currentMoveVector)
|
||||
currentMoveVector = newMoveVector
|
||||
end
|
||||
end
|
||||
|
||||
local userCFrameEnabledConn = nil
|
||||
local function onUserCFrameEnabled()
|
||||
if shouldUseNavigationLaser() then
|
||||
bindJumpAction(false)
|
||||
setLaserPointerMode("Navigation")
|
||||
else
|
||||
bindJumpAction(true)
|
||||
setLaserPointerMode("Hidden")
|
||||
end
|
||||
end
|
||||
|
||||
function VRNavigation:Enable()
|
||||
navigationRequestedConn = VRService.NavigationRequested:connect(onNavigationRequest)
|
||||
heartbeatConn = RunService.Heartbeat:connect(onHeartbeat)
|
||||
|
||||
ContextActionService:BindAction("MoveThumbstick", controlCharacterGamepad, false, Enum.KeyCode.Thumbstick1)
|
||||
ContextActionService:BindActivate(Enum.UserInputType.Gamepad1, Enum.KeyCode.ButtonR2)
|
||||
|
||||
userCFrameEnabledConn = VRService.UserCFrameEnabled:connect(onUserCFrameEnabled)
|
||||
onUserCFrameEnabled()
|
||||
|
||||
pcall(function()
|
||||
VRService:SetTouchpadMode(Enum.VRTouchpad.Left, Enum.VRTouchpadMode.VirtualThumbstick)
|
||||
VRService:SetTouchpadMode(Enum.VRTouchpad.Right, Enum.VRTouchpadMode.ABXY)
|
||||
end)
|
||||
end
|
||||
|
||||
function VRNavigation:Disable()
|
||||
stopFollowingPath()
|
||||
|
||||
ContextActionService:UnbindAction("MoveThumbstick")
|
||||
ContextActionService:UnbindActivate(Enum.UserInputType.Gamepad1, Enum.KeyCode.ButtonR2)
|
||||
|
||||
bindJumpAction(false)
|
||||
setLaserPointerMode("Disabled")
|
||||
|
||||
if navigationRequestedConn then
|
||||
navigationRequestedConn:disconnect()
|
||||
navigationRequestedConn = nil
|
||||
end
|
||||
if heartbeatConn then
|
||||
heartbeatConn:disconnect()
|
||||
heartbeatConn = nil
|
||||
end
|
||||
if userCFrameEnabledConn then
|
||||
userCFrameEnabledConn:disconnect()
|
||||
userCFrameEnabledConn = nil
|
||||
end
|
||||
end
|
||||
|
||||
return VRNavigation
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
--[[
|
||||
// FileName: VehicleControl
|
||||
// Version 1.0
|
||||
// Written by: jmargh
|
||||
// Description: Implements in-game vehicle controls for all input devices
|
||||
|
||||
// NOTE: This works for basic vehicles (single vehicle seat). If you use custom VehicleSeat code,
|
||||
// multiple VehicleSeats or your own implementation of a VehicleSeat this will not work.
|
||||
--]]
|
||||
|
||||
local VehicleController = {}
|
||||
|
||||
local ContextActionService = game:GetService('ContextActionService')
|
||||
local Players = game:GetService('Players')
|
||||
local RunService = game:GetService('RunService')
|
||||
|
||||
local MasterControl = require(script.Parent)
|
||||
|
||||
while not Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
local LocalPlayer = Players.LocalPlayer
|
||||
local CurrentVehicleSeat = nil
|
||||
local CurrentThrottle = 0
|
||||
local CurrentSteer = 0
|
||||
local HumanoidSeatedCn = nil
|
||||
local RenderSteppedCn = nil
|
||||
local Accelerating = false
|
||||
local Deccelerating = false
|
||||
local TurningRight = false
|
||||
local TurningLeft = false
|
||||
-- Set this to true if you want to instead use the triggers for the throttle
|
||||
local useTriggersForThrottle = true
|
||||
-- Also set this to true if you want the thumbstick to not affect throttle, only triggers when a gamepad is conected
|
||||
local onlyTriggersForThrottle = false
|
||||
|
||||
local function onThrottleAccel(actionName, inputState, inputObject)
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(0, 0, -CurrentThrottle))
|
||||
CurrentThrottle = (inputState == Enum.UserInputState.End or Deccelerating) and 0 or -1
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(0, 0, CurrentThrottle))
|
||||
Accelerating = not (inputState == Enum.UserInputState.End)
|
||||
if (inputState == Enum.UserInputState.End) and Deccelerating then
|
||||
CurrentThrottle = 1
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(0, 0, CurrentThrottle))
|
||||
end
|
||||
end
|
||||
|
||||
local function onThrottleDeccel(actionName, inputState, inputObject)
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(0, 0, -CurrentThrottle))
|
||||
CurrentThrottle = (inputState == Enum.UserInputState.End or Accelerating) and 0 or 1
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(0, 0, CurrentThrottle))
|
||||
Deccelerating = not (inputState == Enum.UserInputState.End)
|
||||
if (inputState == Enum.UserInputState.End) and Accelerating then
|
||||
CurrentThrottle = -1
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(0, 0, CurrentThrottle))
|
||||
end
|
||||
end
|
||||
|
||||
local function onSteerRight(actionName, inputState, inputObject)
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(-CurrentSteer, 0, 0))
|
||||
CurrentSteer = (inputState == Enum.UserInputState.End or TurningLeft) and 0 or 1
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(CurrentSteer, 0, 0))
|
||||
TurningRight = not (inputState == Enum.UserInputState.End)
|
||||
if (inputState == Enum.UserInputState.End) and TurningLeft then
|
||||
CurrentSteer = -1
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(CurrentSteer, 0, 0))
|
||||
end
|
||||
end
|
||||
|
||||
local function onSteerLeft(actionName, inputState, inputObject)
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(-CurrentSteer, 0, 0))
|
||||
CurrentSteer = (inputState == Enum.UserInputState.End or TurningRight) and 0 or -1
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(CurrentSteer, 0, 0))
|
||||
TurningLeft = not (inputState == Enum.UserInputState.End)
|
||||
if (inputState == Enum.UserInputState.End) and TurningRight then
|
||||
CurrentSteer = 1
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(CurrentSteer, 0, 0))
|
||||
end
|
||||
end
|
||||
|
||||
local function getHumanoid()
|
||||
local character = LocalPlayer and LocalPlayer.Character
|
||||
if character then
|
||||
for _,child in pairs(character:GetChildren()) do
|
||||
if child:IsA('Humanoid') then
|
||||
return child
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getClosestFittingValue(value)
|
||||
if value > 0.5 then
|
||||
return 1
|
||||
elseif value < -0.5 then
|
||||
return -1
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
local function onRenderStepped()
|
||||
if CurrentVehicleSeat then
|
||||
local moveValue = MasterControl:GetMoveVector()
|
||||
local didSetThrottleSteerFloat = false
|
||||
didSetThrottleSteerFloat = pcall(function()
|
||||
if game:GetService("UserInputService"):GetGamepadConnected(Enum.UserInputType.Gamepad1) and onlyTriggersForThrottle and useTriggersForThrottle then
|
||||
CurrentVehicleSeat.ThrottleFloat = -CurrentThrottle
|
||||
else
|
||||
CurrentVehicleSeat.ThrottleFloat = -moveValue.z
|
||||
end
|
||||
CurrentVehicleSeat.SteerFloat = moveValue.x
|
||||
end)
|
||||
|
||||
if didSetThrottleSteerFloat == false then
|
||||
if game:GetService("UserInputService"):GetGamepadConnected(Enum.UserInputType.Gamepad1) and onlyTriggersForThrottle and useTriggersForThrottle then
|
||||
CurrentVehicleSeat.Throttle = -CurrentThrottle
|
||||
else
|
||||
CurrentVehicleSeat.Throttle = getClosestFittingValue(-moveValue.z)
|
||||
end
|
||||
CurrentVehicleSeat.Steer = getClosestFittingValue(moveValue.x)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function onSeated(active, currentSeatPart)
|
||||
if active then
|
||||
if currentSeatPart and currentSeatPart:IsA('VehicleSeat') then
|
||||
CurrentVehicleSeat = currentSeatPart
|
||||
if useTriggersForThrottle then
|
||||
ContextActionService:BindAction("throttleAccel", onThrottleAccel, false, Enum.KeyCode.ButtonR2)
|
||||
ContextActionService:BindAction("throttleDeccel", onThrottleDeccel, false, Enum.KeyCode.ButtonL2)
|
||||
end
|
||||
ContextActionService:BindAction("arrowSteerRight", onSteerRight, false, Enum.KeyCode.Right)
|
||||
ContextActionService:BindAction("arrowSteerLeft", onSteerLeft, false, Enum.KeyCode.Left)
|
||||
local success = pcall(function() RunService:BindToRenderStep("VehicleControlStep", Enum.RenderPriority.Input.Value, onRenderStepped) end)
|
||||
|
||||
if not success then
|
||||
if RenderSteppedCn then return end
|
||||
RenderSteppedCn = RunService.RenderStepped:connect(onRenderStepped)
|
||||
end
|
||||
end
|
||||
else
|
||||
CurrentVehicleSeat = nil
|
||||
if useTriggersForThrottle then
|
||||
ContextActionService:UnbindAction("throttleAccel")
|
||||
ContextActionService:UnbindAction("throttleDeccel")
|
||||
end
|
||||
ContextActionService:UnbindAction("arrowSteerRight")
|
||||
ContextActionService:UnbindAction("arrowSteerLeft")
|
||||
MasterControl:AddToPlayerMovement(Vector3.new(-CurrentSteer, 0, -CurrentThrottle))
|
||||
CurrentThrottle = 0
|
||||
CurrentSteer = 0
|
||||
local success = pcall(function() RunService:UnbindFromRenderStep("VehicleControlStep") end)
|
||||
if not success and RenderSteppedCn then
|
||||
RenderSteppedCn:disconnect()
|
||||
RenderSteppedCn = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function CharacterAdded(character)
|
||||
local humanoid = getHumanoid()
|
||||
while not humanoid do
|
||||
wait()
|
||||
humanoid = getHumanoid()
|
||||
end
|
||||
--
|
||||
if HumanoidSeatedCn then
|
||||
HumanoidSeatedCn:disconnect()
|
||||
HumanoidSeatedCn = nil
|
||||
end
|
||||
HumanoidSeatedCn = humanoid.Seated:connect(onSeated)
|
||||
end
|
||||
|
||||
if LocalPlayer.Character then
|
||||
CharacterAdded(LocalPlayer.Character)
|
||||
end
|
||||
LocalPlayer.CharacterAdded:connect(CharacterAdded)
|
||||
|
||||
return VehicleController
|
||||
Reference in New Issue
Block a user