Release Notes for 661

Let’s say we want to show controller input buttons, like for a tutorial.

We can’t even detect what type of controller they’re using. We can’t show playstation vs Xbox buttons.

I see you and @MetaVars in almost every patch note denying our access to this without giving a proper reason. Well I’m fed up with it. Give us a reason, and a very good one, not the “Ui scaling” one you give.

3 Likes

GetImageForKeycode exists, supporting that in a forwards-compatible way: https://create.roblox.com/docs/reference/engine/classes/UserInputService#GetImageForKeyCode

12 Likes

I gave a number of reasons, e.g.:

  • Mixed input devices like Steam Deck or Ally don’t work
  • Using a tablet as a monitor with keyboard and mouse doesn’t work
  • Chromebook and Windows Surface don’t work
  • VR doesn’t work

Please don’t make assumptions based on TouchEnabled, MouseEnabled etc. APIs.
We will replace them with a better API in the future and provide you with input and output capabilities.

15 Likes

you very much can; at least between xbox and PS. here’s code we use to have custom images per-console:

local function IsXbox()
	return UserInputService:GetStringForKeyCode(Enum.KeyCode.ButtonA) == "ButtonA"
end

function ConsoleKeyImageHandler.GetImage(KeyCode: EnumItem): string?
	local Platform = IsXbox() and "Xbox" or "PlayStation"

	return BUTTON_IMAGES[Platform][KeyCode]
end
3 Likes

That could be arguable.
You’re right a lot of people a making ui based on screen size which will not change.

A couple of things that could be useful to have imo that the roblox could handle something like the last input type and give the ability to see the change of the platform (could be useful for mechanics e.g. when to include aim assist).

And as well roblox ui i think already does something like that (changing the jump button size depending on a device)

2 Likes

Here are the updated instances.

Plugin
PluginCapabilities
PluginManager
PluginMouse
PluginToolbar
PluginToolbarButton
StandalonePluginScripts
2 Likes

Apologies if this has already been mentioned elsewhere, but TouchGui is sometimes there and sometimes isn’t for certain players in-game. I believe the TouchGui being there is dependent upon the TouchEnabled. Clarification would be nice if that’s not the case. I put pcalls in my game for enabling/disabling the TouchGui or the JumpButton specifically.

To clarify, I think I’m talking about a different topic here. I hear you saying to not assume the platform based on inputType. Kinda similar, but the quote made me think to ask.

1 Like

Why do some changes stay pending for so long compared to others? There’s still some changes all the way back in #649 (or earlier) that still are pending

2 Likes

UI wise? This makes sense. Though in the future, Roblox should let developers create experiences only aimed at certain groups of users, like users with higher-end hardware with better software, so they can make games without worrying about low-end users, expanding the Engine’s potential.

1 Like

You would want to do this based on specs (or some other thing that relates to what you actually want to do for higher end users), not based off device. The newest iPhone is going to be more powerful than the worst Windows.

3 Likes

That is true, though I think this would still require an API of some sort that doesn’t give the developer direct access to that info, but still allows the developer to use the full/a great portion of that device’s capabilities.

1 Like

I think an API that returns the user’s device type (i.e. PC, Xbox, etc.) would be awesome.

2 Likes

Get ready for 666 everybody!! Watch out for Devilblox!

exception while signaling: Debugger can be attached to a script or module script

:thinking:


Finally, I won’t have to do local plugin: Plugin = plugin anymore, autocomplete works properly.

1 Like

Everyone has been asking for this for years, but we never got it.
This is what I did (requires FastSignal - A consistent signal library):

--< Services >--

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

--< Assets >--

local Modules = ReplicatedStorage.Modules
local Components = Modules.Components

--< Components >--

local Signal = require(Components.FastSignal)

--< Constants >--

local COMPUTER_INPUTS = {
	Enum.UserInputType.MouseButton1,
	Enum.UserInputType.MouseButton2,
	Enum.UserInputType.MouseButton3,
	Enum.UserInputType.MouseWheel,
	Enum.UserInputType.MouseMovement,
	
	Enum.UserInputType.Keyboard
}

local GAMEPAD_INPUTS = {
	Enum.UserInputType.Gamepad1,
	Enum.UserInputType.Gamepad2,
	Enum.UserInputType.Gamepad3,
	Enum.UserInputType.Gamepad4,
	Enum.UserInputType.Gamepad5,
	Enum.UserInputType.Gamepad6,
	Enum.UserInputType.Gamepad7,
	Enum.UserInputType.Gamepad8
}

local TOUCH_INPUTS = {
	Enum.UserInputType.Touch,
	Enum.UserInputType.Gyro,
	Enum.UserInputType.Accelerometer
} 

--< Controller >--

local Controller = {}

Controller.Computer = false :: boolean
Controller.ComputerChanged = Signal.new() :: Signal.ScriptSignal<boolean>

