Touch controls/zh: Difference between revisions
ForgottenCat (talk | contribs) Created page with "JSON文件的根元素必须是一个对象。该对象的属性<code>"touch-buttons"</code>可定义一系列按键的对象。每一个按键对象有以下可调节的性质:" |
ForgottenCat (talk | contribs) Created page with "* 位置和大小 (属性<code>"x"</code>, <code>"y"</code>, <code>"w"</code>, <code>"h"</code>):横/纵坐标和宽/高数据为在单位长度为1000000²的表格上的整数。这些''单位表格''数据会在游戏内依据屏幕大小和纵横比转换为''屏幕表格''数据。这意味着当分辨率改变时一些按键可能会表现得被伸展,但这也使我们对于不同的屏幕纵横比可提供一个合理..." |
||
Line 50: | Line 50: | ||
JSON文件的根元素必须是一个对象。该对象的属性<code>"touch-buttons"</code>可定义一系列按键的对象。每一个按键对象有以下可调节的性质: | JSON文件的根元素必须是一个对象。该对象的属性<code>"touch-buttons"</code>可定义一系列按键的对象。每一个按键对象有以下可调节的性质: | ||
* 位置和大小 (属性<code>"x"</code>, <code>"y"</code>, <code>"w"</code>, <code>"h"</code>):横/纵坐标和宽/高数据为在单位长度为1000000²的表格上的整数。这些''单位表格''数据会在游戏内依据屏幕大小和纵横比转换为''屏幕表格''数据。这意味着当分辨率改变时一些按键可能会表现得被伸展,但这也使我们对于不同的屏幕纵横比可提供一个合理的默认值 | |||
* | * 形状 (属性<code>"shape"</code>):决定显示出来的按键形状。 | ||
* | ** <code>"rect"</code>:方形。 | ||
** <code>"rect"</code> | ** <code>"circle"</code>:圆形。该按键大小会被自动调整,从而使宽度和高度一致。 | ||
** <code>"circle"</code> | * 可见度 (属性<code>"visibilities"</code>):一系列预置的可见度设置可供选择,且仅当所有情况都满足时该按键才会显示。若可见度置空则代表该按键总是显示。预置有以下设置: | ||
* | ** <code>"ingame"</code>:玩家在游戏中,即没有在旁观。 | ||
** <code>"ingame"</code> | ** <code>"extra-menu"</code>, <code>"extra-menu-2"</code>, <code>"extra-menu-3"</code>, <code>"extra-menu-4"</code>, <code>"extra-menu-5"</code>: 给定数字对应的附加菜单处于打开状态。 | ||
** <code>"extra-menu"</code>, <code>"extra-menu-2"</code>, <code>"extra-menu-3"</code>, <code>"extra-menu-4"</code>, <code>"extra-menu-5"</code>: | ** <code>"zoom-allowed"</code>: 该服务器允许缩放。 | ||
** <code>"zoom-allowed"</code>: | ** <code>"vote-active"</code>: 正在进行投票。 | ||
** <code>"vote-active"</code>: | ** <code>"dummy-allowed"</code>: 该服务器允许分身。 | ||
** <code>"dummy-allowed"</code>: | ** <code>"dummy-connected"</code>: 分身已经被连接。 | ||
** <code>"dummy-connected"</code>: | ** <code>"rcon-authed"</code>: 玩家登录了管理员账号。 | ||
** <code>"rcon-authed"</code>: | ** <code>"demo-player"</code>: 正位于录像播放器。 | ||
** <code>"demo-player"</code>: | ** 所有可见度都可以在前面添加<code>-</code>来实现反转。例如:<code>"-ingame"</code>仅在玩家未处于游戏中时满足,即旁观中。 | ||
** | * 行为 (属性<code>"behavior"</code>):一个定义此按键按下/松开时执行的动作的对象,也包括其标签。属性<code>"type"</code>用于区分使用的行为种类。行为种类只能是预设(硬编码的),或者基于通用的控制台指令(类似于绑定)。预设的行为仅在需要时才使用,除此之外所有按键为通用绑定。 | ||
* | ** 预设行为 (属性<code>"type"</code>被设置为<code>"predefined"</code>):属性<code>"id"</code>被设置为一个固定的字符串,以此确认使用的预设行为。以下为可用的预设行为: | ||
** | *** <code>"ingame-menu"</code>: 松开该按钮时直接打开游戏菜单。 | ||
*** <code>"ingame-menu"</code>: | *** <code>"extra-menu"</code>: 附加菜单按钮,切换带有<code>"extra-menu"</code>, <code>"extra-menu-2"</code>, <code>"extra-menu-3"</code>, <code>"extra-menu-4"</code>和<code>"extra-menu-5"</code>可见度的按钮的可见度。按住一段时间后松手则会打开游戏菜单。 | ||
*** <code>"extra-menu"</code>: | **** 给属性<code>"number"</code>定义一个在1至5之间的整数即可对应相应的可见度<code>"extra-menu"</code>, <code>"extra-menu-2"</code>, <code>"extra-menu-3"</code>, <code>"extra-menu-4"</code>, <code>"extra-menu-5"</code>。 | ||
**** | *** <code>"emoticon"</code>: 打开表情选择器(此功能无法通过绑定使用)。 | ||
*** <code>"emoticon"</code>: | *** <code>"spectate"</code>: 打开旁观菜单(此功能无法通过绑定使用)。 | ||
*** <code>"spectate"</code>: | *** <code>"swap-action"</code>:切换当前激活的由直接点击和虚拟摇杆执行的动作(开火和出钩)。 | ||
*** <code>"swap-action"</code> | *** <code>"use-action"</code>:以当前瞄准角度执行激活的动作。 | ||
*** <code>"use-action"</code> | *** <code>"joystick-action"</code>:使用当前激活动作的虚拟摇杆 。 | ||
*** <code>"joystick-action"</code> | *** <code>"joystick-aim"</code>:仅提供瞄准的虚拟摇杆,不会执行其他动作。 | ||
*** <code>"joystick-aim"</code> | *** <code>"joystick-fire"</code>:总是会执行开火的虚拟摇杆。 | ||
*** <code>"joystick-fire"</code> | *** <code>"joystick-hook"</code>: 总是会执行出钩的虚拟摇杆。 | ||
*** <code>"joystick-hook"</code>: | ** 绑定行为(属性<code>"type"</code>设置为<code>"bind"</code>)。带此行为的按键会执行控制台命令,和常规绑定类似。 | ||
** | *** 属性<code>"label"</code>定义一个字符串作为该按键的标签。 | ||
*** | *** 属性<code>"label-type"</code>被定义为一个字符串来决定该按键的标签种类,即属性<code>"label"</code>的处理方法: | ||
*** | **** <code>"plain"</code>: 该标签会被直接使用,不会做出任何改变。 | ||
**** <code>"plain"</code>: | **** <code>"localized"</code>: 标签会被自动翻译。仅在有对应翻译时可用。 | ||
**** <code>"localized"</code>: | **** <code>"icon"</code>: 图标字体被用于该标签。图标必须为UTF-16编码,使用<code>\uXXXX</code>。例如<code>\uf3ce</code>为手机图标,Unicode为<code>f3ce</code>。注意该图标必须在[https://fontawesome.com/search?o=r&m=free Font Awesome Free]可用。 | ||
**** <code>"icon"</code>: | *** 属性<code>"command"</code>被定义为一个可以在控制台运行的指令类型字符串,类似于绑定。例如<code>"+fire"</code>为开火动作。 | ||
*** | ** 绑定切换行为(属性<code>type</code>设置为<code>"bind-toggle"</code>)。带此行为的按键会在两个及以上的指令之间循环触发。 | ||
** | *** 属性<code>"commands"</code>定义了两个及以上的指令,依据先后排列顺序依次触发。每个指令为一个带属性<code>"label"</code>, <code>"label-type"</code>和<code>"command"</code>的对象,与上述绑定行为的定义一致。在该组中必须至少定义两个指令对象。 | ||
*** | |||
<div lang="en" dir="ltr" class="mw-content-ltr"> | <div lang="en" dir="ltr" class="mw-content-ltr"> |
Revision as of 18:48, 31 December 2024
触摸控制从DDNet客户端的18.8版本后已经可用,这也是近期首个发布的DDNet安卓版。早期的安卓版DDNet为9.3.1版本,此版本有一个单独的教程。接下来我们会只考虑18.8以及更新版本的触摸控制。
用户界面可通过触摸控制进行的操作如下:
- 在任意地方触摸可移动光标或进行一次鼠标左键点击。
- 在几乎一个地点按住至少0.5秒可进行一次鼠标右键点击。
- 用两根手指可向上或下滚动可滚动条,例如服务器浏览器和控制台。
- 在安卓上:用(虚拟)返回键当做退出键,可关闭菜单等。
在游戏中的触摸控制可以用配置变量cl_touch_controls
来开启/关闭,此变量在安卓默认为1
,在其他平台则是0
。触摸控制应该在其他支持触摸功能的平台上也能使用,但是此教程主要在安卓上进行的测试。
游戏内触摸控制包含多种在屏幕上的按键。不同按键仅会在特定时候显示,取决于其内容。例如移动键仅会在游玩过程中显示。
默认键位
左,右移动键以及跳跃键的布局类似于⊥
的样子,和WASD控制类似。
对于开火和出钩动作,这里设置了两种模式:
- 直接的点击输入:准星会直接移动至玩家点击屏幕的位置。
- 虚拟摇杆:一个按键会模拟摇杆,可以使准星相对于屏幕中心移动。
在两个模式中,一个按键可用于切换当前启用的动作(开火和出钩)。当虚拟摇杆被按下时,该按键可以直接使用未被启用的动作而不是切换。
直接点击输入模式可以依据在游戏内/旁观中分别调整功能,以此在使用摇杆时避免不必要的点击输入。
旁观时,直接点击输入可用于移动地图,类似于在图片/地图预览器。虚拟摇杆也可用于在旁观时移动地图。
两个独立的按钮可分别用于切换至上一个或下一个武器。
一个汉堡包菜单按钮☰
可用于切换更少使用按键的可见性,包括显示记分板,显示表情选择器,显示旁观菜单,打开队伍和队伍内聊天,投票赞成/反对,和缩放按键。长按汉堡包菜单按钮会打开游戏内菜单。
当分身被连接时,一个用于切换分身和本体的按键会显示。
表情选择器和旁观菜单可被相关按键打开,之后可通过在面板外点击或使用返回键关闭,另外仅当相关按钮被按下时才打开面板这种设置目前而言不可行,至少这种设置对于旁观菜单而言不便利。
键位设置格式
上述提到的默认键位是在一个名为touch_controls.json
的文件中被加载,该文件位于data
目录因此无法被修改。该键位可通过在配置目录中创建一个名为touch_controls.json
来修改。
键位配置文件是一个JSON格式的文本文件。推荐先学习JSON的基本格式来更好的理解以下教程。配置文件必须是一个有效的JSON文件。JSON格式的教程和检查工具可在网络上找到。JSON文件的结构如下。
JSON文件的根元素必须是一个对象。该对象的属性"touch-buttons"
可定义一系列按键的对象。每一个按键对象有以下可调节的性质:
- 位置和大小 (属性
"x"
,"y"
,"w"
,"h"
):横/纵坐标和宽/高数据为在单位长度为1000000²的表格上的整数。这些单位表格数据会在游戏内依据屏幕大小和纵横比转换为屏幕表格数据。这意味着当分辨率改变时一些按键可能会表现得被伸展,但这也使我们对于不同的屏幕纵横比可提供一个合理的默认值 - 形状 (属性
"shape"
):决定显示出来的按键形状。"rect"
:方形。"circle"
:圆形。该按键大小会被自动调整,从而使宽度和高度一致。
- 可见度 (属性
"visibilities"
):一系列预置的可见度设置可供选择,且仅当所有情况都满足时该按键才会显示。若可见度置空则代表该按键总是显示。预置有以下设置:"ingame"
:玩家在游戏中,即没有在旁观。"extra-menu"
,"extra-menu-2"
,"extra-menu-3"
,"extra-menu-4"
,"extra-menu-5"
: 给定数字对应的附加菜单处于打开状态。"zoom-allowed"
: 该服务器允许缩放。"vote-active"
: 正在进行投票。"dummy-allowed"
: 该服务器允许分身。"dummy-connected"
: 分身已经被连接。"rcon-authed"
: 玩家登录了管理员账号。"demo-player"
: 正位于录像播放器。- 所有可见度都可以在前面添加
-
来实现反转。例如:"-ingame"
仅在玩家未处于游戏中时满足,即旁观中。
- 行为 (属性
"behavior"
):一个定义此按键按下/松开时执行的动作的对象,也包括其标签。属性"type"
用于区分使用的行为种类。行为种类只能是预设(硬编码的),或者基于通用的控制台指令(类似于绑定)。预设的行为仅在需要时才使用,除此之外所有按键为通用绑定。- 预设行为 (属性
"type"
被设置为"predefined"
):属性"id"
被设置为一个固定的字符串,以此确认使用的预设行为。以下为可用的预设行为:"ingame-menu"
: 松开该按钮时直接打开游戏菜单。"extra-menu"
: 附加菜单按钮,切换带有"extra-menu"
,"extra-menu-2"
,"extra-menu-3"
,"extra-menu-4"
和"extra-menu-5"
可见度的按钮的可见度。按住一段时间后松手则会打开游戏菜单。- 给属性
"number"
定义一个在1至5之间的整数即可对应相应的可见度"extra-menu"
,"extra-menu-2"
,"extra-menu-3"
,"extra-menu-4"
,"extra-menu-5"
。
- 给属性
"emoticon"
: 打开表情选择器(此功能无法通过绑定使用)。"spectate"
: 打开旁观菜单(此功能无法通过绑定使用)。"swap-action"
:切换当前激活的由直接点击和虚拟摇杆执行的动作(开火和出钩)。"use-action"
:以当前瞄准角度执行激活的动作。"joystick-action"
:使用当前激活动作的虚拟摇杆 。"joystick-aim"
:仅提供瞄准的虚拟摇杆,不会执行其他动作。"joystick-fire"
:总是会执行开火的虚拟摇杆。"joystick-hook"
: 总是会执行出钩的虚拟摇杆。
- 绑定行为(属性
"type"
设置为"bind"
)。带此行为的按键会执行控制台命令,和常规绑定类似。- 属性
"label"
定义一个字符串作为该按键的标签。 - 属性
"label-type"
被定义为一个字符串来决定该按键的标签种类,即属性"label"
的处理方法:"plain"
: 该标签会被直接使用,不会做出任何改变。"localized"
: 标签会被自动翻译。仅在有对应翻译时可用。"icon"
: 图标字体被用于该标签。图标必须为UTF-16编码,使用\uXXXX
。例如\uf3ce
为手机图标,Unicode为f3ce
。注意该图标必须在Font Awesome Free可用。
- 属性
"command"
被定义为一个可以在控制台运行的指令类型字符串,类似于绑定。例如"+fire"
为开火动作。
- 属性
- 绑定切换行为(属性
type
设置为"bind-toggle"
)。带此行为的按键会在两个及以上的指令之间循环触发。- 属性
"commands"
定义了两个及以上的指令,依据先后排列顺序依次触发。每个指令为一个带属性"label"
,"label-type"
和"command"
的对象,与上述绑定行为的定义一致。在该组中必须至少定义两个指令对象。
- 属性
- 预设行为 (属性
The root object additionally has the following attributes:
"direct-touch-ingame"
: specifies the mode of direct touch input while ingame. Possible values:"disabled"
: Direct touch input is not used while ingame. This means a virtual joystick is necessary."action"
: Direct touch input uses the active action (see above)."aim"
: Direct touch input only changes the aiming position without using an action. This means separate buttons for using the actions are necessary."fire"
: Direct touch input always uses fire."hook"
: Direct touch input always uses hook.
"direct-touch-spectate"
: specifies the mode of direct touch input while spectating. Possible values:"disabled"
: Direct touch input is not used while spectating. This means a virtual joystick is necessary."aim"
: Direct touch input is used for spectating.
In addition to the separate on-screen touch controls, a second row is added to the main page of the ingame menu when cl_touch_controls
is enabled for less frequently used functions which are otherwise not usable without a keyboard:
- Buttons to open the local and remote consoles. Opening the local console without the touch controls is useful because error messages would be shown there if the touch controls configuration could not be loaded.
- Button to close the menu, which is more convenient than using the virtual back button if it's not always shown.
- Checkbox for toggling the touch controls editor UI (see below).
Ingame touch controls editor
The user interface to adjust the touch controls is rendered over the main screen of the ingame menu when enabled. For now, the touch controls editor is limited to basic configuration management functions.
- Saving the configuration to the
touch_controls.json
file in the config directory. - Discarding the current changes by reloading the
touch_controls.json
file from the config directory. - Restoring the default configuration by reloading the
touch_controls.json
file from the data directory. - Displaying whether there are unsaved changes.
- Importing and exporting the configuration from and to the clipboard. This is the only way to edit the configuration on newer Android versions, as editing files within apps' storage is not possible anymore.
Furthermore, the global touch controls settings can be adjusted in this UI:
- The direct touch input modes while ingame and spectating (see Touch button configuration format) can be adjusted using dropdown menus.
While the touch controls editor is active, all touch buttons are shown regardless of their visibilities, to better support arranging the buttons.
Adjusting the controls
- Export the touch configuration to the clipboard.
- Save the clipboard to a file so you can more easily edit it. You should also do this to have a backup of your configuration!
- Edit the configuration (see above for details about the format).
- Copy the edited configuration to the clipboard and import it in the client again. If the configuration could not be loaded successfully, check the local console for error messages containing
touch_controls
and fix the configuration accordingly. Use online tools for JSON validation and formatting. - Save the changes in the client when you are done. You can also discard your changes or revert to the default if you messed up.
A more convenient user interface to edit the touch controls directly in the client is planned.
Note: You can also edit the file touch_controls.json
in the config directory directly instead of exporting/importing to/from the clipboard, but this is not supported on Android.
Examples
Example for the overall structure of the touch configuration:
{
"direct-touch-ingame": "action",
"direct-touch-spectate": "aim",
"touch-buttons": [
...
]
}
Example button with "bind"
behavior that echos a message in chat:
{
"x": 500000,
"y": 500000,
"w": 100000,
"h": 100000,
"shape": "rect",
"visibilities": [
],
"behavior": {
"type": "bind",
"label": "Example",
"label-type": "plain",
"command": "echo Hello world!"
}
}
Example button with "predefined"
behavior for a virtual joystick that uses the active action:
{
"x": 755000,
"y": 580000,
"w": 225000,
"h": 400000,
"shape": "circle",
"visibilities": [
"ingame"
],
"behavior": {
"type": "predefined",
"id": "joystick-action"
}
}
Example button with "bind-toggle"
behavior that switches between echoing three different messages in chat:
{
"x": 600000,
"y": 200000,
"w": 100000,
"h": 100000,
"shape": "rect",
"visibilities": [
],
"behavior": {
"type": "bind-toggle",
"commands": [
{
"label": "Echo 1",
"label-type": "plain",
"command": "echo 1"
},
{
"label": "Echo 2",
"label-type": "plain",
"command": "echo 2"
},
{
"label": "Echo 3",
"label-type": "plain",
"command": "echo 3"
}
]
}
}
Known issues
- Problem on Android: Pressing down 3 or more fingers at the same times causes all fingers to be released immediately.
- Solution: This is caused by features of your phone that handle global gestures with multiple fingers. Open the Settings app and disable gesture features that involve 3 or more fingers (search for "3 fingers"). In particular, disable the "Swipe down with 3 fingers to take screenshot", "Touch and hold with 3 fingers to take screenshot" and "Swipe up with 3 fingers to enter Split View" features.
- Problem on Android: Rarely, touching in the top around 15% of the screen does not work at all or very inconsistently.
- Solution: It is unclear what causes this. It should be fixed by restarting the app. Going back to the home screen may also fix it.
Implementation details
These are details about the implementation of the touch controls intended for developers.
The ingame touch controls are implemented in a separate client component CTouchControls
in the files src/game/client/components/touch_controls.cpp
and src/game/client/components/touch_controls.h
. Whenever possible, binds are used directly as button behavior instead of using predefined behavior to reduce complexity.
When adding your own button behavior in a forked client it is recommended to prefix names of new shape, visibility, behavior etc. with the name of your fork, e.g. myfork.octagon
if you add a new shape for octogonal buttons, to prevent conflicts in future versions.
To add touch support for other ingame client components like the emoticon wheel and spectator menu, use the CUi::UpdateTouchState
function like for the emoticon wheel and spectator menu. Ensure that your component handles KEY_ESCAPE
to close itself, which also corresponds to the Back-button on Android. Note that only one component may use the touch state in each frame, so it is not possible to hold an ingame touch button and use another component like the emoticon wheel at the same time with other fingers. Instead, the respective predefined touch button behavior (e.g. CSpectateTouchButtonBehavior
) only activates the ingame component (e.g. the spectator menu) in its OnDeactivate
function but does not deactivate it again. Activating the component in the OnActivate
function already would cause the finger that activated the button to also affect the activated component.
References
- Default touch button configuration: https://github.com/ddnet/ddnet/blob/84b1c3c49c8d97a6911da34424d2023879ccdaf8/data/touch_controls.json
- Pull Request adding Touch controls to engine and UI: https://github.com/ddnet/ddnet/pull/8621
- Pull Request adding Ingame touch controls: https://github.com/ddnet/ddnet/pull/8632
- Pull Request adding Emoticon and Spectate touch controls: https://github.com/ddnet/ddnet/pull/8801