觸屏操控
觸屏操控從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"
:直接點擊可用於旁觀。
遊戲內菜單欄

除了菜單欄底下的觸控按鈕,將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