【翻譯轉載】如果你想要構建一套基於ECS的GUI框架

w4ngzhen發表於2024-08-21

譯者序

本文原文地址:So you want to build an ECS-backed GUI framework | Leafwing Studios (leafwing-studios.com)。翻譯和釋出本文前,已經獲得了原作者的許可。

本人翻譯這篇文章的主要是因為儘管該文是從 bevy_ui 這一具體的庫出發,但其核心是討論GUI框架的設計思路與正規化,同時還介紹了很多已有成果,個人覺得如果有讀者對基於Rust的GUI建設感興趣的話,一定會從這篇文章中學到很多有價值的內容。當然,筆者只是利用自己欠佳的英語水平結合翻譯軟體來對原文進行了翻譯,所以如有翻譯上的問題,還請讀者指出,感激不敬!

此外,這篇文章由原作者於23年11月編寫,當時 bevy 正值0.12版本,在翻譯這篇文章的時候已經是24年的8月底,bevy的版本已經更新到了0.14,所以文中關於 bevybevy_ui 的一些建設工作(如PR、討論等)不一定具有時效性。

原文標題為:"So you want to build an ECS-backed GUI framework",從文章上下文理解看來,實際上應該是"So (if) you want to build an ECS-backed GUI framework"

正文

Challenges and opportunities in the future of bevy_ui

關於 bevy_ui 未來的挑戰與機遇

Alice I. Cecile, Rose Peck | 2023-11-27

如果你想要透過Rust(以及其生態)構建一個使用者介面,那有什麼工具能比實體-元件-系統(ECS)框架更合適呢?它不僅提供了一種型別安全的、流行的狀態管理方案,而且最重要的是:這套體系的速度將非常快(顯然無需進行基準測試)。

當然,Bevy 確實在這麼做!實際上,它已經這樣做了好幾年。那麼,為何它沒有在競爭中脫穎而出,贏得數百萬人的心,並取代 areweguiyet.rs 呢?

譯者注:Are we GUI yet?網站陳列了目前已知的所有基於Rust繫結或實現的GUI框架。這裡的“取代”主要含義是為什麼Bevy的基於ECS的GUI框架為什麼做的並不出眾,沒有成為某種優秀的範例,進而讓基於Rust的GUI框架結束百花齊放的局面。

