1. 程式人生 > >試玩 GOWOG ,初探 OpenAI(使用 NeuroEvolution 神經進化)與 Golang 多人線上遊戲開發

試玩 GOWOG ,初探 OpenAI(使用 NeuroEvolution 神經進化)與 Golang 多人線上遊戲開發

![](https://img2020.cnblogs.com/blog/436453/202101/436453-20210127130247840-652073298.gif) `GOWOG`: * 原專案:[https://github.com/giongto35/gowog](https://github.com/giongto35/gowog) * 我調整過的:[https://github.com/Kirk-Wang/gowog](https://github.com/Kirk-Wang/gowog) `GOWOG` 是一款迷你的,使用 Golang 編寫的多人 Web 遊戲。 ## 試玩遊戲 Demo:[http://game.giongto35.com](http://game.giongto35.com) ## 在 Agent 上的 AI 實驗 由於伺服器,客戶端和訊息是分離的,因此很容易與後端進行通訊。 此專案是用 `Python` 編寫的 `AI agent`,可以學習與環境的互動。 這個實驗是利用 `neuroevolution` (神經進化)在迷宮中尋找一條路徑。 油管 Demo:https://www.youtube.com/watch?v=pWbb1m91mhU ## 本地 Docker 執行 `run_local.sh` ```sh #!/bin/bash docker build . --build-arg HOSTNAME=localhost:8080 -t gowog_local|| exit docker stop gowog docker rm gowog docker run --privileged -d --name gowog -p 8080:8080 gowog_local server -prod client/build/ ``` 執行,我本地是 `Mac`: ```sh ./run_local.sh ``` 開啟 [http://localhost:8080](http://localhost:8080) ## 本地開發 遊戲包含兩部分:伺服器和客戶端。伺服器使用 `Golang`,客戶端使用 `Node.JS` 和 `Phaser` 遊戲引擎。 ### 伺服器 為少調整過的專案:[Kirk-Wang/gowog](https://github.com/Kirk-Wang/gowog) 我的本地環境是 `go 1.14`。 本地啟動: ```sh go run cmd/server/* ``` 伺服器將監聽 `8080`。 ### 客戶端 ```sh npm install npm run dev -- --env.HOST_IP=localhost:8080 # HOST_IP -> 伺服器地址 ``` 進入 [http://localhost:3000](http://localhost:3000) ### 注意 在開發過程中,客戶端在埠 `3000` 上執行,伺服器端在埠 `8080` 上執行。 在 `production` 和 `docker`環境中,已構建 `Client`,golang 伺服器將在同一埠 `8080` 上返回客戶端頁面。因此,如果我們執行 `docker` 環境,則遊戲將在瀏覽器中的 [http://localhost:8080](http://localhost:8080) 執行。 ### 通訊約定 伺服器和客戶端之間的通訊包基於 `protobuf`。 安裝 `protoc` 以生成 `protobuf`。 * http://google.github.io/proto-lens/installing-protoc.html 每次你在 `server/message.proto` 中有更改(package singature)時。請執行: ```sh cd server ./generate.sh ``` ## 遊戲前端設計 ![](https://img2020.cnblogs.com/blog/436453/202101/436453-20210127130343697-1369545353.jpg) 這個前端專案是基於: * https://github.com/RenaudROHLINGER/phaser-es6-webpack ```js ├── client │   ├── index.html │   ├── src │   │   ├── config.js: javascript config │   │   ├── index.html │   │   ├── main.js │   │   ├── sprites │   │   │   ├── Leaderboard.js: Leaderboard object │   │   │   ├── Map.js: Map object │   │   │   ├── Player.js: Player object │   │   │   └── Shoot.js: Shoot object │   │   ├── states │   │   │   ├── Boot.js Boot screen │   │   │   ├── const.js │   │   │   ├── Game.js: Game master │   │   │   ├── message_pb.js: Protobuf Message │   │   │   ├── Splash.js │   │   │   └── utils.js │   │   └── utils.js ``` 每個物件都是從 `Sprite` 繼承的類。 玩家包含 `shootManager`,每次射擊時,`shoot manager` 都會生成新的 `bullet`。 ## 遊戲後端設計方案 ### Components(元件) 遊戲中主要有 `5` 個實體。他們的狀態是私有的 | 實體 | 私有狀態 | | | ------ | ----- | ----------- | | `Client` | websocket.Conn | client hold 住 websocket 連線 | | `Hub` | Client | Hub 處理所有通訊, 包含所有 client 列表 | | `ObjManager` | Player, Shoot, ... | ObjManager 包含所有 Player 和 Shoot,處理遊戲邏輯 | | `Game Master` | ObjManager, Hub | Master object 由 ObjManager 和 Hub 組成 | ### Architecture(架構圖) ![](https://img2020.cnblogs.com/blog/436453/202101/436453-20210127130405831-1242664062.png) 不同的實體通過包裝在函式中的 `channel` 彼此呼叫。 ### Client 與 Server 互動設計方案 **Player connect(玩家連線)** ![](https://img2020.cnblogs.com/blog/436453/202101/436453-20210127130422682-423746001.png) **Player Disconnect(玩家斷開連線)** ![](https://img2020.cnblogs.com/blog/436453/202101/436453-20210127130437178-1254376293.png) **Client input(客戶端輸入)** ![](https://img2020.cnblogs.com/blog/436453/202101/436453-20210127130505521-1771590020.png) ### Profile `Profile` 是研究 `Golang` 效能並找出 `slow components` 的方法。執行伺服器時,可以使用標誌 `--cpuprofile` 和`--memprofile` 來配置 server。 ```sh cd server go run cmd/server/* --cpuprofile --memprofile ``` ### 程式碼結構 ``` ├── server │   ├── cmd │   │   └── server │   │   └── server.go: Entrypoint running server │   ├── game │   │   ├── common │   │   ├── config │   │   │   └── 1.map: Map represented 0 and 1 │   │   ├── gameconst │   │   ├── game.go: Game master objects, containing logic and communication │   │   ├── mappkg │   │   ├── objmanager │   │   ├── playerpkg │   │   ├── shape │   │   ├── shootpkg │   │   ├── types.go │   │   └── ws │   │   ├── wsclient.go │   │   └── wshub.go │   ├── generate.sh: Generate protobuf for server + client + AI environment │   ├── message.proto │   └── Message_proto │   └── message.pb.go ├── Dockerfile └── run_local.sh ``` ## AI 訓練設計方案 此倉庫包含遵循 `openAI Gym` 格式和訓練指令碼的 `CS2D` 環境。 訓練指令碼使用 `NeuroEvolution(神經進化)`在迷宮中找到到達目的地的最短路徑。 https://www.youtube.com/watch?v=pWbb1m91mhU ### 執行 按照的說明執行 `gowog` 環境。即本地 Docker 執行: ```sh ./run_local.sh ``` 使用 `virtualenv` 設定 `python3` 虛擬環境(直接用 Docker 吧~)。 * 安裝 `requirements.txt` 所包含的庫。 執行訓練指令碼 ```sh python train_ga.py -n save_file_name ``` `save_fie_name` 是儲存權重(`weights`)的地方。 在下一次,如果我們指定了一個現有的檔案,它將繼續從該檔案的最後一次執行中的權重(`weights`)進行訓練。 ### Genetic Algorithm(遺傳演算法) `_cs2denv_ga.py 的實現_` 基於機器學習的目的,`CS2D Agent` 是在 `CS2D` 上構建的。 它遵循 `openAI gym`,支援 `agent` 的基本方法,包括:`reset()`、`step()`、`observation_space` 和`action_space`。 `ObservationSpace` 是一個一維陣列,它由來自伺服器的 `update_player` 訊息構造而成 1. Player position(`玩家位置`), player size(`玩家大小尺寸`), number of columns(`列數`), number of rows(`行數`), block width(`塊寬度`), block height(`塊高度`) 2. 到左,右,上,下到最近 block(`塊`)的距離。此輸入是為了避免碰撞 3. 玩家在二進位制塊地圖(binary block map)中的位置。地圖是 `0` 和 `1` 的 `2` 維陣列(`0` 為空,`1` 為塊) 4. binary block map 獎勵是 `1 / distance(目標的距離)`。如果 `agent` 接近目標 `100` 點,那麼獎勵就是 `1`,情節結束。 ### NeuroEvolution(神經進化) `_train_ga.py 的實現_` 神經網路(`Neural Network`)通過使輸入(觀察空間)通過神經網路來獲得最佳動作。 `NeuroEvolution`(神經進化)是使用進化演算法不斷改進人工神經網路的AI。對於每次迭代(生成),程式將基於前一次迭代中的最佳設定生成一組新的神經網路權重。 由先前的 `NN(神經網路)` 生成一個 `NN` 的過程叫做 `Mutate`,它給神經網路中的每個引數新增隨機噪聲。 一個特別的改進是,我們只儲存應用於神經網路的噪聲種子列表,而不是儲存所有的代權值。因為在同一個種子下,所有的隨機化都是相同的,所以一個種子可以代表一個網路的突變運算元。我們不需要保留每一代的所有權值,我們只需要儲存一組從開始到當前一代的種子,然後從這組種子中重新構造權值來得到所有神經網路的權值。 程式碼是基於 `Maxim Lapan` 的 `"Deep Reinforcement Learning Hands-On"` * https://github.com/PacktPublishing/Deep-Reinforcement-Learning-Hands-On/blob/master/Chapter16/04_cheetah_ga.py ``` 我是為少。 微信:uuhells123。 公眾號:黑客下午茶。 謝謝點贊支援