【第4章】色々なオブジェクトで遊ぼう
第18回 ゲームパッドで動作させてみよう(システム)
ゲームパッドのボタンでヘッドライトをオンオフさせてみよう。XInput対応のゲームパッドではVRMNXのビューワーは、A:警笛、B:進行方向反転、Y:制御方式変更、X:視点オフセット初期化、L:視点オフセット回転、R:視点オフセット回転、START:列車切り替えとなっています。このうちXボタンとYボタンを使います。
【使用するVRMNX命令】色々な部品にある命令:SetEventFrame(ユーザーID)
'frame'イベントを設定します。アプリは、入力・実行など一連の動作を1秒間に複数回繰り返しています。この繰り返し1回が、フレームです。フレームごとに発生するイベントです。
【使用するVRMNX命令】SYSTEM()関数の命令:GetGamepadX(デバイス番号)
Xボタンの状態を取得します。デバイス番号は0から3でゲームパッドが1つ接続している場合は0です。戻り値がTrueでボタンが押されている状態です。
【使用するVRMNX命令】SYSTEM()関数の命令:GetGamepadY(デバイス番号)
Yボタンの状態を取得します。デバイス番号は0から3でゲームパッドが1つ接続している場合は0です。戻り値がTrueでボタンが押されている状態です。
【やってみよう】「親子で学ぼう用レイアウト(8初期状態).vrmnx」を開き、レイアウトにスクリプトをこのように書こう。書くのが大変ならコピペしよう。完成品は「親子で学ぼう用レイアウト(18-1).vrmnx」です。
#LAYOUT
import vrmapi
def vrmevent(obj,ev,param):
train = vrmapi.LAYOUT().GetTrain(11)
car = train.GetCar(0)
if ev == 'init':
vrmapi.LAYOUT().SetView(10)
vrmapi.LAYOUT().SKY().LoadSkyImage(0, 1)
vrmapi.LAYOUT().SKY().SetSunType(3, 0)
obj.SetEventFrame(123)
(中略)
elif ev == 'frame':
if param['eventUID'] == 123:
x = vrmapi.SYSTEM().GetGamepadX(0)
y = vrmapi.SYSTEM().GetGamepadY(0)
if x == 1:
car.SetHeadlight(True)
if y == 1:
car.SetHeadlight(False)
(以下省略)
【解説】ゲームパッドのXボタンが押されたらというイベントハンドラはないため、'frame'イベントで毎フレームボタンが押されたかを監視する形を取ります。Xボタンが押されたら「TRAIN_11」のヘッドライトを点灯、Yボタンが押されたら消灯としています。
【実践】それでは「運転」を押してビューワーを起動させましょう。Xボタンでヘッドライト点灯、Yボタンで消灯すれば成功です(^^)/
【余談】実は当初このように1つのボタンを使いトグル式にしようとしていました。完成品は「親子で学ぼう用レイアウト(18-2).vrmnx」です。
#LAYOUT
import vrmapi
def vrmevent(obj,ev,param):
if ev == 'init':
vrmapi.LAYOUT().SetView(10)
vrmapi.LAYOUT().SKY().LoadSkyImage(0, 1)
vrmapi.LAYOUT().SKY().SetSunType(3, 0)
obj.SetEventFrame(123)
(中略)
elif ev == 'frame':
if param['eventUID'] == 123:
y = vrmapi.SYSTEM().GetGamepadY(0)
train = vrmapi.LAYOUT().GetTrain(11)
car = train.GetCar(0)
if y == 1:
b = car.GetHeadlight()
if b == 0:
car.SetHeadlight(True)
else:
car.SetHeadlight(False)
(以下省略)
ところが実行すると1回押すと複数回動作してしまうため使い物になりませんでした。例えば60FPSで動作し0.1秒押したらその間に6回は動作するわけで1ボタンでのトグル式は無理そうです。
なおこちら後者のスクリプトでは'frame'イベント内でtrainやcarのインスタンスを毎秒たくさん生成してしまっています。1両だけならそんなに問題はありませんが多数を対象としてくると処理が重くなるので、'frame'イベントを使うのであれば前者のスクリプトのように「if ev == 'init':」の前でtrainやcarを取得した方が良いでしょう。
また'frame'イベントの場合は余程のことがない限りはユーザーIDを使って「if param['eventUID'] == 123:」とせずに、この部分は省略してしまっても良いようです。