昨天提到說,我覺得 Rive 的有限狀態機是非常糟糕的東西,我的意思是說,Rive 官方引入了不必要的複雜度,就我們自己的經驗來說,在實務上造成了很多困擾。
當然還是要先打個預防針,以下的想法,是建立在 Rive 的定位是簡單快速做出漂亮的動畫,以及 Rive 省下的成本應該多做這種動畫,這兩個前提上,再往下延伸的。所以如果不同意這兩個前提的話,以下的想法就沒什麼價值,上樑不正下樑歪的概念。
State Machine, State Machine Input, View Model, Data Binding 的關係,因為時間跟篇幅的關係,有興趣的話再去問 AI 就好。我想說的是,i dot car。

就好像 Rive 官方不怎麼在乎功能面或工程面的東西一樣,身為工程師,我只在乎要 call 哪一個 API 可以讓 Rive 檔動起來,至於那個 API 叫做 State Machine Input 還是 Data Binding 還是什麼 AbaAbaAba 對我來說根本不重要。
好吧換個比較委婉的說法,我們當然可以理解,越往底層走,這些底層的名詞或是概念的確有區別實益,而且對抽象或可複用性來說也很有價值,但對比較外層的使用者來說,盡量把這些東西封裝起來避免曝露,會減少非常多的複雜度,進而減少非常多不必要的溝通成本與浪費。
例如就我們所知,就算我們團隊用了 Rive 這麼久,也不太有人知道 State Machine 跟 State Machine Input 到底差在哪,雞同鴨講問 A 答 B 張飛打岳飛的情況非常常見。畢竟現代人多少都有一點 ADHD,再加上都用 AI 寫文章,所以文字跟講話沒那麼精確也是很正常的。
當然身為團隊的一員,我們還是要盡力加強自己的邏輯與表達能力,但 Rive 官方還是可以盡量降低這些概念的複雜度,這兩者並不衝突。對工程師來說,我們還是比較想 Code to an interface, not an implementation.
另外一個問題是,如果要開放客製化的話,動畫很容易變成不有限的狀態。例如動畫裡面要插入文字,文字內容要從 API 來,這是一個常見的 promote 需求。或是想把動畫換個顏色,換個字體什麼的,此時這些文字、顏色、字體,嚴格說起來,都不是有限的狀態。
當然就跟 functional programming 一樣,believers 會跟我們說啊雖然 APP 還是要打 API 讀 DB 沒錯,但我們把打 API 這件事包成一隻 function return 出去,所以這隻 function 本身還是沒有 side effect,他還是 pure function。Rive 官方對這種不有限的狀態,也是很優雅的把他們包成可以 Binding 的 Data 再拋出去,再跟我們說喔我的狀態本身還是有限的喔,那些無限的狀態只是包在 Data Binding 這層抽象後面而已。
這有點像 Vuex & Pinia,一開始說什麼單向資料流 state 改變 view view 觸發 action action 改變 state state 改變 view 絕對不能直接改變 state 一定要透過 mutation 不然會很難追蹤然後還有分什麼 mutation action 喔什麼同步要用 mutation 非同步要用 action。結果現在 Pinia 還是開放可以不透過 action 改變 state。
當然透過 action 改 state 是一個好習慣,要盡量這樣寫比較好,但有沒有必要把 count++ 或是動畫插入文字這件事引入一堆概念跟名詞弄的這麼複雜,這是兩件事,特別是對 Rive 這種定位在簡單快速做出漂亮的動畫的工具而言。
又不小心扯得太遠了,再回到文章開頭提到的兩個前提,如果認同那兩個前提的話,那在有限狀態機以及這一連串阿哩阿咂的名詞面前,我個人的建議是……不要太花時間在這上面。我們只需要一組 API 來操作動畫,至於這組 API 背後的原理,有興趣的話再深入研究。
自己學 Rive 的時候是這樣,對外溝通的時候也是這樣,不要太糾結大家講的到底是 State Machine 還是 State Machine Input 還是什麼東西,大家開開心心的上班,東西能在期限內做出來賺錢,可能還是比較重要。Rive 是個很好用的工具,適當的忽略一些坑,等以後官方整理好再回頭來看,應該會是更有效益的事。
