ジョイスティックからの入力を扱おう
DDIDEXコンポーネントを利用して、ジョイスティックによる入出力を行う方法について、簡単なアプリをいっしょに作りながら、学習しましょう。
まず、「ファイル−アプリケーションの新規作成」を選び、「ファイル−すべて保存」でアプリケーションを作り始める準備をします。ここまではいつも通りですね。
では、フォームにDDIDEXコンポーネントを貼り付けます。猫の手にINPUTという文字列が目印です。また、ApplicationEventsコンポーネントも貼り付けます。

さて、始めましょう。今回のチュートリアルでは、フォームをジョイスティクでずるずる動かすプログラムを作ります。
早速、本題である入力機器の状態の読み方を解説します。といっても非常に簡単です。
まず、DDIDEX1.Scanメソッドでキーボードから入力するか、ジョイパッドから入力するか、という事を指定し、メソッドを呼んだ時点でのジョイスティック・キーボードの状態を後で説明するStick,Buttonsプロパティに反映します。
DDIDEX1.Scan(DI_KYEB); なら、キーボードからの入力を行い、 DDIDEX1.Scan(DI_JOY1); なら、一本目のジョイスティックから入力を行います。
次に、DDIDEX1.Stickプロパティでスティックの状態を取り出せます。そして、DDIDEX1.Buttonsプロパティで、各ボタンが押されているか、押されていないかをチェックできます。
以上を踏まえた上で、お題であるフォーム動かしをやってみます。
では、ApplicationEvents.OnIdleイベントハンドラを書き換えましょう。
procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean); begin DDIDEX1.Scan(DI_JOY1); Top:=Top + (DDIDEX1.Stick.Y); Left:=Left + (DDIDEX1.Stick.X); Done:=False; end;
こんな感じで。まずScanでジョイスティック1の状態をStick,Buttonsプロパティに反映し、その後でStickプロパティを読んでいる、という事がおわかりになると思います。
ジョイスティックが右に倒れているならStick.Xは+1になり、下に倒れているならStick.Yが+1になるため、このように書くだけで、フォームがジョイスティックの倒れている方向に動き回るのです。結構、親切設計でしょ(^^;)
最後の行にある、Done:=False という記述に気づかれたでしょうか。これはApplication.OnIdleイベントが終わった後の、アプリケーションの振る舞いを制御するためのフラグです。
何も書かない場合、Done:=Trueと同じ扱いになり、何か他のイベントが起こるまではこのルーチンを呼ばなくなります。
一方で、この場合のようにDone:=Falseとすると、何もイベントが起きていない間は、Application.OnIDleイベントハンドラ(この場合、今書いたAppIdle手続き)を繰り返し呼ぶようになるわけです。
さて、このままではボタンの入力が無いので(^^;)、それも付けてみましょう。
procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean);
var
speed:Integer;
begin
DDIDEX1.Scan(DI_JOY1);
if DDIDEX1.Buttons[0] then
speed:=8
else
speed:=1;
Top:=Top + (DDIDEX1.Stick.Y) * speed;
Left:=Left + (DDIDEX1.Stick.X) * speed;
Done:=False;
end;
ここでは、ジョイスティックのButtons[0] (SideWinderではAボタンに相当)を押されると、通常の八倍速でフォームが画面を蹂躪してまわるようにしました。よぅし、かっこいいぞ。
さて、これまでのサンプルでは全てジョイスティックの使用を前提にしていましたね。ジョイスティックを持っていない人はキーボードで、持っている人はジョイスティックで操作出来るようにするにはどうするかというと、
procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean);
var
speed:Integer;
begin
DDIDEX1.OrScan([DI_JOY1,DI_KEYB]);
if DDIDEX1.Buttons[0] then
speed:=8
else
speed:=1;
Top:=Top + (DDIDEX1.Stick.Y) * speed;
Left:=Left + (DDIDEX1.Stick.X) * speed;
Done:=False;
end;
このように、OrScanメソッドを使用して、入力を受けたい機器番号の配列を渡すことで、複数の入力機器の状態のOR(論理和)を取った値が、各プロパティに代入されるのです。
使用可能な入力機器番号は、
DI_KEYB ... キーボード
DI_MOUSE ... マウス
DI_JOY1〜DI_JOY16 ... 1台目から16台目までのジョイスティック
となっています。
アナログジョイスティックや、マウスからの入力に対応する場合も、とても簡単です。
procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean);
var
speed:Integer;
begin
DDIDEX1.Scan(DI_MOUSE);
if DDIDEX1.Buttons[0] then
speed:=8
else
speed:=1;
Top:=Top + (DDIDEX1.AStick.Y) * speed;
Left:=Left + (DDIDEX1.AStick.X) * speed;
Done:=False;
end;
違いがわかりますか?
Stickプロパティではなく、AStickプロパティを読んでいるだけです。
マウスの動きに反応して、フォームが動くようになります。マウスを速く動かせば、フォームも速く移動します。
ジョイスティック・キーボードの場合も全く同様ですが、少し注意が必要です。ジョイスティックは目一杯倒すと、AStickプロパティには32767(右か下に目一杯)または、-32768(左か上に目一杯)という非常に大きな値を返します。
キーボードのAStickプロパティもそれに合わせて、大きな値を返すようにしています。マウスの場合は、単純に前回のScanからの移動量をピクセル単位で返すだけとなっています。
そこで、アナログジョイスティックを使う場合は、多くの場合、AStickプロパティから読み出した値にある程度の重み係数を掛けて使うことになるでしょう。今回は、重み係数を、1/2000にして、最大で16ピクセルずつ動くことにします。
procedure TForm1.AppIdle(Sender: TObject; var Done: Boolean);
var
speed:Integer;
begin
DDIDEX1.OrScan([DI_Joy1,DI_KEYB]);
if DDIDEX1.Buttons[0] then
speed:=8
else
speed:=1;
Top:=Top + (DDIDEX1.AStick.Y) * speed div 2000;
Left:=Left + (DDIDEX1.AStick.X) * speed div 2000;
Done:=False;
end;