はじめに
この記事の続きです。
遂にJR EAST Train Simulatorが正式リリースされました!!やったぜ。オープニングがカッコイイ。
ということで(?)、一応完成としていた前回記事の状態から、ちょっとだけ手を加えました。(これ以上の変更点の追記は可読性を下げそうな気がしたので別記事にしました。)
2022/12/10: コードを微修正し,githubに置き直しました.
概要
- コントローラの操作をすべてマウス操作として入力する
- コントローラのボタンにキーボードのキーを割り当てる
コントローラの操作をすべてマウス操作として入力する
前の記事では、ハンドルの位置変化をキー押下ではなくマウスホイールのスクロールとして入力するように変更しました。
すなわち、ハンドルがNおよびEB位置の場合の処理はそれぞれS
、1
のキー押下のままなわけですが、これでは211系などの2ハンドル車ではうまく動作しません。2ハンドル車を1ハンドルマスコン型のコントローラで操作するというのはいかがなものか…という気はしますが、一応遊べるようにしておきます。
マウスホイールで操作する
公式の操作マニュアルを見ると、マウス操作においてEB投入に相当するボタン等は無いみたいです。また、ブレーキ・加速ゼロ(前回記事におけるS
押下に相当)はマウスホイールのクリックのようです。
pyautoguiでマウスホイールをクイックするには、pyautogui.click(button='midlle')
を実行すればよいみたいです。(参照)
また、pyautogui.click(button='midlle')
を実行する際に
The Pillow package is required to use this function.
とエラーが出るので、この記事の通りPillowをインストールしました。
また、前回のコードではnow_pos
がN位置かEB位置にあった場合、何度もS
、1
が押下されていたので、位置に変化が無い場合は何もしないように変更しました。
def mouse_scroller(prev_pos, now_pos, newtral_pos):
if(prev_pos==now_pos):
pass
else:
if(now_pos == newtral_pos): # N位置ならホイールクリック
pyautogui.click(button='middle')
elif(now_pos == 0):
pyautogui.scroll(10000) # EB位置なら上方向に思いっきり回転
else:
delta = prev_pos-now_pos
pyautogui.scroll(delta*130)
# ゲーム上ではマウスホイールでの操作として認識させます。
# 検証したところ、1段あたりだいたい130"click"だと適切に動作します。値が小さいと、コントローラでB7に入れてもゲーム上でB6になるなどします。
# 値は環境に依存するかもしれません。
# delta<0で下スクロール、delta>0で上スクロールです。
コントローラのボタンにキーボードのキーを割り当てる
こっちが本題みたいな感じではあります。
が、マニュアルによれば使用するキーは18、コントローラには16個のボタンしかありません。
したがって、一部の機能はキーボードでの操作が必須になります。
運転動作への関連度を考慮して、いくつかの操作はボタンに割り振りません。
コントローラ上のボタンと押すべきキーの対応付け
とりあえず
-
A
ボタンを警笛1、X
ボタンを警笛2、Y
ボタンをEBリセット、B
ボタンを連絡ブザー -
↑
ボタンをレバーサ前、↓
ボタンをレバーサ後、→
をATS確認、←
を警報持続 -
CAPTURE
を低速/抑速、L
を勾配起動、-
をTASC切
とします。
pygameのリファレンスにコントローラ上のボタンがどのjoystick内のbuttonに対応しているか書かれています。なので、リファレンスとシミュレータのマニュアルを反復横跳びして…buttonの番号とそのボタンに割り当てるキーを対応させておきます。
ButtonNum_PushKey={0:'enter', 1:'b', 2:'backspace', 3:'e', 4:'t', 7:'k', 11:'up', 12:'down', 13:'x', 14:'space', 15:'w'}
押す動作と離す動作
シミュレータには、運転士がボタンを「押す音」と「離す音」がどちらも収録されています。また、警笛など長押しをしたいので、できるようにします。
pyautoguiでは、keyDown()
でキー押下、keyUp()
で離す動作ができるようです。したがって、以前のボタンの状態と現在のボタンの状態を比較して、keyDown()
、keyUp()
することにします。
joystickオブジェクトのbuttonの状態を手に入れます。
def get_button_status(device): # pygame.joystickオブジェクトを引数にとり、全てのbuttonの状態を配列で返します。
button_num=device.get_numbuttons()
button_status=[device.get_button(i) for i in range(button_num)]
return button_status
値が0なら押されておらず、1なら押されている状態を表すので、前状態と比較して0->1であればkeyDown()
、1->0であればkeyUp()
すればよいですね。
def key_press(prev_btnstatus,now_btnstatus,ButtonNum_Key_Table):
# 前回のボタン状態配列、現在のボタン状態配列、ボタンの番号と押すべきキーの対応辞書を引数にとります。
for button_num,keyname in ButtonNum_Key_Table.items():
if(prev_btnstatus[button_num] < now_btnstatus[button_num]): # status 0->1: 押された
pyautogui.keyDown(keyname)
elif(prev_btnstatus[button_num] > now_btnstatus[button_num]): # status 1->0: 離された
pyautogui.keyUp(keyname)
else:
pass
動作確認
良い感じです。動画は無いですが、211系でも正常に運転できます。コード
2022/12/10
githubに置いてあります.