このところファイティングスティックVXをベースとしたガレッガ用のコントローラーを作っていました。
まだ記事にはできていませんが、一応目途がついたので他のことに着手します。
バーチャの練習環境を整備したい
2年ほど前にヤフオクで買ったVF3tb基板の動作確認をする際、ArduinoのGPIOをレバーにつなぎ、high/lowを切り替えて連続じり下がりをさせてみたことがあります。
当時はV-SYNCとの同期もしていなかったのでとてもぎこちない動きでした。
それでもコマンドコントローラーを作成できそうな手応えは感じたものです。
その後シンクロ連射装置の作成に挑戦したことで、V-SYNCに同期してhigh/lowを切り替えることができるようになりました。
その応用として入力信号をレバー(上下左右)と複数ボタン分用意すればコマンドコントローラー的なものも作れるハズです。
CPU戦ではなかなかよろけ回復の練習ができなかったり、実戦ではスピードが速すぎてじっくりと反復練習できなかったりしますよね。
なんとか練習環境を整備したいなと思っていたのでした。
おさらい
修正版のソースはまだ記事にできていませんが、シンクロ連射装置のコードではGPIOのhigh / low情報は配列で持たせています。
配列(ren)にボタンが押されている(0)/離されている(1)という情報を格納しておき、V-SYNC割り込みごとに連射処理のサブルーチンを呼ぶ作りになっています。
1 2 3 4 5 | volatile int ren[] = {0,1,1,1,1,1,1}; volatile int ren_element = 0; // 現在の要素番号 volatile int ren_speed = 4; // 現在の連射速度(5:10発,4:12発,3:15発,2:20発,1:30発) |
サブルーチンでは参照する配列(ren)の要素をずらしていき、連射速度(ren_speed)で指定した数だけ配列の要素をずらし終わったら、次に読む時は先頭に戻ってボタンon(0)から読み直します。
ボタンを押している時間と離している時間の間隔(いくつ要素をずらしたら先頭に戻るか)は変数(ren_speed)に持たせているため、ロータリースイッチによってこの変数値を変えることで、速度可変の連射装置へ応用できるはずです。
PORT操作
レバーやボタンのON/OFFを変えるためにはdigitalWrite関数で各GPIOピンのLOW(0V)/HIGH(+5V)を変える必要があります。
1 2 3 | digitalWrite(10, LOW); // GPIO No.10を0Vに変える場合 |
ガレッガ用に作成中の連射装置では、GPIOのピンを複数使うことによって速度の違うボタンを用意できるようにしています。
(例えばショット15発/sとボム連30発/sなど)
この場合でも配列は1つで良いし、GPIOピンごとにdigitalWriteを使用しても面倒ではありませんでした。
しかしバーチャの練習環境を作るとなると、レバーやボタンの状態が頻繁にかわります。そのたびに何度もdigitalWrite関数を並べるのは・・・とても面倒ですよね。
X68000の時は確か1Byte読み書きすればよかったはずなので、あのように手軽にI/O操作できる方法はないのかと検索しまくりました。
そしてとても良い方法があることがわかりました。
PORT操作をすることで複数ピンの状態をまとめて変更することができるようです。
高速化もできるし願ったり叶ったりですね。
バーチャファイターで一番ボタンが多いのはVF3tbの4ボタン。
上下左右PKGEの8つを自動化したいので、1Byte書き込むだけで済めば効率が良いです。
配列をByte型で宣言すればメモリ効率も良くなります。
連射装置で使用したArduino UNOでは8bit連続しているPORTは確保できないのですが、GPIOピン数が多いArduino MEGA2560を使用すれば8bit連続で確保できるPORTがいくつもありますので、1Byte書き込むだけでレバー上下左右とボタン4つの状態を変えることができます。
Arduinoはオープンハードなので互換品は格安で販売されています。
評判の良さそうなものを早速購入してみました。
技のデータをどうやって用意するか
V-SYNCに同期して1フレームごとにHIGH(+5V)/LOW(0V)を切り替えることは実現できているので、単純に考えればレバー4方向+ボタン4つ分の情報を配列に格納しておけば、VF2/VF3tbで使用できるコマンドコントローラーができるはずです。
しかし、技や連携を出させるときに、都度1Fごとのコマンドデータを用意するのは面倒です。
肘・膝・ヤクホなど技の種別ごとにある程度まとめて技ごとのコマンドデータを用意しておければ便利でしょう。
しかし単純作業で入力データを作成するための元データがないのです。。
VF3tbムックのフレーム表には発生やダメージ・硬化差は記載されているのですが、VF2マニアックスに記載されていたような攻撃判定の持続フレームや硬化フレーム等は記載されていません。
技のコマンドを入力した後、どのくらい間隔を置いて次のコマンドを入力すればよいのかわからないんですね。
そのためコマンドデータはVF2のフレーム表(箱〇青年部版)から適当に自動生成して、VF3tbで変わった箇所を微修正していけば動くだろう、、、などと簡単に考えていたのですが・・・技数分の配列を宣言したらメモリ不足になりました。。
Arduinoのメモリは小さいのです。
方針を考える
バーチャの練習環境としてコマンドコントローラーを作成していくにはいくつか段階があると考えています。
- 簡単な練習ツール
- 学習モード付練習ツール
- 1P/2P完全同期の調べごとツール
- PCとのシリアル転送付練習ツール
肘~投げなど対応を反復練習したい技だけを配列に登録しておけばよいケース。
配列を2,3個登録させておいて、乱数で行う操作を変えるとより練習に役立ちそうです。
(50%で肘~投げ、50%で肘~旋蹴りなど)
また投げに来るタイミングも乱数で最速・ちょい遅れ・遅めなどバリエーションを増やせればそれだけ現実的な練習ができると思います。
だんだん1フレームごとに考えて配列データを用意するのが面倒になってくると思います。
そのため、自分の操作を覚えさせて自動で配列データを作るようにすれば、もっとテンポよく練習ができるはずです。
上記2パターンは片方を自分で操作して反復練習を行うためのツールですが、調べごとで完全に同じタイミングで1P/2Pそれぞれの技を出してみたい(どちらが判定勝ちするか等)こともあるでしょう。
そういった調べごとツールもいずれ必要になると思いますが、仕様やフレーム表を疑うところまでは到達できていないのでまだ具体的には考えていません。
技数が多くなったり、連携までデータ化するとなると、Arduinoのメモリが不足してしまうことも考えられます。
その場合はパソコン側からシリアル転送で都度データを送る方法を採るしかないでしょう。
しかしパソコン側で動作させるプログラムから基板のV-SYNCを検知する術はないため、垂直表示期間中にArduino側プログラムから送信要求を出し、それを受け取ったパソコン側からArduinoにデータをシリアル転送。シリアルで送ったデータをArduino側できちんと受け取れたらパソコン側へackを返し、垂直帰線期間になったらGPIOの値を変える、というようなパソコンとArduinoとのやり取りを行う仕組みをコーディングする必要がありそうです。
いきなりここまで作り込むのは大変そうなので、まずは志をぐっと低くして、単純な練習に使えるレベルのものを目指します。
最初の目標
- V-SYNCに同期させて1フレームごとにレバー・ボタンの入力をArduinoから行う
- キャラ選択やステージ選択の際は普通に操作できるよう簡易コントローラーを作る
- どのような入力ができているのか一目で把握できるようにLEDをつける
- 左右が入れ替わった時のために配列データを左右入れ替えて出力するスイッチをつける(オプション)
あたりを最初の目標にしてみます。
というわけで作ってみた
ソース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | volatile unsigned long time_prev = 0,time_now; unsigned long time_chat = 8; // 0.5F volatile int process_now = 0; // 今後のため volatile int array_num = 0; volatile int array_max = 0; volatile byte action1[] = { B01010101, // 3フレームごとに入力を変える B01010101, B01010101, B10101010, B10101010, B10101010}; void setup() { // GPKE DDRC = B11111111; //GPIO D30-D37(2P:上下左右1234) 出力 DDRB = B00001111; //GPIO D53-50,D10-13 // D50:左右入れ替えSW attachInterrupt(0, V_SYNC, FALLING); process_now = 1; // 最初は常に1 } void loop() { array_max = sizeof(action1) - 1; // 今のところ毎回計算する必要はないが、学習モードを有効にした場合のために //処理中の場合は次の配列の内容を処理させる if ( process_now == 1 ) { if (array_num > ( sizeof(action1) -1)) { array_num = 0; } } } void V_SYNC() { time_now = millis(); if ( time_now - time_prev > time_chat ) { //チャタリング対策 if ( process_now == 1 ) { PORTC = action1[array_num]; array_num = array_num + 1; } } time_prev = time_now; } |
ハード面
本来は図を描くべきだとは思うのですが、簡単に接続を説明すると、
JAMMAハーネス~簡易コントローラー~Arduino となっています。
上部にあるタクトスイッチは一般的なアーケード基板操作のための
スタート、コイン、テスト、サービス等のスイッチです。
キャラ選択やステージ選択ができるように上下左右とボタン4つ分のタクトスイッチも付けました。
どのような入力がされているかわかるように各レバー・ボタンに対応したLEDもつけました。
(LEDの色がバラバラなのは手持ちがなかったためです。。)
実際に動作させてみた例を動画で載せてみます。
EボタンだけArduinoと接続し、3フレームごとにON/OFFさせるプログラムを動かした状態で、各ボタンを押してみてLEDがきちんと点灯することを確認。
動画には映っていませんが、LEDが光った際にVF3tbのテストモードで実際にONとなることは確認できています。
Arduinoからの連射信号が来ているEボタンについても、ボタンを押したときにLEDが常時点灯になることも注目です。
前記事で学んだ連射装置の取り付け方と同じように接続しているので、連射装置と手動ボタンが同時にONになった時は押しっぱなし(シューティングでの溜め撃ち)になっています。
上部に設置してある2つのトグルスイッチはまだ何も接続していません。
1つめはキャラ・ステージの選択時にArduinoの動作を停止させるためのスイッチ。
2つめは入力データの左右を反転させるためのスイッチにする予定です。