觸屏操控
觸屏操控從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"
):橫/縱坐標和寬/高數據為在單位長度為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"
的對象,與上述綁定行為的定義一致。在該組中必須至少定義兩個指令對象。
- 屬性
- 預設行為 (屬性
除此之外,根對象還有以下屬性:
"direct-touch-ingame"
: 定義在遊戲中直接點擊所執行的動作。可用的值有:"disabled"
:遊戲中直接點擊不會執行任何動作。這意味著需要使用虛擬搖杆。"action"
:直接點擊會使用當前被激活的動作(見上)。"aim"
:直接點擊僅會改變瞄準角度,不會執行其他動作。這意味著你需要其他按鈕來開火或出鉤。"fire"
:直接點擊總是會開火。"hook"
:直接點擊總是會出鉤。
"direct-touch-spectate"
:定義在旁觀時直接點擊所執行的動作。可用的值有:"disabled"
:旁觀時直接點擊不會執行任何動作。這意味著需要使用虛擬搖杆。"aim"
:直接點擊可用於旁觀。
遊戲內菜單欄

除了菜單欄底下的觸控按鈕,將cl_touch_controls
設置為 1 (推薦值)後,在菜單欄下方第二行還會出現一些不常用但重要又需要鍵盤才能使用的功能:
- 打開本地和遠程控制台的按鈕:當綁定控制台開關的觸控按鍵失效時,仍可以快捷查看顯示在控制台的錯誤信息;
- 菜單關閉按鈕:在不方便使用返回鍵時更便於關閉菜單。
- 鍵位編輯器開關(詳情見下方)。
鍵位編輯器

鍵位編輯器在被啟用時會顯示在遊戲內菜單的主屏幕上。該編輯器目前只有最基本的鍵位編輯功能。
- 保存當前設置至配置目錄中的
touch_controls.json
文件。 - 取消當前設置,並加載配置目錄中的
touch_controls.json
文件。 - 加載數據目錄中的
touch_controls.json
文件從而將鍵位初始化。 - 用於提醒當前設置未被保存。
- 從剪貼板導入設置,或將設置導出至剪貼板。在較新的安卓版本中這是修改鍵位的唯一方法,因為無法直接修改應用的數據。
同時,全局的觸摸控制也可以在該界面被修改:
- 遊戲中和旁觀時的直接點擊輸入(見鍵位設置格式)可以用下拉菜單調整。
當鍵位編輯器被打開時,所有按鍵都會無條件顯示,從而讓玩家更好地排列按鍵。
鍵位調整
- 導出當前鍵位至剪貼板。
- 將剪貼板內容粘貼至一個文件來修改它。同時你也應該給你的鍵位設置備份!
- 修改鍵位設置(關於相關格式見上)。
- 複製所有內容至剪貼板,然後在客戶端內導入。若導入失敗,在本地控制台內找到包含
touch_controls
的錯誤消息,並更正錯誤。用在線工具可更正JSON文本的錯誤和格式化。 - 更改完成後在客戶端中保存你的設置。你也可撤銷更改或者初始化鍵位如果你搞砸了。
一個可在客戶端內直接修改鍵位的界面在計劃中。
註:你也可直接更改配置目錄中的touch_controls.json
文件來修改鍵位,而不是導出/導入到剪貼板,但在安卓該做法不可行。
示例
全局鍵位格式設置的示例:
{
"direct-touch-ingame": "action",
"direct-touch-spectate": "aim",
"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
文件中。儘量直接使用綁定作為按鈕的行為而不是預定義行為,從而降低複雜度。
在分叉客戶端中加入你自己的按鍵行為時,建議在新形狀,可見性,行為等前加上你的分叉的名稱。例如:myfork.octagon
如果你添加一個八邊形的按鍵,從而避免和未來的版本發生衝突。
為其他的客戶端組件例如表情輪盤和旁觀菜單添加觸摸控制支持時,使用CUi::UpdateTouchState
函數。確保你的組件會在接收KEY_ESCAPE
時自動關閉,即安卓上的返回鍵。注意在每一幀中,只有一個組件可以使用觸摸狀態,因此按住一個遊戲按鍵時同時用另一個手指使用另一個組件例如表情輪盤是不可能的。相反,相應的預定義按鈕觸摸行為(例如CSpectateTouchButtonBehavior
)僅會觸發遊戲內的組件(例如旁觀菜單),但是不會將其再次停用。激活OnActivate
函數中的組件已經會導致激活按鈕的手指同時會影響激活的組件。
參考資料
- 默認的鍵位文件:https://github.com/ddnet/ddnet/blob/84b1c3c49c8d97a6911da34424d2023879ccdaf8/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