雖然基於ECS模式的GUI可能並不是傳統方式,但現有技術表明這並非不可能。flecs這篇文件中將許多核心思想進行了實現,同時也像 bellybevy_lunexbevy_ui_dslcuicui_layout以及kayak_ui這些庫進行了這方面的嘗試,使得Bevy的ECS(模式)顯現出了巨大的潛力。甚至還有一個名為Polyphony的,獨立的,ECS先行的,基於Javascript編寫的GUI庫(關於它的討論:Polyphony ECS GUI and future · Issue #1 · traffaillac/traffaillac.github.io)。

事實證明,困擾bevy_ui的大多數問題都不是由、由於使用ECS甚至使用Rust的決定引起的,而是一些無聊、乏味和令人沮喪的內容:編寫GUI框架是一項涉及大量容易變動的工作。Bugs、模板程式碼和缺失的功能擊碎了使用者和開發人員逐步改進最佳化程式碼的意願。

但在我們深入討論繁雜的細節之前,有一個重要的免責宣告。Alice是Bevy的維護者(譯者注:同時也是本文的作者),但不是專案負責人,甚至不是UI方面的專家。Rose是Foresight Spatial Labs的一名員工,她日常工作是使用Bevy和傳統的web框架(React)來構建重GUI的應用程式。本文相關的論點、意見純粹是我們自己的,不是最終定性的或官方的話!

這篇文章旨在記錄如何製作一個GUI框架,為什麼我們要使用ECS,以及我們需要修復哪些部分才能使 bevy_ui 變得更優秀。(關於這些內容)我們在很多地方(這裡這裡這裡,以及這裡)都有過很多重複的討論,但很少有實質性,落地的實踐活動(除了ickshonpe ,you rock)(譯者注:這位icksphonpebevy_ui 的部分提交了大量的最佳化、修復程式碼)。說“bevy_ui應該像我最喜歡的ui框架一樣工作”很容易,但實際上將其轉化為可行的設計、達成共識並其構建出來卻要困難得多。

透過編寫一份關於需求、願景和進展的最新、全面、通俗易懂的文件,我們希望Bevy社群能夠團結起來解決 bevy_ui 今天遇到的問題,徹底排除各種可能性,併為關鍵的缺失部分提出可靠的設計。

誰知道呢?也許十年後,你正在閱讀這篇文章,夢想著編寫自己的基於ECS驅動的GUI框架。

在我感到非常疲憊、厭倦的過往中,有三類常見的關於 bevy_ui “脫軌”(譯者注:原文為"get derailed")的討論:

  1. Bevy應該使用一套現有的GUI框架。
  2. 一個同時適用於遊戲和應用程式的GUI框架是不可能的。
  3. 您無法在ECS中構建GUI框架。

為什麼不直接用egui(或是dioxus,或是tauri,或是iced,或是yew)?

現在已經有非常多的基於Rust的GUI框架,其中一些甚至一直在積極地維護,編寫文件以及增加基本功能!

社群已經為其中一些製作了出色的crates,像Foresight這樣的公司甚至使用這些第三方GUI框架製作了複雜的生產應用程式

Bevy想編寫我們自己的ui實現,顯然是"非我發明"綜合症的典型案例(譯者注:重複造輪子)。當我們可以使用現有的解決方案來編寫即將到來的 Bevy Editor 時,為什麼要將稀缺的精力(和決策)用於此?畢竟,我們可以與Dioxus完成一次正式的合作,以此省下很多年的工作量。

然而,以下是我們基於技術以及社會方面考慮的,認為Bevy不應該這樣做的原因:

  1. 與引擎的其他部分保持一致性是非常有價值的:
    1. 為新使用者提供了更簡單、更一致的學習上的體驗。
    2. 這樣做使得系統更容易維護。
    3. 將所有更改儲存在同一個程式碼倉庫中,從而消除了在存在依賴樹的情況下,對於版本釋出要更加小心謹慎處理的必要。
    4. 一致性讓UI模組能夠從引擎其他模組的改進中也受益,反之亦然。Cart相信許多挑戰並非是UI模組獨有的,我們對此表示贊同!
  2. Bevy已經為GUI庫需要完成的許多核心任務提供了一個很好的解決方案。
    1. 渲染、狀態管理、資產asset、輸入、視窗、非同步等等。
    2. 為什麼我們要再次採用重複的、或許微妙不相容的方法來完成這些任務?
  3. 將資料傳送到外部UI框架和從外部UI框架接收資料本身就容易出錯,邏輯會變得複雜,難以維護,並且充斥著很多樣板程式碼。
    1. 我們不可避免的需要提供整合層來面對不匹配的資料模型。
    2. 這並不是UI模組獨有的:bevy_rapier在物理方面也遇到了類似的問題(儘管它仍然是一個優秀的庫)。
  4. 打破目前“螢幕上的盒子(boxes on a screen)”這一UI標準的設計思路,將會使得現狀變得更加困難。
    1. 世界空間UI(World-space UI)是遊戲的一個關鍵功能,涉及到:單元疊加(unit overlays)、VR選單、計算機螢幕等等。
    2. 遊戲UI往往希望與遊戲世界狀態緊密結合,並具有不同尋常的藝術效果
    3. 使用第三方解決方案編寫自定義著色器來覆蓋某些節點的行為會變得更加困難。
  5. 現有的Rust GUI專案都沒有很好地回答解決一個事實:借用檢查器非常討厭這樣資料結構以及討厭拆分(資料)可變性。
    1. 透過新增關係relations,Bevy保證了一種在Rust中處理圖資料關係的獨特而強大的方法。
    2. Bevy的系統是一個靈活的、無panic的、快速且可靠的解決方案,用於共享對世界狀態的可變訪問。這背後有很多黑魔法,親愛的上帝,我們不想解釋兩次了(譯者注:可以在這裡瞭解)。
  6. 其他專案不由Bevy專案運營。
    1. 我們的目標可能會有所不同:例如,egui是專注於簡單、快速構建的UI,為了達到這一要求,它需要在效能和可定製性之間做出權衡取捨。
    2. 改動會變得更難協調:我們需要遷移PR,並且無法快速新增編輯器所需的功能。
    3. 上游的依賴庫可能(再次)被廢棄。如果Bevy計劃繼續存在幾十年,所依賴其他庫的UI解決方案也會一併存在嗎?
    4. 我們無法保證某一個關鍵依賴項的質量。
    5. 它給那些較小的所以依賴的第三方庫帶來了很大的維護壓力,因為會讓如此大的客戶端向它們發出最佳化、fix的請求。
  7. 許多建議提到的第三方GUI庫由於它們通常依賴於C、C++或JavaScript等其他語言生態,使Bevy的構建和分發過程變得非常複雜。
  8. 不要太苛刻,但很多現有的Rust GUI解決方案,只是不是那麼完美。
    1. 雖然我們有很多能夠接受的選擇,但它們都有不小的缺點。沒有人真正成為贏家。
    2. Are we GUI yet?說“根不深,但種子已經播下”("The roots aren't deep but the seeds are planted.")是有原因的。
    3. 在內心深處,我們都知道我們可以做得更好,並且我們應該做得更好。
  9. 喜歡第三方GUI解決方案的使用者可以並且無論如何都會使用它們。

我們會學習其他GUI框架嗎?當然。我們會正式大規模採用它們嗎?絕對不會。

一套GUI框架來統領所有?

在討論 bevy_ui 時,另一個常見的友善問題是“我們真的能用一個UI框架來滿足所有使用者的需求嗎”?

我看到了一些潛在的分歧:

  • 應用程式UI vs 簡單遊戲UI vs 複雜遊戲UI
  • 一些熱愛CSS以及web應用開發的人 vs 恨它們的人
  • 程式化的程式設計師友好型GUI vs 資產驅動的藝術家友好型GUI
  • 立即模式GUI vs 保留模式GUI

我相信你能想到更多,分歧很容易出現,也很有趣!理論上,我們可以參考Unity(譯者注:原文“pull a Unity”,但譯者覺得可以理解為參考Unity,意思是“再搞一個類似的”),並在Bevy中建立多個相互競爭的UI框架。但我們認為這將非常糟糕,因為:

  • 這對使用者來說非常困惑。
  • 它分散了開發人員的注意力。
  • 對於使用者來說,很難權衡到底要使用哪種解決方案。
  • 在兩個相互競爭的解決方案之間進行遷移會非常痛苦。
  • 在同一個專案中使用多個解決方案從根本上是站不住腳的。
  • 需要兩倍的時間(如果你幸運的話)。

幸運的是,“在多個使用者群體的不同需求中找到正確的所需的東西”並不是UI獨有的問題。我們有很好的工具在架構層面管理這一點:

  • 這個問題其實算是一種假設,因為實際上已經在web開發上得到了解決:
    • 我們不會爭辯說web UI是否是有史以來最偉大的UI解決方案(它有許多明顯和不明顯的缺陷)。
    • 但事實上人們已經成功構建了幾乎任何一種你能想到的使用HTML/CSS/JavaScript來搭建的UI:網頁、程式碼編輯器、遊戲(瀏覽器和獨立版)、CAD應用程式、終端等。有一個常見的笑話是“未來一切都是chrome(<化學元素>鉻,但實際指Google的Chrome瀏覽器)”(謝謝Electron
    • 值得說明的是,web UI技術棧並不是為大多數用例設計的。可以說,它不是為他們中的任何一個單獨設計的!
  • 模組化:確保使用者可以移除或留下解決方案中某些他們不喜歡(或喜歡)的部分。
    • 元件、系統、外掛和Rust庫crate的feature特性都非常適用於模組化!
    • 第三方UI庫如今存在著,並將繼續存在。
  • 可擴充套件性:確保內部構件可訪問且可構建。
    • 公共元件以及資源真的很有用。
    • 想象一下,一個基於 bevy_ui 的可互動擴充套件庫組成的豐富生態系統,所有這些庫都建立在我們的核心渲染、互動和佈局規範之上。
  • 抽象設計中的漸進式披露(Progressive Disclosure)。
    • widget部件是由節點構建的。
    • 節點只是實體。
    • 在整個過程中,沒有什麼能阻止你在較低的層次進行hook(譯者注:Hook)。

如果使用者可以將相同的ECS和渲染工具用於從畫素藝術平臺到單元著色視覺小說(cell-shaded visual novels)再到PBR競技場射擊遊戲的一切實現,那麼我們就可以創造出一個足夠靈活、舒適的,適合每個人的UI解決方案。

ECS中的GUI:bevy_ui實際上是如何工作的?

解決了這些常見的反對意見後,我們有望開始討論如何實際構建我們的UI框架。讓我們考慮一下我們的實際產品需求,這樣我們就可以看到 bevy_ui 的不足之處。

不幸的是,對我們來說GUI框架是極其複雜的“野獸”。其中某些部分是如此重要,以至於將它們排除會破壞整個系統:

  1. 儲存節點樹(Storing a tree of nodes)
    1. 幾乎每個優秀的UI正規化都有一個或多個巢狀的元素樹。
    2. “節點”是這樣的元素:UI中最小的不可再分割的原子。
    3. 你需要把這些資料儲存在某個地方!
    4. bevy_ui 中,節點樹儲存在世界World中:每個節點都是一個具有node元件的實體。
    5. UI實體透過使用父元件和子元件連線在一起。
  2. 佈局(Layout)
    1. 一旦有了一組節點後,我們希望能夠描述它們在螢幕上的位置。
    2. 只是簡單地指定絕對大小和位置並不是很穩健:當新增、刪除節點,或螢幕大小更改時,這樣的佈局可能會遭到破壞。
    3. bevy_ui 中,透過Style元件指定佈局(這名稱得怪CSS,抱歉)。
    4. bevy_ui 使用了taffy(Alice幫助維護!):它支援flexbox彈性盒子css-grid網格的佈局策略。
    5. 如果你不想受到Web佈局演算法的約束,morphorm(在我們看來)是一個更好的選擇。
  3. 輸入(Input)
    1. 以鍵盤按壓、滑鼠點選、滑鼠移動、觸控式螢幕點選、遊戲手柄輸入等形式收集使用者輸入。
    2. 通常與“拾取(picking)”相匹配:根據位置找出滑鼠指標事件關聯的元素。
    3. 理想情況下,為涵蓋懸停、按下、釋放和長按按鈕等操作設計一套不錯的抽象概念。
    4. bevy_ui 依賴於 bevy_input,而 bevy_input 又從 winitgilrs 這些底層庫中獲得資料。
  4. 文字(Text)
    1. 將字串轉換為畫素以便於我們能夠將它們繪製到螢幕上。
    2. 在所包含文字的UI節點的邊界內排列這些文字。
    3. 精確的畫素對渲染很重要,但大小尺寸作為節點佈局的輸入同樣也重要。
    4. bevy_ui 當前正使用 glyph_brush 進行文字字元渲染。
    5. cosmic-text 對非拉丁文字有更好的塑形(shaping)支援。
  5. 視窗管理(Window management)
    1. 建立一個(或n個)視窗來繪製UI。
    2. bevy 使用 winit,你也應該用它。
  6. 渲染(Rendering)
    1. 將UI的元素繪製到使用者螢幕上。
    2. Bevy使用 bevy_render,而其內部進而使用 wgpu
    3. 如果你正在構建自己的Rust GUI框架,試試vello
  7. 狀態管理(State management)
    1. 保持對UI狀態的永續性跟蹤。
    2. 填充的文字內容,單選按鈕,動畫進度,選單是開啟還是關閉,暗/亮模式等。
    3. bevy_ui 中,狀態作為元件儲存在實體上(或者少量的狀態作為全域性資源)。這工作得非常好!
  8. 資料傳遞(Data transfer)
    1. 將資料從UI傳輸到其他資料結構進行儲存,反之亦然。
    2. 在Bevy的上下文中,“其他資料儲存”是儲存您所有遊戲/應用程式狀態的ECS World世界。
    3. 資料繫結是一種用於自動化此過程的抽象:自動和精細地進行資料的變更傳遞。
    4. 目前,bevy_ui使用系統(system)在world其他部分來回傳送資料。

在此基礎上,您可能希望 bevy_ui 新增如下的功能:

  1. 導航(Navigation,GUI頁面上元素導航)
    1. 以有原則的離散的方式瀏覽GUI選單元素:“tab鍵”是常見的鍵繫結。
    2. 導航對鍵盤和遊戲手柄都非常有用。
    3. 傳統應用程式的重要可訪問性功能(accessibility,a11y)。
    4. bevy_ui 對這塊還沒有第一方的解決方案。
  2. 樣式(Styling)
    1. widget部件和節點具有大量主要是樣式性的屬性。
    2. 我們希望確保我們的應用程式具有一致的外觀和體感,並能完成快速更換。
    3. 對於應用程式(尤其是移動應用程式)來說,我們期望能夠達到原生外觀和體感。
    4. 樣式可能採取以下形式達成實際效果:
      1. 級聯繼承(如CSS)。
      2. 選擇器(如CSS中的選擇器,或您可能使用在 bevy_ui 中提供的查詢能力編寫選擇器)。
      3. 全域性主題,例如白天明亮模式以及夜間暗黑模式。
      4. widget部件支援某些特定樣式。
    5. 樣式通常需要有可預測的組合規則:當多個樣式同時影響一個元素時會發生什麼?
    6. bevy_ui 目前沒有任何第一方的抽象設計。
  3. 可組合、可重用Widget部件的抽象設計(An abstraction for composable, reusable widgets)
    1. 即使是簡單的部件型別(單選按鈕、文字輸入框),程式碼編寫使用起來也相當複雜!
    2. 使用者應該能夠一次性編寫這些程式碼,然後在整個專案中重用(reuse)它們,從而提高開發效率和以及保持UI一致性。
    3. 部件可以由一個或多個節點/元素組成。
    4. 每個部件的節點數量可以動態變化:想想不斷增長的待辦事項列表。
    5. 部件需要能夠接受引數來更改其內容或行為。例如,建立一個具有可自定義文字的可重用按鈕。
    6. bevy_ui 目前使用Bundle型別,但由於無法處理多個節點,因此算是較為失敗。
  4. 動作行為抽象(Action abstractions)
    1. 撤銷-重做。
    2. 可重新繫結熱鍵。
    3. 命令選項板。
    4. bevy_ui 對此沒有第一方解決方案,甚至第三方解決方案也不成熟(抱歉!)。
  5. 可訪問性(Accessibility)
    1. 為UI建立並暴露機器程式友好的API:讀取狀態、控制渲染/顯示、傳送輸入並檢測這些輸入更改時會發生什麼。
    2. 通常能夠對鍵盤導航進行hook。
    3. 提供API供螢幕閱讀器等工具使用,這些工具提供了一個可供選擇的使用者介面,以滿足殘疾使用者的需求。
    4. bevy_a11y hook到accesskit,你的GUI框架也應該如此。
    5. 關於可訪問性,存在很多事項需要討論,但不幸的是,我們在這裡沒有具體事項統計。
  6. 本地化(Localization)
    1. 存在不止一種使用者語言:你需要一種方法來變更UI元素(尤其是文字),以滿足喜歡不同語言的使用者的需求。
    2. 有些語言是從右向左而不是從左向右閱讀的,如果不考慮這一點,某些UI設計往往會倒退(backwards)。
    3. 圖示和表情符號在不同的地方也有不同的文化含義。
    4. 說真的,用fluent就行了。
  7. 資產管理(Asset management)
    1. UI經常使用預先渲染的影像或圖示作為視覺效果,尤其是在遊戲中。
    2. 你可能想要自定義的UI的效果和圖示等,或者以自己的方式顯示影像和影片。
    3. bevy_ui 使用bevy_asset來完成它
  8. 動畫(Animation)
    1. 小動畫,特別是一些UI元素髮生變化時的小動畫,可以顯著提高UI的精緻度和豐富性。
    2. 摺疊/展開上下文選單,滑動抽屜,旋轉載入圖示,淡入/淡出等動畫效果。
    3. bevy_ui 理論上與bevy_animation整合在一起,但整合還沒有完善(譯者注:翻譯這篇文章的時候,已經整合釋出了)。
  9. 除錯工具(Debug tools)
    1. 渲染後快速檢測,修改UI節點樹。
    2. 除錯工具對於定位bug和除錯過程中擺弄(twiddling)樣式非常有用。
    3. bevy_ui 對此沒有解決方案,但 bevy_inspector_egui 做得很好。
  10. UI序列化(記憶體中物件到檔案)和反序列化(檔案到記憶體中物件)(UI serialization (in-memory object to file) and deserialization (file to in-memory object))
    1. 如果我們可以根據儲存在檔案中的定義並構建UI,那麼我們可以:
      1. 使得外部工具(如遊戲編輯器)更容易構建UI。
      2. 讓客戶端使用者更容易自定義UI(想想Greasemonkey和遊戲模組)。
      3. 構建除錯工具會更容易實現和使用。
      4. 減少編譯時間:只需熱更新UI資產。
      5. 允許完全控制用於定義物件的格式和語法(譯者注:比如創造DSL)。
      6. 提供了更好的模組化工具的潛力,可以在不修改原始碼的情況下建立更高階別的抽象和自動化遷移
    2. 在遊戲中,這被稱為“資料驅動”方式。
    3. bevy_ui 當前使用場景scenes(來自bevy_scene)來實現UI序列化和反序列化。
  11. 非同步任務(Asynchronous tasks)
    1. 有的任務工作是由UI觸發的,但是需要很長時間才能完成。
    2. 當發生上述情況時,你肯定不希望你的程式處於一直UI凍結的狀態。
    3. bevy_ui 中,使用 bevy_tasks 來實現。

為什麼 bevy_ui 很糟糕?

透過hook到功能齊全(但尚未完成)的遊戲引擎Bevy,bevy_ui 實際上在大多數這些領域都有初步的解決方案!

那麼,為什麼絕大多數人認為它比Bevy更像Bavy呢(more Bavy than Bevy)?在聽取和整理了使用者使用 bevy_ui 的體驗後,以下是 bevy 0.12版本中,按照對使用者體驗的主觀印象進行排列的,關於 bevy_ui 的關鍵問題:

  1. 生成具有大量自定義屬性的實體需要大量的樣板:

    1. 無限巢狀的以及隨處可見的..Default::default()
    2. 當處理樹中排列的多個實體時,情況會變得更糟。如前所述,你不能在此場景使用bundle。
    3. 資料驅動的工作流並沒有被廣泛使用,因為Bevy的場景冗長且文件不足。
  2. Bevy需要為UI部件擁有一套真正的抽象:

    1. 並非所有widget部件都可以有意義地表示為單個實體。
    2. Bevy提供了很少的預構建好的widget部件:我們只有按鈕和影像。
    3. 因為我們缺乏標準化的抽象,即使新增最簡單、最有用的widget部件也會引起爭議並陷入困境。(需要明確的是,這不是審稿人或作者的錯)
  3. 在schedule中使用系統不太適合資料繫結:

    1. UI的行為幾乎總是一次性(one-off)的或非常離散稀疏的(very sparse)。(譯者注:而ECS體系下的系統總是每一輪都在進行執行)
    2. 從UI側啟動的任務要麼通常很小,要麼通常將其放入非同步任務池中。
    3. 我們真的希望能夠引用一個單一的特定實體及其父實體和子實體。
      1. 解決這個問題需要建立幾十個標記元件(Marker Component):幾乎每個按鈕、文字框、影像、容器等都有一個。
    4. 99%的時間,這些處理UI事件的系統不會工作,比較浪費時間,因為schedule模組必須不斷輪詢以檢視是否需要做任何事情。
  4. 在 bevy_ecs 中管理和遍歷層次結構(向上或向下)真的很糟糕:

    1. Relations關係管理短時間還不會實現。
  5. Bevy的UI輸入處理非常的原始:

    1. 用於處理指標輸入的Interaction互動元件使用起來非常有限了。
    2. 對移動端多點觸控支援也非常有限
    3. 鍵盤和遊戲手柄導航目前是缺乏支援的(譯者注:翻譯此文章的時候已經支援了)。
    4. 對於可配置的按鍵繫結,沒有第一方動作行為抽象支援。
    5. Bevy的“picking選取”支援非常簡單,且不容易擴充套件到非矩形元素或世界空間中的元素。(bevy_mod_picking加油!)
  6. Flexbox彈性盒子佈局(以及小範圍的CSS Grid網格)很難學習,有令人沮喪的邊緣案例情況,還有糟糕的API。你能解釋一下flex-basis是什麼嗎?

  7. 由於不久前的修復錯誤bevy_ui 中的字型渲染有時非常難看。

  8. Bevy缺失了樣式抽象:

    1. 如今我們已經完成了實現:只需修改元件即可!
  9. bevy_ui 新增非常規的視覺效果太難了:

    1. 我們缺少圓角:這對美觀的UI至關重要。(它們目前在UI方面非常流行。我們可以等幾年讓它們過時,但無論如何,它們都會在幾年後回來。)
    2. 我們也沒有陰影,但沒人在乎。
    3. 我們缺少九宮格佈局支援(nine-patch support):這對美觀但也靈活的基於資產定義的UI至關重要。
    4. 在Bevy 0.12的UI材質(功能釋出)之前,沒有另外一條路可以讓你在 bevy_ui 中新增自己的渲染抽象。
  10. 用純程式碼或透過手工編寫場景檔案來構建UI可能會很痛苦且容易出錯:如果有一款視覺化編輯器將會很棒。

  11. 世界空間的UI的支援程度很差,並且使用了一套完全不同的工具

    1. 這對於遊戲(生命條、單位幀)至關重要,對於GIS或CAD應用程式中的標記和標籤等也非常有用。
  12. bevy_ui沒有對動畫的一級支援。

  13. bevy_ui節點都有TransformGlobalTransform 元件,但不允許開發者使用它們。

  14. 在Bevy中處理非同步任務的人體工程學設計是令人沮喪的:需要對執行的任務進行手寫程式碼跟蹤和輪詢太多。

在這些問題中,只有1(實體生成樣板程式碼過多)、2(widget部件的抽象不足)、3(系統不適合UI事件回撥)以及4(UI節點層次結構處理令人痛苦)是由於我們選擇使用ECS架構而引起的。其餘的都是標準的GUI問題:無論你使用什麼正規化,都需要解決這些問題。關鍵的是,每一個與ECS相關的問題都是Bevy應該為其他用例修復的:

  1. 生成自定義實體(尤其是實體組合)對於常規的遊戲程式碼來說很糟糕,場景scene也不是最佳實踐。例如,我們生成一個玩家及其所有武器。
  2. Bevy缺少一種涵蓋多實體層次結構的程式碼定義級別的抽象:bundle也支援的不夠好。
  3. 一次性系統適用於各種定製的複雜邏輯,我們需要創造一套開發模式來有效地使用它們。
  4. Bevy的對於處理層級繼承等部分的實現從根本上來說是緩慢、脆弱和痛苦的。Relations關係設計需要首要一級支援。

ECS和GUI之間沒有根本上的模式不匹配或架構不相容。bevy_ui 並不是一個有根本缺陷的概念設計,只是它的ECS部分的基礎還不夠好。

bevy_ui的前進之路

bevy_ui 真正強大還有很長的路要走,但我們可以一步一步腳踏實地。儘管我們面臨著一些懸而未決的問題,以及即將對核心元件進行重寫的事項,但這並不意味著 bevy_ui 中的所有內容都應該被毀滅移除。GUI框架涉及大量複雜的,獨立的子元件:一個領域模組的改進不會因其他領域模組的重寫而無效!

我們可以把要做的工作分為三類:毫無爭議的部分,有爭議的部分以及待研究的部分。

沒有爭議直截了當的部分只需要解決掉它們即可。這些任務可能很容易,也可能比較困難,但對於如何或是否應該這樣做,不應該有太多的分歧。就目前,這類事項包括:

  1. 檢視以及合併UI圓角支援
  2. 檢視以及合併九宮格佈局支援
  3. 檢視以及合併實現動畫插值與混合能力的Animatable特性
  4. 檢視以及合併winit更新,它包含了對各種BUG的修復以及功能最佳化。
  5. 最後,檢視併合並將ab_glyph遷移為cosmic-text的PR,該部分解鎖了系統字型和複雜字型的使用。
  6. 新增對世界空間UI的支援,開始著手檢視和合並基於攝像機驅動的UI的PR
  7. 新增對UI不透明度變化的支援。
  8. 新增更多關於 bevy_scene 的文件、示例和測試,使其更容易擴充套件和學習。
  9. 為Bevy中的多點觸控輸入新增更好的示例和功能。
  10. 改進Bevy中關於處理非同步任務的人體工程學設計。
  11. 在taffy中新增Morphorm和/或cuicui_layout佈局策略,並在Bevy中暴露出來。
  12. 新增數十個widget部件(但目前由於圍繞良好的widget部件抽象還未達成共識)。

有爭議的事項是那些我們對其具備清晰的理解和廣泛的共識,但完成它們會產生重大的架構影響的事項,比如:

  1. 建立一套樣式抽象設計,使其透過修改元件值來完成工作:
    1. Alice寫了一個非常古老的RFC來說明這是如何工作的,bevy_kot提供了一種樣式級聯的方式,viridia的quill的實驗也有一個很好的提案。
  2. 上游的bevy_fluent,將會在bevy專案的保護之下進行長期的維護。
  3. 新增對鍵盤以及遊戲手柄的導航支援,並將其加入到 bevy_a11y 中。
  4. 如何處理指標事件和狀態新增適當的抽象
  5. 最佳化並實現Cart的bsn提案,以提高場景的可用性:
    1. 這是受到現有作品(如cuicuibellypolako)的啟發並與之密切相關。
  6. 新增類似bundle的抽象,但適用於多級層次組合:
    1. 新增一個bsn!宏,以便更容易例項化Bevy實體,特別是使用較少樣板程式碼的實體層次結構。
    2. 新增一種透過派生宏從結構體生成這些多層次實體的方法。
    3. 現有技術包括bevy_protomoonshine-spawn
  7. 新增插值顏色的方法以提升UI動畫效果。
  8. 建立一個UI特定的變換型別,以實現更快的佈局和更清晰,型別更安全的API。
  9. taffy 中新增在單個節點樹中的混合佈局策略的支援。
  10. bevy_easingsbevy_tweening這兩個庫完成後,新增對動畫緩動(easing)/tween的支援。
  11. 使用上游的leafwing-input-manager庫,用於提供對按鍵繫結的抽象。
  12. 使用上游的bevy_mod_picking庫,解鎖高效能、靈活的元素選擇。
  13. 實現Relations,並將其應用到 bevy_ui 中。

研究任務需要具備相關重要的設計專業知識,需要仔細考慮截然不同的提案,可能沒有明確的要求需要幹嘛:

  1. 定義並實現一個標準的UI widget部件抽象
    1. 可組合的:widget部件可以與其他部件組合以建立新的部件型別。
    2. 靈活的:我們應該能夠使用這種抽象來支援從按鈕到列表再到選項卡檢視的所有內容。
    3. 可配置的:使用者可以更改widget部件某些重要屬性來達成效果,而無需重複建立自己的型別。
    4. 或許可以對映到一個或多個Bevy實體,使用普通系統就可以對widget部件進行動態更新。
    5. 可在Bevy場景之間進行序列化。
  2. 弄清楚我們希望如何處理UI行為(和資料繫結),以避免因為使用ECS中的系統system而捲入其他的問題:
    1. 這是Alice建立一次性系統的最初動機。
    2. 事件冒泡和各種各樣(quillbevy_kot)的響應式UI嘗試(futures-signalsbevy_rxu4)似乎是有趣的潛在工具庫。
    3. 雖然並不總是直接適用,但Raph Levien在Xilem上的帖子很有趣,值得一讀。
    4. 資料模型是一項關鍵的挑戰:很容易陷入所有權問題。
  3. 弄清楚如何將資料繫結邏輯整合到Bevy場景中:
    1. Callback as Asset這個PR看起來很有希望。
    2. Vultix提出了一種用.bsn檔案定義資料繫結的語法和策略。
  4. 構建Bevy編輯器,並實現使用編輯器構建GUI場景的能力:
    1. 這裡存在一種“迴圈依賴”:bevy_ui 越好,編輯器構建起來就越容易(,編輯器構建越容易,使用 bevy_ui 構建GUI就越好用)

顯然,還有很多工作要做!但關鍵的是,並沒有什麼是完全不可能的。如果我們(Bevy開發者社群)能夠團結起來,一次一個穩步地解決這些問題,我們(Alice和Rose)真的認為 bevy_ui 總有一天會達到我們對引擎其他部分所期望的質量、靈活性和人體工程學的標準。

感謝您的閱讀:希望它具有教育意義、發人深省和/或有趣。如果你想在未來閱讀更多這樣的內容,可以考慮註冊我們的電子郵件列表或訂閱我們的RSS

譯者寫在最後

儘管有翻譯工具的幫助,但是為了讀懂原作者的意思,還是需要結合Bevy這個庫以及ECS概念。翻譯這篇文章也花了一定的時間,感謝讀者的耐心閱讀。

本文也會同步釋出到本人的部落格上:zhen.one(真一),歡迎小夥伴訪問。

相關文章