HayBox 是數位或混合式類比/數位控制器的模組化跨平台固件,主要針對 B0XX 型控制器。
特點包括:
如果您只想使用具有預設引腳映射和配置的預先建置韌體,請參閱預先建置二進位檔案部分。如果您想對程式碼進行任何更改,請參閱從原始程式碼建置部分。
.uf2
檔案),只需將其插入 PC 時將其置於 bootsel 模式,然後將.uf2
檔案拖放到出現的 RPI-RP2 磁碟機上.hex
檔案),您可以使用 QMK Toolbox 等程式將.hex
檔案刷入其中目前HayBox的建置主要有以下三種方式:
GitHub Actions 和 GitHub Codespaces 都要求您建立 GitHub 帳戶,但不要求您在本機上安裝任何依賴項。
在本地建置時需要以下依賴:
安裝所有要求後,下載並提取最新的 HayBox 版本,或者如果安裝了 git,則複製儲存庫(這使您可以更輕鬆地提取更新)。
在那之後:
git config --global core.longpaths true
(在 VS Code 或常規 cmd/PowerShell 中都可以)config/<environment>/config.cpp
)。您的控制器沒有的任何按鈕都可以從清單中刪除。HayBox/.pio/build/<environment>/firmware.uf2
拖曳到RPI 上-出現的RP2磁碟機。這可能是修改和重建 HayBox 最方便的方法,但請記住,GitHub 的免費套餐對您每月可以使用 Codespaces 的數量設定了一些限制。因此,您需要確保在不使用 Codespace 時將其關閉,以便最大限度地從配額中獲得收益。
首先,建立GitHub 帳戶,或者如果您已經有帳戶,則直接登錄,然後分叉此儲存庫,並透過點擊綠色程式碼按鈕-> Codespaces -> Create codespace on master 在新的Codespace 中開啟您的分叉。這應該會在瀏覽器中開啟 VS Code,並預先安裝所有必要的擴充功能和相依性。從這裡開始,該過程與本地建置非常相似,只是您無法使用“上傳”按鈕來刷新韌體。相反,您必須從HayBox/.pio/build/<environment>/
下載已編譯的二進位檔案並手動刷新它(有關更多信息,請參閱此處)。
此儲存庫包含一個GitHub Actions 工作流程定義,該定義會在每次推送時建置矩陣中指定的每個PlatformIO 環境,並將韌體二進位檔案作為工件上傳,您可以透過點擊歷史記錄中的特定工作流程運行來下載這些工件。您可以建立此儲存庫的分支,並透過點擊設定 -> 操作 -> 常規 -> 選擇「允許所有操作和可重複使用工作流程」 -> 儲存來啟用操作。
如果您只想透過 GitHub Actions 進行構建,最快的更改方法是使用 github.dev。您只需按 即可完成此操作.
當您開啟此儲存庫的分支時,在鍵盤上輸入,它將在瀏覽器中開啟 VS Code 編輯器。這不會為您提供與 Codespace 中相同的開發功能,但它允許您直接從瀏覽器進行更改並提交它們。更改您想要的任何內容,然後使用左側的「原始碼管理」標籤新增、提交和推送您的變更。最後,返回儲存庫並點擊“操作”選項卡,單擊您的工作流程運行,然後等待它構建工件。
如果您要新增新的裝置配置/PlatformIO 環境,則必須將該環境新增至矩陣中,以便透過 GitHub Actions 工作流程建置它。您也可以從矩陣中刪除您不關心的任何環境,以減少資源使用並可能加快建置速度。
若要將基於 Pico 的控制器重新啟動到 bootsel 模式,請在外掛程式上按住 Start。
若要在 GCCPCB2、GCCMX、B0XX R2 或 LBX 上切換到 Brook 板模式,請在插件上按住 B。
根據控制器中使用的微控制器的類型,通訊後端的選擇略有不同。
在 Pico/RP2040 上,會自動偵測 USB、GameCube 和 Nintendo 64。如果未插入控制台,則預設為XInput ,它應該可以與大多數 PC 遊戲即插即用。按住插件上的以下按鈕之一來選擇其他後端:
在 Arduino/AVR 上,如果偵測到 USB 連接,則選擇DInput後端。否則,它預設為 GameCube 後端,除非透過按住插件上的以下按鈕之一手動選擇另一個後端:
與其他類似的韌體不同,HayBox 預設可讓您即時切換模式,而無需拔掉控制器。這主要在 PC 上有用,而不是在控制台上有用,在控制台上您通常必須重新啟動控制台才能切換遊戲。它還可以減少插入時必須用一隻手握住的按鈕數量。
預設控制器模式按鈕組合為:
預設鍵盤模式按鈕組合(僅在使用 DInput 後端時可用,不適用於 XInput):
HayBox 需要與官方 B0XX 韌體不同的 Dolphin 控制器配置文件,因為它使用不同的 DInput 映射,這對於在多個遊戲中使用更有意義。這些可以在 HayBox 儲存庫的dolphin
資料夾中找到。設定檔的命名是為了表明它們適用於什麼通訊後端和作業系統:
若要安裝設定檔:
dolphin
資料夾複製到資料夾<YourDolphinInstallation>UserConfigProfilesGCPad
(如果不存在則建立它)%appdata%Slippi LaunchernetplayUserConfigProfilesGCPad
~/.config/SlippiOnline/Config/Profiles/GCPad/
Cmd + Shift + G
並輸入路徑/Users/<USER>/Library/Application Support/Slippi Launcher/netplay/Slippi Dolphin.app/Contents/Resources/Sys/Config/Profiles/GCPad
%userprofile%DocumentsDolphin EmulatorConfigProfilesGCPad
~/.config/dolphin-emu/Profiles/GCPad/
* macOS 僅支援 DInput(而且不是很好),因此如果使用基於 Pico/RP2040 的控制器,您將必須透過按住插件上的 Z 來強制 DInput 模式,即使如此,它也可能無法運作。我對蘋果糟糕的控制器支援無能為力(他們似乎在每次其他更新中都破壞了這一點),而且我沒有任何蘋果設備,所以這也將被視為不受支援的 HayBox 使用。
通訊後端(例如 DInput、GameCube 或 N64)部分是透過自動偵測選擇的,部分是基於插件上的按鈕選擇的。這是在config/<environment>/config.cpp
的setup()
函數中處理的。邏輯相當簡單,即使您沒有程式設計經驗,也應該不難看出正在發生的事情並根據需要進行更改。
Arduino環境對應的config資料夾為:
config/arduino_nativeusb/
用於具有本機 USB 支援的 Arduino(例如 Leonardo、Micro)config/arduino/
用於沒有本機 USB 支援的 Arduino(例如 Uno、Nano、Mega 2560)對於 Arduino 設備配置,您可能會注意到數字 125 被傳遞到GamecubeBackend()
。這可以讓您更改輪詢率,例如,如果您的 DIY 不支援本機 USB 並且您想將其與超頻 GameCube 控制器適配器一起使用。在該範例中,您可以傳入 1000 以同步至 1000Hz 輪詢率,或傳入 0 以完全停用此滯後修復。輪詢率可以按照與此相同的方式傳遞到 N64Backend 建構函式中。
您可能會注意到 1000Hz 輪詢率也適用於控制台。請注意,雖然這有效,但會導致更多的輸入延遲。這裡設定輪詢速率的目的是讓 GameCube 後端可以延遲到下一次輪詢之前才讀取輸入,從而使輸入是新鮮的且不會過時。
對於 Pico/RP2040,不需要傳入控制台輪詢率,因為 Pico 在收到控制台輪詢後有足夠的處理能力來讀取/處理輸入,因此不需要預測輪詢何時到達並做好準備提前。
若要設定輸入模式(控制器/鍵盤模式)的按鈕保持,請編輯config/mode_selection.hpp
中的select_mode()
函數。每個if
語句都是一個用來選擇輸入模式的按鈕組合。
大多數輸入模式支援傳入 SOCD 清理模式,例如socd::2IP_NO_REAC
。請參閱此處以了解其他可用模式。
對於建立新的輸入模式,如果您了解一些 C++,或至少有一些程式設計經驗,將會有所幫助。也就是說,如果您只是將新模式建立在現有模式的基礎上並將其作為範例,那麼即使沒有經驗,您也應該能夠順利進行。
輸入模式有兩種:ControllerMode 和 KeyboardMode
鍵盤模式稍微簡單一些,所以讓我們從這裡開始。
KeyboardMode 的行為類似於標準鍵盤,並且應該適用於任何支援鍵盤的裝置。
您可以在UpdateKeys()
函數中自由使用您喜歡的任何邏輯和程式設計技巧來根據輸入狀態決定輸出。您可以建立輸入圖層(例如混戰模式下的方向鍵圖層,在按住 Mod X 和 Mod Y 時啟動)或其他類型的條件輸入。
可用鍵碼清單可以在此處找到。
請記住,鍵盤模式只能在使用DInput通訊後端(而非XInput)時啟動。
ControllerMode 接受數字按鈕輸入狀態並將其轉換為與標準遊戲手把相對應的輸出狀態。任何 ControllerMode 都可以與任何 CommunicationBackend 搭配使用。 CommunicationBackend 只需從一個或多個輸入來源讀取輸入,使用目前的 ControllerMode 根據這些輸入更新輸出,並處理將輸出傳送到控制台或 PC。
要建立 ControllerMode,您只需要實作函數UpdateDigitalOutputs()
和UpdateAnalogOutputs()
。
UpdateDigitalOutputs()
與鍵盤模式下的UpdateKeys()
函數非常相似,不同之處在於,我們只是設定本次迭代的輸出狀態,而不是呼叫Press()
函數立即發送輸入。顧名思義,我們在此函數中僅處理數字輸出。
UpdateAnalogOutputs()
有點複雜。首先,它必須在執行其他操作之前呼叫UpdateDirections()
。此函數接收的值指示您的左搖桿和右搖桿是否指向左/右/上/下。您還可以傳入最小、中性(中心)和最大搖桿模擬值,以便您可以根據每種模式進行配置。所有這些資訊都用於根據您傳入的輸入自動設定搖桿模擬值。
UpdateDirections()
也使用指示當前搖桿方向的值填充變數directions
,對於兩個搖桿的 X 軸和 Y 軸,該值可以是 1、0 或 -1。這些值使編寫修飾符邏輯變得更加容易。
呼叫UpdateDirections()
後,新增所需的任何修飾符處理邏輯。請記住, UpdateDirections()
已經設定了預設的模擬搖桿值,因此在處理修改器時,您只需手動設定實際正在修改的軸的值。除此之外,我無法教如何編寫修飾符邏輯,因此只需查看範例並嘗試一下即可。
最後,設定您需要的任何模擬觸發值。
注意:類比觸發輸出也可以在UpdateDigitalOutputs()
中處理,但我認為將它們與其他類比輸出放在一起通常看起來更乾淨。
另請注意:您無需擔心重設輸出狀態或清除其中的任何內容。這是在每次迭代開始時自動完成的。
在每種模式(對於控制器模式和鍵盤模式)的建構函式中,您可以配置成對的相反方向輸入以套用 SOCD 清理。
例如,在src/modes/Melee20Button.cpp
中:
_socd_pair_count = 4;
_socd_pairs = new socd::SocdPair[_socd_pair_count]{
socd::SocdPair{&InputState::left, &InputState::right, socd_type},
socd::SocdPair{ &InputState::down, &InputState::up, socd_type},
socd::SocdPair{ &InputState::c_left, &InputState::c_right, socd_type},
socd::SocdPair{ &InputState::c_down, &InputState::c_up, socd_type},
};
這將左/右、下/上、C-左/C-右和C-下/C-上設定為將應用SOCD清潔的相反基本方向對。 SOCD 清理會在UpdateDigitalOutputs()
和UpdateAnalogOutputs()
之前自動完成,您無需再擔心。
對於每個SocdPair
您可以傳入您選擇的SocdType
。預設情況下,對於大多數模式,它會作為單一建構函數參數傳入,但可以傳入多個參數,或簡單地使用硬編碼值。這兩種方法都在src/modes/FgcMode.cpp
中舉例說明。
SocdType | 描述 |
---|---|
SOCD_NEUTRAL | 左 + 右 = 中性 - 如果SocdPair 中未指定SocdType 則為預設值 |
SOCD_2IP | 第二個輸入優先權 - 左 -> 左 + 右 = 右,反之亦然。釋放第二個方向給出原始方向 |
SOCD_2IP_NO_REAC | 無需重新激活的第二輸入優先級 - 與上述相同,但釋放第二方向會導致中性。必須以物理方式重新啟動原始方向。 |
SOCD_DIR1_PRIORITY | SocdPair 中的第一個按鈕始終優先於第二個按鈕 |
SOCD_DIR2_PRIORITY | SocdPair 中的第二個按鈕始終優先於第一個按鈕 |
SOCD_NONE | 沒有 SOCD 解析度 - 遊戲決定 |
請注意,您不必像在 Melee20Button 和 Melee18Button 模式中那樣實作HandleSocd()
函數。它僅在這些模式下被覆蓋,以便我們可以在 SOCD 清理之前檢查左和右是否都被保持,因為當它們都被保持時(沒有垂直方向被保持),我們需要覆蓋所有修改器。
如果您的控制器沒有遮光罩按鈕,您可能需要使用 Mod X 進行遮光罩,並將遮光罩傾斜放在 R 上。您可以使用 Melee18Button 模式而不是 Melee20Button 來完成此操作。
Melee20Button 和 Melee18Button 模式提供了按下 + 向右時使用哪個座標的選擇。預設情況下,按住 + 返回鍵將允許您自動取消刺拳,這對於某些角色來說是一種有用的技術。
另一種使用下+右對角線的流行技術是所謂的蹲伏/行走選項選擇。該技術涉及在蹲伏時以一定角度按住+向前,這樣在蹲伏取消攻擊後,你將自動開始向對手走去,而不是回到蹲伏狀態。這對於技術追逐非常有用,但是用於此技術的座標不允許您自動取消刺拳。
這可以透過將crouch_walk_os
選項設為 true 來配置,如config/mode_selection.hpp
所示:
new Melee20Button(socd::SOCD_2IP_NO_REAC, { .crouch_walk_os = false })
您還必須在config/<environment>/config.cpp
中更改此設置,以便將其應用於插件,因為mode_selection.hpp
僅控制切換模式時發生的情況。
ProjectM 模式有一些額外的選項來配置某些行為。如config/mode_selection.hpp
所示:
new ProjectM(
socd::SOCD_2IP_NO_REAC,
{ .true_z_press = false, .ledgedash_max_jump_traj = true }
)
首先, ledgedash_max_jump_traj
選項可讓您啟用或停用從近戰模式借用的行為,其中按住左和右(並且沒有垂直方向)將給出 1.0 基數,無論持有修飾符為何。
如果您將 SOCD 模式變更為 2IP(需要重新啟用),如果您想要流暢的遊戲體驗,您也應該將此選項變更為 false。
其次,存在true_z_press
選項是因為 Project M/Project+ 處理 Z 按下的方式與近戰不同。近戰將 Z 按下解釋為光盾 + A,因此它可以用於 L 取消,而不會將您鎖定在技術之外。在 PM/P+ 中,按下 Z 會觸發一項技術,如果用於 L 取消,則會導致不必要的技術鎖定。預設情況下,HayBox 中的 ProjectM 模式設定為使用 lightshield + A 宏,以保留近戰的預期行為。但是,此巨集不允許您使用繩索/抓斗攻擊或抓取物品。要解決此問題,您可以按 Mod X + Z 發送真實的 Z 輸入。
如果這讓您煩惱,並且您只想在按 Z 時預設發送真實的 Z 輸入,則可以將true_z_press
選項設為 true。
HayBox 支援多種輸入來源,可以讀取這些輸入來源來更新輸入狀態:
GpioButtonInput
- 最常用,用於讀取直接連接到 GPIO 引腳的開關/按鈕。輸入映射由GpioButtonMapping
數組定義,幾乎在所有現有配置中都可以看到。SwitchMatrixInput
- 與上方類似,但掃描鍵盤樣式的開關矩陣而不是單一開關。 Crane 模型 C<=53 的配置包含在config/c53/config.cpp
中,它作為如何定義和使用開關矩陣輸入來源的範例。NunchukInput
- 使用 i2c 從 Wii Nunchuk 讀取輸入.這可用於混合輸入控制器(例如,左手使用雙節棍進行移動,右手使用按鈕進行其他控制)GamecubeControllerInput
- 與上方類似,但從 GameCube 控制器讀取。可以與 GamecubeBackend 類似地實例化。目前僅針對 Pico 實現,您必須在與 GamecubeBackend 的任何實例不同的 pio 實例(pio0 或 pio1)上運行它,或者確保兩者使用相同的 PIO 指令內存偏移量。每個輸入來源都有一個「掃描速度」值,大致指示讀取輸入所需的時間。快速輸入來源總是在最後可能的時刻讀取(至少在 Pico 上),導致非常低的延遲。相反,慢速輸入來源通常在需要之前很久就被讀取,因為它們太慢而無法回應輪詢而讀取。因此,更理想的做法是在單獨的核心上不斷讀取這些輸入。這在 AVR MCU 上是不可能的,因為它們都是單核,但在 Pico/RP2040 上是可能的(而且很容易)。預設 Pico 設定config/pico/config.cpp
的底部透過使用 core1 讀取 Nunchuk 輸入而 core0 處理其他所有內容來說明這一點。有關使用 core1 的更多信息,請參閱下一節。
在每個配置的setup()
函數中,我們建立一個輸入來源數組,然後將其傳遞到通訊後端。通訊後端決定何時讀取哪些輸入來源,因為不同的後端需要在不同的時間點讀取輸入。我們還建構了一系列通訊後端,允許同時使用多個後端。例如,在大多數配置中,每當使用 DInput 後端時,B0XX 輸入檢視器後端都會用作輔助後端。在每次迭代中,主循環告訴每個後端發送各自的報告。未來,可能會有更多後端用於將資訊寫入 OLED 顯示器等。
在每個配置中,都有函數setup()
和loop()
,其中setup()
先運行,然後loop()
重複運行,直到設備斷電。
在Pico/RP2040上, setup()
和loop()
函數在core0上執行,您可以新增函數setup1()
和loop1()
以便在core1上執行任務。
例如,要讀取 core1 上的 GameCube 控制器輸入:
GamecubeControllerInput *gcc = nullptr;
void setup1() {
while (backends == nullptr) {
tight_loop_contents();
}
gcc = new GamecubeControllerInput(gcc_pin, 2500, pio1);
}
void loop1() {
if (backends != nullptr) {
gcc->UpdateInputs(backends[0]->GetInputs());
}
}
while
迴圈確保我們等到 core0 上的setup()
完成通訊後端的設定。然後我們建立一個輪詢率為 2500Hz 的 GameCube 控制器輸入來源。我們也在pio1
上運行它,作為避免干擾任何 GameCube/N64 後端的簡單方法,除非另有說明,否則這些後端使用pio0
。在loop1()
中,我們假設主後端是backends
數組的第一個元素(無論如何,它是在同一個檔案中配置的,所以我們並沒有真正假設任何我們不知道的東西)並直接掃描GameCube控制器輸入到後端的輸入狀態。
作為一個稍微瘋狂的假設示例,人們甚至可以使用單個Pico 為兩人街機櫃的所有控件供電,方法是創建兩個開關矩陣輸入源,每個輸入源使用10 個引腳,以及兩個GameCube 後端,兩者都位於單獨的核心上。可能性是無限的。
如果您使用基於 Arduino 的控制器的官方適配器,您可能必須在插件上保留 A,該插件透過將 0 的輪詢率傳遞給 GamecubeBackend 建構子來停用輪詢延遲最佳化。
如果您使用沒有升壓電路的基於 Arduino 的控制器,則需要 5V 電源,因此對於 Mayflash 適配器,您需要插入兩條 USB 電纜,並且控制台上的隆隆聲線需要完好無損。 Pico 本身使用 3.3V 電源工作,因此這不是問題。
我歡迎貢獻,如果您想分享一個輸入模式,請隨時提出拉取請求。請安裝 VS Code 的 clang-format 外掛程式並使用它來格式化您想要新增的任何程式碼。
我們使用 SemVer 進行版本控制。有關可用版本,請參閱此儲存庫上的標籤。
另請參閱參與專案的貢獻者清單。
該專案已獲得 GNU GPL 第 3 版許可 - 有關詳細信息,請參閱許可證文件