触屏操控
触屏操控从DDNet 18.8版本客户端开始启用,这也标志着最近期的首个DDNet安卓版发布。早期的安卓版本为DDNet 9.3.1,该版本已有一个单独教程。以下教程将只考虑18.8以后版本的触屏操控。
在用户界面可以进行的触屏操控如下:
- 直接点击屏幕某位置:视为移动光标至该位置并用左键单击;
- 长按屏幕某位置至少0.5秒:视为用鼠标右键单击该位置,轻微移动手指不影响判定;
- 用两根手指长按屏幕并上下滑动:视为在该位置滚动鼠标滚轮,可以上下滚动列表如服务器浏览器和控制台;
- 在安卓设备上触发了(虚拟)返回键:视为使用了Esc键,可关闭菜单等。
在游戏界面内的触屏操控可以通过配置参数cl_touch_controls
来开启/关闭,此参数在安卓设备上默认为1
,在其他平台则是0
。触屏操控在其他支持触控的平台上应该也能正常使用,但此教程主要针对安卓设备进行测试。
游戏内触屏操控包含许多屏幕按钮。不同按钮根据功能不同仅会在可用时显示,例如移动键仅会在进行游玩时显示。
默认触控按键配置

左、右移动和跳跃键的位置分布形如⊥
,和键盘上的WASD分布类似。
关于开火和出钩的操作,游戏内默认提供了两种操作方式:
- 通过直接点击屏幕空白处,可以将准星直接移动到点击处并立即朝准星处开火或出钩,此时不松手拖动可以控制瞄准角度或不松钩;
- 通过拖动虚拟摇杆按钮,可以将准星以玩家位置为原点朝拖动方向移动,同时开火或出钩。
在两种操作方式下都可以点击右上角的“当前”功能按钮切换为开火或出钩模式。当按住虚拟摇杆时,“当前”按钮将变成直接触发另一功能的按钮,按钮上的文字提示也会相应改变。
对于游戏或旁观时,可以分别设置直接点击屏幕的功能,通过禁用“直接触摸操作”可以避免游戏中使用摇杆的同时点击误触。
旁观模式下,如果将直接触屏操控设置为瞄准,则可以类似图片一样拖动地图进行观察;如果设置为禁用,则只能在摇杆范围内拖动。
默认情况下左上角有两个按钮用于切换上一武器和下一武器。

