これはなに?
Live Coding Street Fighter 2 (for Abpro'19) https://t.co/MNo29trkMP @YouTubeさんから
— nobu_e753 (@nobu_e753) October 5, 2019
Live codingでスト2キャラクターを操作し戦うものです.
俺より強い奴(プログラマー)に会いに行く!
IT系勉強会後の宴会に良さそうです.
本記事はその実施方法解説記事です.
ハックについて
明治大学で開催されたABPro 2019(「普通じゃないプログラム作品」の発表会)にて,津田塾大・栗原一貴先生より発表のあったゲームハックです.
プログラマブルゲームコントローラー GameControllerizer を使うことで,自身のプログラム(javascript)からのキャラクター操作を可能にしています.
必要な機材
- PC(コーディング用)
-
GameControllerizer(プログラマブル
ゲームコントローラー) - Raspberry Pi Zero W(↑と組み合わせて使います)
- ゲームコンソール(今回はRetroFreak)
接続方法
Raspberry Pi Zero W とPC間のネットワーク導通は確認しておきます.
あまりにも遅延が大きい環境だと実施が難しいです.
設定手順
1. GameControllerizer + RasPiZW のセットアップ
公式サイトのセットアップ方法にそって進めます.RasPi上のNode-REDが立ち上がったら,こちらのページにあるCheatSheet をimportしておきます.Dpad
/Button
/Stick
/Misc
の4タブが生成されていることを確認しておきます.
うちMisc
は以下のようになっています.これの意味するところは,GameControllerizerにより**外部からWebSocket経由でws://xxxx:1880/gamepad
へと送られてくる制御コマンド(JSON形式)が,機械語に翻訳されゲーム機に流しこまれる,**ということになります.
2. Live Coding環境のOpen
を開くとコーディング画面が表示されます.ここで指定のコマンドを記述すると,ゲーム機の制御として反映される仕組みです.実際にはページを開く際に
-
wshost
RasPiのIPアドレス -
wsport
Node-REDサーバーのポート番号(default = 1880)
をクエリパラメータで指定する必要があるため,具体的なアドレスは
のようになります.
ブラウザのセキュリティ警告
Javascript内に Secured WebSocket ではなくWebSocket で通信をするコード(PC→RasPi)が書かれているため,ブラウザによってはセキュリティ警告が出ます.以下の方法で回避できますが,本件の利用が済んだら戻しておくのが良いでしょう.
Chrome
URLバーの右にある盾マークから「安全ではないスクリプトを読み込む」
Firefox
URLにabout:config
を入力しEnter
.設定画面が表示されたらnetwork.websocket.allowInsecureFromHTTPS
をtrue
に変更する.
※関連記事:FirefoxでhttpsからWebSocket接続(ws)するには..
導通確認
PC→RasPi間でWebSocketによる導通が確保されると,Node-REDフロー上で緑色のマークが点灯します.
3. いざコーディング!
2までできればあとはコーディングするだけです.基本的にはGameControllerizer専用の制御コマンド仕様(DSL4GC)に基づいた記述を$x()
で発行する,になります.例えば波動拳なら以下になります.
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待つ |
やってみた
**ガイルで一生ソニック撃っていれば,意外と簡単にクリア出来るんじゃないの?**と思ったのですが...
あ,あれれ...ケン(3面)強いぞ.
行動部のコード
回り込まれると即死なので,ソニック x 2 → バックジャンプ x 2.
記述はこんな感じです.
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人でやってみたいですね.