試玩 GOWOG ,初探 OpenAI(使用 NeuroEvolution 神經進化)與 Golang 多人線上遊戲開發
阿新 • • 發佈:2021-01-27
![](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。
公眾號:黑客下午茶。
謝謝點贊支援