左上角的☰
字形按钮是游戏内菜单按钮,可用于显示或隐藏更多按钮,这些按钮大部分与游戏操作无关。包括显示计分板、表情轮盘、旁观列表、全局聊天、队伍内聊天的按钮,以及投票按钮和视野缩放按钮。长按菜单按钮松手时会打开类似于电脑按下 Esc 后的游戏内菜单,当然安卓设备也可以使用返回键代替。
连接分身后,右上角会出现切换分身的按钮。
显示更多按钮时,可以打开表情轮盘或旁观列表等菜单,点击表情发送或点击旁观对象观察,点击空白处则可以关闭菜单,安卓设备可以使用返回键关闭。但是目前还无法实现长按按钮时显示菜单、松手自动关闭的功能,并且也不适合用于旁观列表。
自定义触控键位设置
默认键位保存在touch_controls.json
文件中,安卓版本下该文件位于data
目录,高版本安卓设备一般会禁止用户修改这一目录下的文件。因此如果您要进行键位自定义,需要通过在配置目录中创建同名为touch_controls.json
的文件,利用更高的优先度来覆盖默认设置。
键位配置文件是JSON格式的文本文件,推荐在掌握一定JSON基础的情况下阅读下方教程,在配置JSON文件时必须保证有效性。关于JSON格式的相关教程和工具可在网络上找到,下面也会涉及到许多相关术语,当然也可以将游戏配置文件当作练习对象来学习JSON,但是建议在进行实操前先做好重要文件的备份。本教程涉及的JSON配置文件的结构如下:
JSON文件的根元素必须是一个对象。该对象的属性"touch-buttons"
可定义一系列按钮对象。按钮对象都可调节下列属性:
- 位置和大小(属性
"x"
,"y"
,"w"
,"h"
):屏幕显示区域将被平均划分为1000000x1000000的网格,前面提到的四个属性为整数,大小分别表示按钮的中心点横纵坐标和宽度高度。网格的实际单位长度会根据游戏窗口大小及屏幕比例实时拉伸,因此对于不同的屏幕设备,只要屏幕纵横比差异不大,按钮布局就不会变得特别不合理。 - 形状 (属性
"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
。注意该图标必须来自于DDNet或在Font Awesome Free上可用。
- 属性
"command"
指定为可以在控制台执行的命令的字符串,与绑定类似。例如"+fire"
为按钮添加开火动作。
- 属性
- 绑定切换行为(属性
type
设置为"bind-toggle"
)。此行为类型的按钮会循环触发两个或更多的命令。- 属性
"commands"
指定为两个及以上的指令列表,依据排列的先后顺序依次触发和显示。单个指令为一个拥有属性"label"
、"label-type"
和"command"
的对象,与上述绑定行为的定义基本一致,但是在指令列表中必须至少有两个指令对象。
- 属性
- 预设行为(属性
除此之外,根对象还有以下属性:
"direct-touch-ingame"
:定义游戏内点击屏幕空白处时做出的动作。可用的值有:"disabled"
:点击屏幕空白部分不会做出任何动作。这也意味着你需要使用虚拟摇杆。"action"
:点击屏幕空白部分会使用当前激活的动作(见上)。"aim"
:点击屏幕空白部分仅会改变瞄准角度。这意味着你需要另一个按键来执行必要的动作。"fire"
:点击屏幕空白部分会改变瞄准角度并开火。"hook"
:点击屏幕空白部分会改变瞄准角度并出钩。
"direct-touch-spectate"
:定义旁观时点击屏幕空白部分时做出的行为。可用的值有:"disabled"
:点击屏幕空白部分不会做出任何动作。这也意味着你需要使用虚拟摇杆。"aim"
:在屏幕空白部分滑动可以旁观。
"background-color-inactive"
(在DDNet 19.0加入):定义未激活按钮的背景颜色。颜色的格式相关细节见下。"background-color-active"
(在DDNet 19.0加入):定义激活按钮的背景颜色。颜色的格式相关细节见下。
颜色格式
颜色的格式是类似于RRGGBBAA
,RRGGBB
,RGBA
和 RGB
的十六进制字符串,且没有像#
一类的前缀,例如:"A526C440"
。若没有alpha(透明度)的值,则默认为完全不透明。
游戏菜单栏

除了菜单栏底下的触控按钮,将cl_touch_controls
设置为 1 (推荐值)后,在菜单栏下方第二行还会出现一些不常用但重要又需要键盘才能使用的功能:
- 打开本地和远程控制台的按钮:当绑定控制台开关的触控按键失效时,仍可以快捷查看显示在控制台的错误信息;
- 菜单关闭按钮:在不方便使用返回键时更便于关闭菜单。
- 键位编辑器开关(详情见下方)。
触控编辑器

触控编辑器在被启用后会在游戏菜单栏的主屏幕上显示,目前只有如下有限的触控设置管理功能:
- 保存更改:将当前触控设置保存到配置目录下的
touch_controls.json
文件中; - 放弃更改:撤销当前对触控设置的改变,并重新加载配置目录下的
touch_controls.json
文件; - 恢复默认设置:从数据目录中加载
touch_controls.json
文件来将键位初始化; - 右上角留白用于提醒当前是否有设置未被保存;
- 从剪贴板导入设置,或将设置导出至剪贴板。在较新的安卓版本中应用数据无法直接修改,因此导入写好的设置文件是修改键位的唯一方法。
另外,对屏幕空白处进行操作的模式也可以在该界面被修改:
- “直接触摸操作”下拉菜单调整的正是上方提及的游戏模式参数
direct-touch-ingame
和旁观模式参数direct-touch-spectate
(参见上方,自定义触控键位设置)。
当触控编辑器打开时,所有按钮无视可见性属性并全部显示,从而让玩家更易观察和调整按键位置。
键位调整
- 导出当前键位至剪贴板。
- 将剪贴板内容保存为文件便于进行修改。请记得给您的键位设置留下备份!
- 修改键位设置(相关格式细节请参见上方)。
- 复制编辑好的内容至剪贴板,然后导入到客户端。若导入失败,在本地控制台内找到包含
touch_controls
的错误消息,据此更正错误。可以用在线工具帮助更正JSON文本的错误和格式。 - 修改完成后记得在客户端中保存您的设置。如果出现问题,您也可以选择撤销更改或者初始化键位。
目前正计划开发一个可在客户端内直接修改键位的便捷界面。
注意:如果没有安卓系统限制,您也可以直接更改配置目录中的touch_controls.json
文件来修改键位,而不用反复导出导入剪贴板。
示例
全局键位格式设置的示例:
{
"direct-touch-ingame": "action",
"direct-touch-spectate": "aim",
"background-color-inactive": "00000040",
"background-color-active": "33333340",
"touch-buttons": [
...
]
}
示例:带有"bind"
行为的按钮,会在对话框返回一条消息:
{
"x": 500000,
"y": 500000,
"w": 100000,
"h": 100000,
"shape": "rect",
"visibilities": [
],
"behavior": {
"type": "bind",
"label": "Example",
"label-type": "plain",
"command": "echo Hello world!"
}
}
示例:带有"predefined"
行为的按钮,表现为一个会执行当前被激活的行为的虚拟摇杆:
{
"x": 755000,
"y": 580000,
"w": 225000,
"h": 400000,
"shape": "circle",
"visibilities": [
"ingame"
],
"behavior": {
"type": "predefined",
"id": "joystick-action"
}
}
示例:带有"bind-toggle"
行为的按钮,会在对话框循环返回三条不同的消息:
{
"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"
}
]
}
}
一些已知的问题
- 安卓的问题:同时按下三根手指会导致所有手指被立即同时松开。
- 解决方法:原因是你手机自带的全局多指手势动作(设置里面搜"三指")。具体地,关闭"三指下滑截屏","三指长按截屏","三指上滑进入菜单"功能。
- 安卓的问题:有时候点击屏幕顶端15%位置会无响应或响应不连续。
- 解决方法:目前不清楚原因。一般可以重启应用,返回手机主界面也可能可以修复该问题。
实现细则
下面是开发者须知的触屏操控的实现细则:
游戏内触屏操控由单独的客户端组件CTouchControls
实现,该组件位于src/game/client/components/touch_controls.cpp
和src/game/client/components/touch_concontrol.h
文件中。如果一些按钮的功能可以直接通过绑定实现,尽量不要增加预设行为让代码变复杂。
当您想在分叉客户端中添加自己的按键行为时,建议在新增的形状、可见性和行为等等之前加上您的分叉的名称。例如:用 您的分叉.octagon
来表示您添加的八边形按键,预防与未来的版本更新发生冲突。
为其他的游戏内客户端组件例如表情轮盘和旁观菜单添加触屏操控支持时,请使用CUi::UpdateTouchState
这一触摸状态监测函数。
确保您的组件能在接收到KEY_ESCAPE
信号时立即关闭,即安卓上的返回键。
注意在每一游戏帧中,只能有一个组件可以响应触摸状态,因此在占用游戏内触控组件的同时无法使用另一个组件的内容,例如按住一个游戏内按钮就无法使用表情轮盘。
然而,按钮的预设行为(例如CSpectateTouchButtonBehavior
)在调用OnDeactivate
函数打开游戏内的组件(例如旁观菜单)之后不会禁用它,此时手指按下会同时影响按钮和它打开的组件。
参考资料
- 默认键位:https://github.com/ddnet/ddnet/blob/69c92a79e6bab9f9390245f518c5340222c544dc/data/touch_controls.json
- 添加触摸操控至引擎和界面的拉取请求:https://github.com/ddnet/ddnet/pull/8621
- 添加游戏内触摸操控的拉取请求:https://github.com/ddnet/ddnet/pull/8632
- 添加表情和旁观相关的拉取请求:https://github.com/ddnet/ddnet/pull/8801