背景
Ink 是 React 在命令行中渲染系統(tǒng)的一個實(shí)現(xiàn), 在 GitHub 上已經(jīng)有 1w+ Star. 看著蠻好玩, 因此嘗試著寫了一個五子棋游戲, 經(jīng)過若干天的劃水, 終于初見成效了!
先來看個演示動畫(Gif 太大這里放不下, 請移步 GitHub 觀看):
需要聲明的是: 這個客戶端我已經(jīng)開源在了 GitHub 上, 地址是 https://github.com/acrazing/gomoku-terminal, 但是這是一個在線游戲的客戶端, 因?yàn)樯虡I(yè)原因, 服務(wù)端代碼沒有開源, 所以這篇文章主要描述 Ink + React 構(gòu)建客戶端的過程, 后續(xù)如果有機(jī)會的話會考慮寫一篇文章來聊聊服務(wù)端的架構(gòu)與思路.
如何使用
首先需要你在本地安裝 node + npm, 然后使用 npm 全局安裝本項(xiàng)目的 npm 包:
npm i -g gomoku-terminal
這個時候全存在一個命令行入口 gomoku
, 其使用方法是:
$ gomoku --help
gomoku [options]
Options:
--version Show version number [boolean]
--api the api host [string] [default: "http://23.106.139.99:5001"]
--store the config & session store file
[string] [default: "~/.gomoku-terminal.json"]
--help Show help [boolean]
如果只啟動一個實(shí)例, 則不需要傳遞任何參數(shù)在命令行中直接調(diào)用即可, 但是如果要啟動多個實(shí)例, 則需要傳入 --store
參數(shù), 指向不同的文件名, 來儲存會話信息.
第一次啟動或者 token 過期時, 會首先進(jìn)入登錄界面:
這個時候你需要使用方向鍵來控制焦點(diǎn), 然后輸入用戶名和密碼再將焦點(diǎn)移動到 Go 上按回車鍵登錄, 或者不輸入用戶名和密碼直接按 Anonymous 進(jìn)行匿名登錄, 目前注冊接口似乎有問題, 只支持匿名登錄.
登錄成功后, 會跳轉(zhuǎn)到房間列表頁面:
這個頁面會展示5個房間, 你可以使用上下鍵來選擇一個房間進(jìn)入(如果有的話), 或者點(diǎn)擊 New 來創(chuàng)建一個房間并進(jìn)入. 按 R 可以手動刷新房間列表.
進(jìn)入房間后, 會自動跳轉(zhuǎn)到房間頁面:
這個時候你首先需要按 Ready 鍵(或者按鍵盤 R)來準(zhǔn)備, 長時間未準(zhǔn)備會被踢出, 雙方均準(zhǔn)備后游戲自動開始. 這個時候如果該你落子的話可以通過方向鍵來選擇要落子的位置, 然后按回車落子, 長時間未落子會自動判負(fù):
技術(shù)實(shí)現(xiàn)
主要有兩個難點(diǎn):
一個是鍵盤控制, 這個 ink 并沒有提供一個有效的方案來進(jìn)行操作, 只提供了一個 StdinContext
來暴露了標(biāo)準(zhǔn)輸入, 而通過按鍵來控制焦點(diǎn)則需要自行實(shí)現(xiàn), 本項(xiàng)目中的實(shí)現(xiàn)是通過一個 Focusable
組件來實(shí)現(xiàn)的, 具體可以查看該文件: Focusable.ts.
另一個是性能問題, Ink 的組件每一次刷新(render)都會觸發(fā)一次全量渲染, 這個和 react-dom
不一樣, react-dom
做了大量的優(yōu)化(主要是 diff 算法與 patch update). 在繪制棋盤界面的過程中, 至少需要有255(15 * 15)個元素, 因此必須要嚴(yán)格控制每個 Piece 的刷新過程, 絕對不能出現(xiàn)一個狀態(tài)變更導(dǎo)致所有 Piece 都渲染的情況, 因此只能通過元素局部狀態(tài)來控制, 而不能通過 props.
此外, 本項(xiàng)目中使用 mobx
來管理狀態(tài), mobx-sync
來持久化狀態(tài)到文件系統(tǒng), 還實(shí)現(xiàn)了一個快捷鍵系統(tǒng), 具體可以查看該文件: KeyboardReceiver.
TODO
- 優(yōu)化性能: 目前的渲染性能實(shí)在太糟糕, 只能說是勉強(qiáng)能用的狀態(tài), 這個需要 ink 自身做大量的優(yōu)化
- 優(yōu)化體驗(yàn): 目前只完成了基礎(chǔ)的交互功能, 但是外觀相當(dāng)丑
源代碼地址: https://github.com/acrazing/gomoku-terminal
npm 包地址: https://www.npmjs.com/package/gomoku-terminal