I’ve posted about this on DevForum before, but I’m making a game where the player controls a plane. Currently I have both mouse/keyboard and Gamepad support, but I’d like to make the final leap to mobile support to ensure that all Roblox users have the opportunity to play my game.
However, I’m not at all familiar with scripting mobile controls, and I’m unsure as to what the proper method for detecting where the player is touching the screen is. This is my control code so far:
run.Stepped:Connect(function(_currentTime, deltaTime)
if input.GamepadEnabled then
av = Vector3.new(
0,
-(tstick.Position.X),
(tstick.Position.Y)
)
elseif input.TouchEnabled then
-- ??????
else
if input:IsMouseButtonPressed(1) then
av = Vector3.new(
0,
((math.rad(-(mouse.X) + (mouse.ViewSizeX/2)))/2),
((math.rad(-(mouse.Y) + (mouse.ViewSizeY/2)))/2)
)
else
av = Vector3.new(
0,
0,
0
)
end
end
plane.AngularVelocity.AngularVelocity = av
plane.Orientation = Vector3.new(
0,
plane.Orientation.Y,
plane.Orientation.Z
)
camera.CFrame = camera.CFrame:Lerp(plane.Attachment.WorldCFrame,8*deltaTime)
end)
Note how the code gets the mouse position and thumbstick position every frame, so I would simply need to grab the touch position in real time with no need to detect if the player is dragging their finger or not… or would I? Again the question is how I actually approach this in the first place.
Well, to add mobile touch controls to your game for controlling the plane, I believe you can use the UserInputService to detect touch input. The UserInputService provides information about input devices, including touch events on mobile devices.
Here’s an example of how you can modify your code to support touch controls:
local function getTouchPosition()
local touches = game:GetService("UserInputService"):GetTouches()
if #touches > 0 then
-- Assume the player is using the first touch for control
return touches[1].Position
end
return nil
end
run.Stepped:Connect(function(_currentTime, deltaTime)
local av
if input.GamepadEnabled then
av = Vector3.new(
0,
-tstick.Position.X,
tstick.Position.Y
)
elseif input.TouchEnabled then
local touchPosition = getTouchPosition()
if touchPosition then
-- Convert the touch position to a normalized direction for control
local halfWidth = workspace.CurrentCamera.ViewportSize.X / 2
local halfHeight = workspace.CurrentCamera.ViewportSize.Y / 2
local normalizedTouchPos = Vector2.new(
(touchPosition.X - halfWidth) / halfWidth,
(touchPosition.Y - halfHeight) / halfHeight
)
-- Use the normalizedTouchPos to control the plane (adjust the sensitivity as needed)
av = Vector3.new(
0,
math.rad(-normalizedTouchPos.X) * sensitivityFactor,
math.rad(-normalizedTouchPos.Y) * sensitivityFactor
)
else
av = Vector3.new(0, 0, 0) -- No touch, no input
end
else
-- Mouse/keyboard control as before
-- ...
end
-- Rest of your code, K3ology
end)
In this code, I’ve added a new function getTouchPosition() to retrieve the position of the first touch on the screen. If a touch is detected, the position is then converted to a normalized direction vector, which is used to control the plane’s angular velocity. Adjust the sensitivityFactor variable to control how sensitive the touch controls should be. Remember that mobile devices come in various screen sizes, so it’s essential to handle different screen resolutions and aspect ratios appropriately to ensure the touch controls work consistently across devices. The code I provided above assumes a single touch control for simplicity, but you can extend it to support multiple touches if needed for your game.
I added the code you suggested… the parts that worked, at least. GetTouches isn’t actually a valid method of UserInputService.
This is the entire script for clarity (I should’ve posted that before, oops), and while the code I added within the Stepped loop works, the script is unable to detect when the screen isn’t being touched anymore, and continues turning the plane after the fact.
Is there another function I can use to detect when the screen is being touched or not?
local run = game:GetService("RunService")
local input = game:GetService("UserInputService")
local mouse = game:GetService("Players").LocalPlayer:GetMouse()
local camera = workspace.CurrentCamera
local halfWidth = camera.ViewportSize.X / 2
local halfHeight = camera.ViewportSize.Y / 2
local sensitivityFactor = 100
local states = input:GetGamepadState(Enum.UserInputType.Gamepad1)
local statesByKeyCode = {}
for _, state in pairs(states) do
statesByKeyCode[state.KeyCode] = state
end
local tstick = statesByKeyCode[Enum.KeyCode.Thumbstick2]
wait(1)
local plane = workspace:WaitForChild(script.Parent.Parent.Name .. "Plane")
local av = Vector3.new()
camera.CameraType = Enum.CameraType.Scriptable
camera.CameraSubject = plane
camera.FieldOfView = 45
run.Stepped:Connect(function(_currentTime, deltaTime)
local av
if input.GamepadEnabled then
av = Vector3.new(
0,
-tstick.Position.X,
tstick.Position.Y
)
elseif input.TouchEnabled then
local touchPosition = input:GetMouseLocation()
if touchPosition then
local normalizedTouchPos = Vector2.new(
(touchPosition.X - halfWidth) / halfWidth,
(touchPosition.Y - halfHeight) / halfHeight
)
av = Vector3.new(
0,
math.rad(-normalizedTouchPos.X) * sensitivityFactor,
math.rad(-normalizedTouchPos.Y) * sensitivityFactor
)
else
av = Vector3.new(
0,
0,
0)
end
else
if input:IsMouseButtonPressed(1) then
av = Vector3.new(
0,
((math.rad(-(mouse.X) + (mouse.ViewSizeX/2)))/2),
((math.rad(-(mouse.Y) + (mouse.ViewSizeY/2)))/2)
)
else
av = Vector3.new(
0,
0,
0
)
end
end
plane.AngularVelocity.AngularVelocity = av
plane.Orientation = Vector3.new(
0,
plane.Orientation.Y,
plane.Orientation.Z
)
camera.CFrame = camera.CFrame:Lerp(plane.Attachment.WorldCFrame,8*deltaTime)
end)
I’m unable to record a video right now, but if you need more clarification, the mouse controls in the game itself provide a good example of the effect I’m looking for: 🎮Gamepad Support🎮 Plane Device Test - Roblox
Ended up figuring it out for myself after some more experimentation, here’s what I did for anyone who also has this issue:
elseif input.TouchEnabled then
local function onTouchMoved(touch, gameProcessedEvent)
av = Vector3.new(
0,
((math.rad(-(touch.Position.X) + (mouse.ViewSizeX/2)))/2),
((math.rad(-(touch.Position.Y) + (mouse.ViewSizeY/2)))/2)
)
end
input.TouchMoved:Connect(onTouchMoved)
local function onTouchEnded(touch, _gameProcessedEvent)
av = Vector3.new(
0,
0,
0
)
end
input.TouchEnded:Connect(onTouchEnded)
Pretty self-explanatory tbh. Not sure if the gameProcessedEvent is needed as I just copied the variables from the documentation’s reference code but whatever idc