Controller.Console = false :: boolean
Controller.ConsoleChanged = Signal.new() :: Signal.ScriptSignal<boolean>

Controller.Mobile = false :: boolean
Controller.MobileChanged = Signal.new() :: Signal.ScriptSignal<boolean>

function Controller.Start()
	UserInputService.LastInputTypeChanged:Connect(Controller.LastInputTypeChanged)
	Controller.LastInputTypeChanged(UserInputService:GetLastInputType())
	UserInputService.InputChanged:Connect(function(Input)
		Controller.LastInputTypeChanged(Input.UserInputType)
	end)
	UserInputService.InputBegan:Connect(function(Input)
		Controller.LastInputTypeChanged(Input.UserInputType)
	end)
	UserInputService.InputEnded:Connect(function(Input)
		Controller.LastInputTypeChanged(Input.UserInputType)
	end)
end

function Controller.LastInputTypeChanged(Input: Enum.UserInputType)
	local OnComputer = table.find(COMPUTER_INPUTS, Input) ~= nil
	local OnConsole = table.find(GAMEPAD_INPUTS, Input) ~= nil
	local OnMobile =
		table.find(TOUCH_INPUTS, Input) ~= nil
		and UserInputService.TouchEnabled
		and not OnComputer
		and not OnConsole
	
	if Controller.Computer ~= OnComputer then
		Controller.Computer = OnComputer
	end
	Controller.ComputerChanged:Fire(OnComputer)
	if Controller.Console ~= OnConsole then
		Controller.Console = OnConsole
	end
	Controller.ConsoleChanged:Fire(OnConsole)
	if Controller.Mobile ~= OnMobile then
		Controller.Mobile = OnMobile
	end
	Controller.MobileChanged:Fire(OnMobile)
end

return Controller
3 Likes

Yeah, it’s a really hacky implementation. I wish there was a built-in API, but I guess this will suffice for now.

Changes in older release notes don’t get retroactively updated, it’s always been a thing.

c.c. @realYumiYumee @ramdoys @Velover3454 @AMisspelledUsernaem

You should avoid doing this. Read my post above:

Here’s the gist & some extra info too:
Design and implement your UI to update/function correctly based on the capabilities of the device, don’t try to classify what kind of device it is because that will lead to you making false assumptions about what the device is and how you should respond, you are inherently forcing yourself to ignore most of the actual device capabilities by trying to abstract it.

Best practices for UI design for device compatibility:

  • Use offset units for size more, & calculate a scale factor based on the screen size to pass to a UIScale. This will result in a better experience on mobile because mobile devices use a virtual resolution that Roblox respects. This means that while a particular phone may be 4k, it might use a virtual resolution that is much lower to mimic a phone of the same size with a much lower resolution.
  • Anchor UIs to the sides/center of the screen with scale units & AnchorPoint or UILIstLayouts and use UIPadding to add margins. This will help with scaling if you implement it, because an element is always scaled around the AnchorPoint. This will keep your UI looking consistent, things that should be on the left will be on the left, and things that should be on the right will be on the right.

Best practices for input design for device compatibility:

  • Don’t conditionally listen to inputs based on device capabilities or what you think the device is because these events will only fire if the device has that capability anyway. In other words, always listen to the input events for the devices you are looking to support.
  • Don’t build completely different UIs for completely different devices, and don’t make completely separate input implementations for different devices. Update the UI accordingly. This is what libraries like Fusion or React allow you to do with ease with their state management.
  • In cases where you intend to drastically change the input scheme for ergonomics, change to the scheme based on the input method the user is actually using via UserInputService:GetLastInputType(). Don’t assume you know what the user’s device is based on its capabilities, because most of the capabilities on UserInputService can be held by all devices.
  • Likewise, the same should be done when you’re trying to update imagery or indicators, you should do this based on the last input method used.

Generally, having UI state management like Fusion or React to make your UIs update dynamically, unify your codebase, and create re-usable UI will drastically improve your life when you’re working with UI because it allows you to do pretty much all of the above without a lot of hassle at all.

5 Likes

Oh i’m already using React, i didnt know that UserInputService.GetLastInputType existed :sweat_smile: .
Thanks for telling.

I mean really the best solution is proper device identification by Roblox. We still have to rely on assumptions about device features to guess on if a user is on mobile or a laptop or just has a very small screen. Like you said, assuming that having TouchEnabled means mobile just doesn’t represent what the large portion of devs are using it for.

There is genuine positive outcomes for having something that lets us know the kind of device a user is on so that we can properly adapt the game to fit their device. But, it doesn’t help that tech is constantly being innovated on, pushing the limits of what truly can be called a “tablet” versus a “laptop”. I still think a fairly robust system can help devs better determine when to add things like touch controls and UI scale.