的前世今生)
楔子一個時代的印記如果你是一位Unity老開發(fā)者一定對下面這幾行代碼熟悉得像自己的手指紋floathInput.GetAxis(Horizontal);floatvInput.GetAxis(Vertical);if(Input.GetKeyDown(KeyCode.Space))Jump();if(Input.GetMouseButtonDown(0))Fire();它們樸實、直接、簡單粗暴——就像老式錄音機上的物理按鍵你按下去它就咔噠一聲給你回應(yīng)。這套代碼背后的系統(tǒng)正是Unity從2005年誕生起就一直陪伴我們的舊輸入系統(tǒng)Legacy Input Manager。它見證了《爐石傳說》的誕生陪伴了《紀念碑谷》的成長撐起了《原神》早期版本的輸入邏輯。它像一位話不多但可靠的老朋友二十年來默默地為整個Unity生態(tài)服務(wù)。但如今Unity官方已經(jīng)推出了全新的Input System Package并在文檔里越來越頻繁地把舊系統(tǒng)標記為Legacy——這個詞從來都不是褒義。舊輸入系統(tǒng)正在緩緩走向它的黃昏。在這個交接的時代讓我們停下匆忙的腳步回望一下這位老朋友。它有過怎樣的輝煌它優(yōu)雅在哪里又為何終將謝幕第一章老朋友的自我介紹Unity舊輸入系統(tǒng)的核心是一個靜態(tài)類UnityEngine.Input。它的設(shè)計哲學可以用四個字概括簡單直接。它把所有輸入相關(guān)的功能一股腦塞進這一個類里讓開發(fā)者可以在任何腳本的任何位置隨時隨地地調(diào)用。你不需要初始化、不需要訂閱事件、不需要引用任何對象——它就在那里永遠待命。它主要提供三大類API第一類按鍵狀態(tài)查詢——最常用的三劍客Input.GetKey(KeyCode.W);// W鍵當前是否被按住Input.GetKeyDown(KeyCode.W);// W鍵是否在這一幀被按下Input.GetKeyUp(KeyCode.W);// W鍵是否在這一幀被松開這三個方法的語義清晰得讓人感動“持續(xù)按住”、“剛剛按下”、“剛剛松開”。它精準地對應(yīng)了游戲邏輯中最常見的三種輸入需求——移動持續(xù)按住、跳躍剛剛按下、蓄力釋放剛剛松開。第二類鼠標輸入——像素級的精確控制Input.mousePosition;// 鼠標當前屏幕坐標Input.GetMouseButton(0);// 鼠標左鍵是否按住Input.GetMouseButtonDown(0);// 鼠標左鍵是否按下Input.mouseScrollDelta;// 滾輪滾動量對于所有RTS、MOBA、點擊冒險游戲來說這幾個API就是它們的生命線。第三類虛擬軸——那個最優(yōu)雅的抽象Input.GetAxis(Horizontal);Input.GetAxis(Vertical);Input.GetAxis(Mouse X);虛擬軸——這可能是舊輸入系統(tǒng)里最閃光的一個設(shè)計。它把物理按鍵、手柄搖桿、鼠標移動等各種輸入源統(tǒng)一抽象成一個介于-1到1之間的浮點數(shù)。開發(fā)者不需要關(guān)心玩家用什么設(shè)備只需要問一句玩家想往哪個方向走Unity就會給你答案。第二章Input Manager——那個藏在Project Settings里的老倉庫打開Unity編輯器的Edit Project Settings Input Manager你會看到一份長長的清單Horizontal、Vertical、Fire1、Fire2、Fire3、Jump、Mouse X、Mouse Y、Mouse ScrollWheel、Submit、Cancel……這就是舊輸入系統(tǒng)的配置中心。每一個條目Axis都是一份精心撰寫的檔案記錄著Name: 這個軸叫什么名字字符串 Negative Button: 觸發(fā)-1的按鍵 Positive Button: 觸發(fā)1的按鍵 Alt Negative: 備用觸發(fā)-1的按鍵 Alt Positive: 備用觸發(fā)1的按鍵 Gravity: 無輸入時回落到0的速度 Sensitivity: 有輸入時靠近目標的速度 Dead: 死區(qū)大小 Snap: 反向按鍵時是否瞬間歸零 Invert: 是否反轉(zhuǎn) Type: 輸入類型按鍵/鼠標/手柄軸 Axis: 對應(yīng)手柄的哪根軸 Joy Num: 對應(yīng)哪一號手柄這份配置的美妙之處在于它把邏輯意圖和物理按鍵解耦了。你的代碼只需要說我想讀Horizontal的值至于Horizontal到底對應(yīng)A/D、方向鍵、還是手柄左搖桿那是配置的事。這個設(shè)計放在2005年絕對是超前的——那時候大部分游戲引擎還在硬編碼按鍵映射Unity已經(jīng)在教開發(fā)者輸入抽象的哲學了。第三章老朋友的性格——它的優(yōu)點在這套簡單直接的接口背后舊輸入系統(tǒng)有幾個被無數(shù)開發(fā)者深愛的品質(zhì)優(yōu)點一零門檻的學習曲線一個剛接觸Unity的新手學會控制角色移動只需要五分鐘voidUpdate(){floathInput.GetAxis(Horizontal);floatvInput.GetAxis(Vertical);transform.Translate(h*speed*Time.deltaTime,0,v*speed*Time.deltaTime);}不需要理解事件、訂閱、綁定、動作圖——你就是Update里問一句Unity答一句。這種命令式輪詢的編程模型與新手的直覺高度契合。優(yōu)點二無處不在的可用性Input是一個靜態(tài)類意味著你可以在任何地方、任何時候調(diào)用它。無論是在MonoBehaviour里、在協(xié)程里、在編輯器腳本里——它永遠待命隨叫隨到。這種上帝視角的可用性雖然違背了很多現(xiàn)代軟件工程的原則比如依賴注入、可測試性但對于大部分中小型項目來說簡單就是美。優(yōu)點三性能足夠優(yōu)秀Input.GetKey的本質(zhì)是一次查表操作O(1)復雜度。即使你在Update里瘋狂調(diào)用幾十次性能開銷也幾乎可以忽略。雖然GetAxis因為要做字符串查表和插值計算略微昂貴但也在可接受范圍內(nèi)。對于絕大多數(shù)游戲來說舊輸入系統(tǒng)的性能從來不是瓶頸。優(yōu)點四跨平臺一致性舊輸入系統(tǒng)對開發(fā)者屏蔽了大量平臺差異。你在Windows上寫的Input.GetKey(KeyCode.A)在Mac、Linux、Android、iOS上都能工作。雖然手柄映射有時會有點小坑但整體的跨平臺體驗相當絲滑。第四章老朋友的皺紋——它的局限然而隨著時間推移舊輸入系統(tǒng)的皺紋也越來越明顯。當游戲工業(yè)進入手柄、觸摸屏、VR控制器、體感設(shè)備百花齊放的時代這位老朋友開始有些力不從心。局限一字符串命名的脆弱性Input.GetAxis(Horizontal);// 正確Input.GetAxis(Horizental);// 拼錯了編譯不報錯運行時靜默失效用字符串作為API的參數(shù)是舊輸入系統(tǒng)最大的原罪之一。IDE不會給你自動補全編譯器不會幫你檢查錯別字重構(gòu)工具無法安全地重命名。一個拼寫錯誤可能讓你調(diào)試半天。局限二輪詢模型的低效舊輸入系統(tǒng)本質(zhì)上是輪詢式的——你必須在每一幀的Update里主動詢問按鍵狀態(tài)。這意味著如果你忘了調(diào)用就會漏掉事件如果一幀內(nèi)按鍵快速按下又松開可能會被完全忽略無法感知按鍵的具體時序信息對于快節(jié)奏的格斗游戲需要精確的輸入時序和音樂游戲需要精確到毫秒的按鍵時間戳輪詢模型的精度就有些捉襟見肘了。局限三對現(xiàn)代設(shè)備的支持不足舊輸入系統(tǒng)的模型是圍繞鍵盤 鼠標 傳統(tǒng)手柄設(shè)計的。當我們面對觸摸屏多點觸控、手勢識別VR控制器六自由度追蹤、扳機壓力、握持感應(yīng)體感設(shè)備加速度計、陀螺儀自適應(yīng)手柄PS5的自適應(yīng)扳機、觸覺反饋……舊輸入系統(tǒng)就顯得捉襟見肘了。它有一些簡陋的API比如Input.touches、Input.acceleration但整體架構(gòu)沒有為這些新型輸入設(shè)計。局限四運行時重綁定的困難現(xiàn)代游戲幾乎都要提供按鍵自定義功能讓玩家可以自由重新映射按鍵。但在舊輸入系統(tǒng)中Input Manager的配置在編輯器里定義、編譯進游戲后就無法修改。你想讓玩家自定義按鍵只能自己在代碼里維護一套映射表然后寫一堆膠水代碼去橋接——非常麻煩。局限五多玩家支持的缺失想做本地多人游戲想讓玩家1用鍵盤、玩家2用手柄舊輸入系統(tǒng)完全沒有為此設(shè)計。你只能自己實現(xiàn)設(shè)備識別 輸入分發(fā)的邏輯寫著寫著你就會懷疑人生。第五章一個時代的謝幕正是因為這些局限Unity在2019年推出了全新的Input System Package。新系統(tǒng)采用事件驅(qū)動架構(gòu)、支持Action-based的輸入綁定、提供運行時可重映射的能力、原生支持多設(shè)備/多玩家、對觸摸屏、VR、手柄都有一等公民的待遇。技術(shù)演進的車輪滾滾向前舊輸入系統(tǒng)正被慢慢推向歷史的邊緣。但請不要因此看輕它。在過去的將近二十年里正是這套簡單直接的舊系統(tǒng)托起了整個Unity生態(tài)的輸入體驗。從獨立開發(fā)者的第一個小游戲到手游工廠的爆款作品再到主機大作的復雜交互——它都曾在幕后默默地工作著。尾聲向那個時代致敬如果你今天在Unity里寫下floathInput.GetAxis(Horizontal);那么恭喜你你正在使用一個跨越了20年、被數(shù)億開發(fā)者敲下過、被無數(shù)玩家的手指觸發(fā)過的接口。它不完美它有它的時代局限但它承載著一整個游戲開發(fā)時代的記憶?;蛟S在不久的將來我們會全面轉(zhuǎn)向新的Input System那個更強大、更現(xiàn)代、更靈活的系統(tǒng)。但請你在告別之前為這位老朋友留一分敬意——它用最簡潔的方式教會了幾代開發(fā)者什么叫做輸入抽象什么叫做跨平臺什么叫做夠用就好。技術(shù)會迭代接口會淘汰但那些樸素而深刻的設(shè)計哲學會一直流傳下去。再見了Legacy Input Manager。謝謝你陪我們走過這段路。