使用 ink + react 製作一個命令列的線上五子棋遊戲客戶端
背景
Ink 是 React 在命令列中渲染系統的一個實現, 在 GitHub 上已經有 1w+ Star. 看著蠻好玩, 因此嘗試著寫了一個五子棋遊戲, 經過若干天的划水, 終於初見成效了!
先來看個演示動畫(Gif 太大這裡放不下, 請移步 GitHub 觀看):
需要宣告的是: 這個客戶端我已經開源在了 GitHub 上, 地址是 https://github.com/acrazing/g... , 但是這是一個線上遊戲的客戶端, 因為商業原因, 服務端程式碼沒有開源, 所以這篇文章主要描述 Ink + React 構建客戶端的過程, 後續如果有機會的話會考慮寫一篇文章來聊聊服務端的架構與思路.
如何使用
首先需要你在本地安裝 node + npm, 然後使用 npm 全域性安裝本專案的 npm 包:
npm i -g gomoku-terminal
這個時候全存在一個命令列入口 gomoku
, 其使用方法是:
$ gomoku --help gomoku [options] Options: --versionShow version number[boolean] --apithe api host[string] [default: "http://23.106.139.99:5001"] --storethe config & session store file [string] [default: "~/.gomoku-terminal.json"] --helpShow help[boolean]
如果只啟動一個例項, 則不需要傳遞任何引數在命令列中直接呼叫即可, 但是如果要啟動多個例項, 則需要傳入 --store
引數, 指向不同的檔名, 來儲存會話資訊.
第一次啟動或者 token 過期時, 會首先進入登入介面:
這個時候你需要使用方向鍵來控制焦點, 然後輸入使用者名稱和密碼再將焦點移動到 Go 上按回車鍵登入, 或者不輸入使用者名稱和密碼直接按 Anonymous 進行匿名登入, 目前註冊介面似乎有問題, 只支援匿名登入.
登入成功後, 會跳轉到房間列表頁面:
這個頁面會展示5個房間, 你可以使用上下鍵來選擇一個房間進入(如果有的話), 或者點選 New 來建立一個房間並進入. 按 R 可以手動重新整理房間列表.
進入房間後, 會自動跳轉到房間頁面:
這個時候你首先需要按 Ready 鍵(或者按鍵盤 R)來準備, 長時間未準備會被踢出, 雙方均準備後遊戲自動開始. 這個時候如果該你落子的話可以通過方向鍵來選擇要落子的位置, 然後按回車落子, 長時間未落子會自動判負:
技術實現
主要有兩個難點:
一個是鍵盤控制, 這個 ink 並沒有提供一個有效的方案來進行操作, 只提供了一個 StdinContext
來暴露了標準輸入, 而通過按鍵來控制焦點則需要自行實現, 本專案中的實現是通過一個 Focusable
元件來實現的, 具體可以檢視該檔案: Focusable.ts .
另一個是效能問題, Ink 的元件每一次重新整理(render)都會觸發一次全量渲染, 這個和 react-dom
不一樣, react-dom
做了大量的優化(主要是 diff 演算法與 patch update). 在繪製棋盤介面的過程中, 至少需要有255(15 * 15)個元素, 因此必須要嚴格控制每個 Piece 的重新整理過程, 絕對不能出現一個狀態變更導致所有 Piece 都渲染的情況, 因此只能通過元素區域性狀態來控制, 而不能通過 props.
此外, 本專案中使用 mobx
來管理狀態, mobx-sync
來持久化狀態到檔案系統, 還實現了一個快捷鍵系統, 具體可以檢視該檔案: KeyboardReceiver .
TODO
- 優化效能: 目前的渲染效能實在太糟糕, 只能說是勉強能用的狀態, 這個需要 ink 自身做大量的優化
- 優化體驗: 目前只完成了基礎的互動功能, 但是外觀相當醜
原始碼地址: https://github.com/acrazing/g...
npm 包地址: https://www.npmjs.com/package...