*本文只在機核發布
我所製作的《多元窗口》大概率是一個前人未曾涉足的遊戲領域,光是在代碼方面就有著不小的開拓難度,更別說遊戲內容本身的設計了。在機核Booom-lab做出這款遊戲的原型時,就深感這套方案實現的不易,所以也將當時的版本開源並做了教程,希望有人能接替我的成果,那時的我是做不動了。不過後續我並沒有發現有誰使用了這套方案,然後我還在某個比賽上拿了一個獎,所以我決定再次重啟該項目,並且一切都按照我個人能承擔的最低成本去做。
現在遊戲已經在Steam上發佈試玩版了,搜索《多元窗口》就可以找到。當然這個版本絕對算不上多麼細緻,完成度也很有限,我也想未來繼續更新這個試玩版。不過眼下,這套程序實現方案已經極大的壓榨了我的精力,能做到這樣我也就暫且滿意了。秉持著互聯網的分享精神,也決定來機核社區向各位開發者分享一些很可能以前從來沒有人研究過的“怪東西”。
Steam對遊戲進程的檢測
與Godot的單一進程多窗口不同,我的遊戲中需要玩家打開多個遊戲進程,實打實的需要玩家啟動多次遊戲,而這與Steam的模式兼容性極差,經過我的研究,我找到了一些很怪的方案。
在開啟遊戲的時候,Steam會檢測開啟的進程與其所有子進程,這意味著在通過Steam開啟的遊戲中,直接利用代碼去開啟新遊戲時,新開啟的遊戲會成Steam開啟的遊戲的子進程,也會被Steam管理。這一問題甚至還導致了即使遊戲關閉,Steam也認為遊戲在運行,必須重啟才能解決,導致遊戲時長異常(甚至突破50小時)。
![](https://image.gcores.com/295f88ba94c50506796cce1692957e6a-1824-749.png)
關於這個問題,可能有人會想,通過CMD或者PowerShell運行是否可行,先運行一個其他的程序,再通過其他程序中轉行不行。答案是行不通,即使是CMD、PowerShell還是其他的程序,只要這個進程是由當前遊戲打開的,那麼都會成為當前遊戲的子進程,然後新開啟的遊戲一樣會成為子進程,從而被Steam檢測到。
問題的關鍵是“如何讓一個進程創建一個不是子進程的進程”,這個問題估計AI都給不出答覆,我最後是在stackoverflow上找到了一段相關代碼。這段代碼利用了ManagementClass,通過DETACHED_PROCESS這個標記去讓系統創建新的進程。並且這個功能似乎不能在Unity中使用,我通過一個單獨的C#項目復刻了這段C++代碼,然後將編譯後的文件放入我的遊戲項目之中,在遊戲中執行該文件,去創建不是子進程的新的遊戲進程。
代碼出處:https://stackoverflow.com/questions/12068647/creating-a-new-process-thats-not-a-child-of-the-creating-process
![](https://image.gcores.com/758446c10d31924fb709db032dc214ce-830-736.png)
本地聯網的應用
之前有朋友把遊戲給某遊戲大廠的員工試玩,對方還以為這個遊戲的進程溝通是利用了共享內存或者管道通信之類的方法。對於操作系統來說,那些方法確實很管用,但是對於Unity引擎來說,使用進程通信還是太複雜了,對於開發的效率來說很難受。最終我使用了聯網架構,通過現有的Netcode組件在127.0.0.1本地迴環地址中進行聯機,實現了多個窗口的信息傳遞。把複雜的進程溝通問題轉化為簡單的多人遊戲製作(不過目前這套方案還存在一定的延遲,我不理解為什麼本地自己聯機還會有延遲,我還在研究如何優化)。
![](https://image.gcores.com/7e15fea58a23b070fcc408afb43fa8b6-735-1086.png)
所以現在,遊戲進程中有一個進程是主機,其他都是客戶端。但是打開一個新進程的時候,要如何知道這個新進程該是主機還是客戶端呢。我用了一個十分簡單粗暴的方案,就是先作為客戶端進行鏈接,如果連上了,那就作為客戶端待著吧。如果發現沒連上,那就作為主機開啟新的連接。現在想來還是挺變態的方案,其實也可以根據名字檢測進程,根據當前進程數量來判斷主機還是客戶端,但是這樣就會導致一個更變態的東西消失了——不同遊戲之間的連接。經過我的測試,只要網絡部分的架構一致,即使是不同版本的遊戲甚至是完全不同的遊戲,他們之間都是可以相連的。我還不確定這部分能做到什麼份上,但起碼我不想丟掉這份“可能性”,希望能在未來實現這樣的玩法。
全局按鍵檢測
眾所周知遊戲應該只會檢測在遊戲中輸入的按鍵,在遊戲外輸入的按鍵是不會被檢測的,而這對於多窗口遊戲來說可不是好事。為此,我找到了一個檢測玩家全局按鍵輸入的方案,註冊了Windows系統的鍵盤鉤子,通過更加底層的系統鉤子來監聽玩家的鍵盤。雖然這會導致即使玩家不在專注遊玩遊戲時,比如開著遊戲但是切窗口聊天,也會觸發我的遊戲中的鉤子事件,但這確實是一個解決多窗口之間按鍵交互的問題。
S4U同款賽博嘴替?
除了全局按鍵檢測,其實我還實現了一個更加獨特的東西,攔截並且模擬按鍵輸入。也是鍵盤鉤子,不過加上了一點額外的檢測,如果我發現現在的輸入是玩家的輸入,就禁止這個輸入在系統中被激活,然後利用keybd_event執行一個模擬輸入。從某種意義上來說,這有點像是外掛程序的原理。而機核發行的S4U中,我看到這個遊戲中輸入的玩法感覺很有意思,我突然想到,其實我可以在玩家的電腦系統中實現這裡的功能。
![](https://image.gcores.com/3b6f131ae2f751d020e169012032547a-1472-1375.png)
設想一下,一個玩家剛玩了我的遊戲並關閉,但是我的遊戲悄咪咪的留了一個“賽博嘴替.exe”進程沒關,然後再利用一些比較複雜的黑科技,檢測到了玩家正在和某人聊天。這時候程序激活,玩家按下按鍵時,打出來的字都不是他想要的,而是提前設計好的。等會,我是說,我在做的其實是一款聯網遊戲,不過是把聯網部分改成本地而已。那如果我做了遠程聯網功能,並且由我這裡擔任服務器,我來決定玩家怎麼罵(現實裡的)公司領導,那麼我不就可以真的在現實裡玩遊戲,成為人們的賽博嘴替了嗎?
天哪,我都不敢想Steam會不會給我這個遊戲過審了,這就是一個赤裸裸的偽裝成病毒的遊戲,而且我想誰會不願意給一個Unity遊戲開放管理員權限呢。所以在此警示各位,Unity遊戲很有可能也不安全,甚至比你我想的都更有可能是一個木馬病毒。(我本人還是想做正經遊戲的,以上內容暫時還不會出現在《多元窗口》與其試玩版中,我保證)
痛苦的調試與開發
還是收回剛才狂妄的病毒想法吧,如果遊戲不做好玩,又怎麼吸引玩家來下載這個病毒呢。額,我是說我要做一款好遊戲,不應該去想什麼病毒不病毒的。但,在Unity裡做多窗口遊戲就是純純的折磨。傳統的遊戲製作只需要點擊一下播放按鈕,就可以直接在編輯器裡看到遊戲預覽了,但我做的可是多窗口、多進程遊戲。每次修改調試,我都必須完全導出遊戲,忍受這個該死的慢的要死的build過程(咬牙切齒),在新的窗口中檢查遊戲內容有沒有bug。這也就是我開發進度緩慢的最大原因了,我現在一直都在用這樣的土辦法進行調試,鬼知道我到底導出了幾百次還是幾千次這個遊戲。
![](https://image.gcores.com/265b82578a4fd5684f553dce9d5eb3f8-867-352.png)
![](https://image.gcores.com/3f5ee600b4213eb63cad5e07c9cc1eb3-786-329.png)
我目前用到了《Cato》開發者分享過的 InGame Debug Console 插件,這確實很好用,完全符合我的遊戲。不過我其實突然想起來,似乎HotReload插件也具有著遠程連接的功能,我打算接下來研究下能不能不導出遊戲,直接預覽更改。
還有就是在Steam中預覽更改,其實不需要上傳、打包、再在Steam裡更新,直接把導出的遊戲拷入到本地的Steam遊戲安裝文件夾裡覆蓋,就可以直接測試了,也是“俺尋思”的簡單有效做法。哦對了,我還給SteamAPI做了一個編輯器判斷,如果是編輯器,則不激活SteamAPI,這樣就不會在開發的時候導致Steam認為遊戲正在運行了。
總而言之,言而總之,這裡就是《多元窗口》試玩版中一小部分的怪東西了。我兜裡還有更多更有趣的黑科技,不過現在還不是時候。若是各位感興趣,還請務必打開Steam,搜索“多元窗口”,下載試玩版玩一玩,加個願望單甚至給試玩版寫點評測都是很好的。如果遊戲反響不錯,我也就有動力去研究更加有意思的東西,在未來為各位分享更多內容。
在電子遊戲邊界的開拓之路上,總有未曾有人見過的東西值得分享。