Live Coding Street Fighter 2 実施方法 

# これはなに？
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Live Coding Street Fighter 2 (for Abpro&#39;19) <a href="https://t.co/MNo29trkMP">https://t.co/MNo29trkMP</a> <a href="https://twitter.com/YouTube?ref_src=twsrc%5Etfw">@YouTube</a>さんから</p>&mdash; nobu_e753 (@nobu_e753) <a href="https://twitter.com/nobu_e753/status/1180473032436936704?ref_src=twsrc%5Etfw">October 5, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

Live codingでスト２キャラクターを操作し戦うものです．

俺より強い奴（プログラマー）に会いに行く！ 
IT系勉強会後の宴会に良さそうです．

本記事はその実施方法解説記事です．

# ハックについて
明治大学で開催された[ABPro 2019](https://abpro.jp/2019/)（「普通じゃないプログラム作品」の発表会）にて，[津田塾大・栗原一貴先生](https://www.unryu.org/)より発表のあったゲームハックです．

プログラマブルゲームコントローラー [GameControllerizer](https://sites.google.com/view/gamecontrollerizer) を使うことで，自身のプログラム（javascript）からのキャラクター操作を可能にしています．

# 必要な機材
- PC（コーディング用）
- [GameControllerizer](https://sites.google.com/view/gamecontrollerizer/w-raspi)（プログラマブル
ゲームコントローラー）
- [Raspberry Pi Zero W](https://www.raspberrypi.org/products/raspberry-pi-zero-w/)（↑と組み合わせて使います）
- ゲームコンソール（今回はRetroFreak）

## 接続方法

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156705/c6d3ce5d-5fa3-3d01-9c2a-be1978e84ce5.png)

Raspberry Pi Zero W とPC間のネットワーク導通は確認しておきます．
あまりにも遅延が大きい環境だと実施が難しいです．

# 設定手順

## 1. GameControllerizer + RasPiZW のセットアップ
[公式サイト](https://sites.google.com/view/gamecontrollerizer/w-raspi)のセットアップ方法にそって進めます．RasPi上のNode-REDが立ち上がったら，[こちら](https://github.com/GameControllerizer/node-red-contrib-game_controllerizer)のページにある[CheatSheet](https://raw.githubusercontent.com/wiki/GameControllerizer/node-red-contrib-game_controllerizer/docs/node-red-contrib-game_controllerizer-cheatsheet.json) をimportしておきます．`Dpad`/`Button`/`Stick`/`Misc` の4タブが生成されていることを確認しておきます．

うち`Misc`は以下のようになっています．これの意味するところは，GameControllerizerにより**外部からWebSocket経由で`ws://xxxx:1880/gamepad` へと送られてくる制御コマンド（JSON形式）が，機械語に翻訳されゲーム機に流しこまれる，**ということになります．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156705/0b24bf63-99a4-231d-1490-28985ed6953a.png)

## 2. Live Coding環境のOpen

https://qurihara.github.io/livecodinggc/

を開くとコーディング画面が表示されます．ここで指定のコマンドを記述すると，ゲーム機の制御として反映される仕組みです．実際にはページを開く際に

- `wshost` RasPiのIPアドレス 
- `wsport` Node-REDサーバーのポート番号（default = 1880）

をクエリパラメータで指定する必要があるため，具体的なアドレスは

https://qurihara.github.io/livecodinggc?wshost=192.168.11.10&wsport=1880

のようになります．

### ブラウザのセキュリティ警告
Javascript内に Secured WebSocket ではなくWebSocket で通信をするコード（PC→RasPi）が書かれているため，ブラウザによってはセキュリティ警告が出ます．以下の方法で回避できますが，本件の利用が済んだら戻しておくのが良いでしょう．

#### Chrome
URLバーの右にある盾マークから「安全ではないスクリプトを読み込む」

#### Firefox
URLに`about:config`を入力し`Enter`．設定画面が表示されたら`network.websocket.allowInsecureFromHTTPS`を`true`に変更する．

※関連記事：[FirefoxでhttpsからWebSocket接続(ws)するには..](https://qiita.com/khsk/items/87a60b1e425f871bf71a)

### 導通確認
PC→RasPi間でWebSocketによる導通が確保されると，Node-REDフロー上で緑色のマークが点灯します．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156705/be3443d0-61a8-389a-7a5e-7a939672c769.png)

## 3. いざコーディング！
2までできればあとはコーディングするだけです．基本的にはGameControllerizer専用の制御コマンド仕様（[DSL4GC](https://github.com/GameControllerizer/DSL4GC)）に基づいた記述を`$x()`で発行する，になります．例えば波動拳なら以下になります．

```javascript
hado = [
    {"dpad": 2,  "dur":3},
    {"dpad": 3,  "dur":3},
    {"dpad": 6,  "dur":3},
    {"btn": [3], "dur":3}
]
$x(hado)
```
なおコマンドは，多重にネストしても動作します．
あわせて，いくつかヘルプ関数を設けています（暫定調整中です）．

|Command  |Memo  |
|-----|-----|
|`$x(c)`|コマンド`c`を発行する．`c`はネスト配列でもOK|
|`btnf(n,m)`|`{"btn":[n],"dur":m}`に相当．ボタンを押す |
|`btn(n)`|`{"btn":[n]}`に相当．ボタンを押す(chain) |
|`dpadf(n,m)`|`{"dpad":n,"dur":m}`に相当．十字キーを押す |
|`dpad(n)`|`{"dpad":n}`に相当．十字キーを押す(chain) |
|`i=loop(c,m)`| `m`frame間隔でコマンド`c`を発行する．`i`は識別子 |
|`unloop(i)`| 識別子`i`に相当するloopを停止する |
|`repeat(c,m)`| `c`を`m`回繰り返すコマンドを発行する |
|`f(m)`| `m`frame待つ |

# やってみた
**ガイルで一生ソニック撃っていれば，意外と簡単にクリア出来るんじゃないの？**と思ったのですが...
![WIN_20191006_03_07_44_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/156705/369e8bb0-f5e4-a9d5-b32f-374349912175.jpeg)
あ，あれれ...ケン（3面）強いぞ．

## 行動部のコード
回り込まれると即死なので，ソニック x 2 → バックジャンプ　x　2．
記述はこんな感じです． 

```javascript
hp = btnf(2,3)	// punch(high)
lp = btnf(11,3)	// punch(low)
tame = dpadf(1, -1)
back_jump = dpadf(7,60)
$x(hp)

sonic = [
  dpadf(6, 2),
  hp,
  tame
]
s1 = [sonic,f(100),sonic, f(100),back_jump]
id1 = loop(s1, 360)
unloop(id1)
```

# おわりに
コントローラーではなくプログラムで操作するとなると

- いちいち打たないといけない煩わしさ
- loop, repeatに代表される便利さ

が混在し，慣れ親しんだゲームも別物のようです．ただ，左右が入れ替わるといろいろと不都合がおおいです．画像認識などの手法でフィードバックが取れるとよいのですが...

次は人vs人でやってみたいですね．