2017年12月24日日曜日

アスカ見参のパッド設定の問題

アスカ見参の妙に納得いかないコントローラーの仕様を調査しました。

コントローラー(ジョイパッド)の検出

コントローラーは起動時にしか検出していないので、起動後に接続してコントローラーは使用できません。

複数のコントローラー

複数のコントローラーが発見された場合は、強制的にどれか一つだけに決定されます。
どうしても使用したいコントローラーが使用できない場合は他のコントローラーはずしながら再起動してチェックするか、他をすべて外す必要がありそうです。

アナログコントローラー時の軸の初期化の問題

アスカ見参はDirectInput8で入力を判定しています。
アスカ見参のDirectInput8での軸の入力は、X軸とY軸しか考慮していない問題があります。
コントローラーの初期化時にX軸とY軸の取得値の範囲を-1000から1000に設定しています。
取得値が中央値の0に近い値が取得できる際は未入力と判定するという意味になります。
この初期化自体はおかしくないですが、X軸とY軸しか考慮していないため範囲の設定をX軸とY軸しか行っていませんでした。
アナログコントローラーは他にも軸がありますが、取得値の範囲を設定していない軸は、多くのコントローラーでは0から65535の範囲となってます。
アスカ見参にはパッド設定があり、ボタンの設定以外に「移動」という項目がありデフォルトで「Axis」(X軸とY軸に相当)になっています。
変更する場合は「移動」を選択して何かの方向キー(十字キー)やスティックを入力すると変更できる仕様に作られています。
範囲指定していない軸の入力値も-1000から1000で取得される前提で実装されているため、以下のような現象が起こります。
例えば右スティック(X回転とY回転)がある場合の範囲を設定されていないため未入力は32767付近の値が取得されますが、これを1000の方向に入力中を判定されるため、結果的に右下方向に常に入力されている扱いとなっていまい、即「Axis2」(X回転とY回転)に設定されてしまう不具合があります。
ここで設定をキャンセルすればまだよいですが、決定してしまった場合は、常に右下を入力してる扱いになって戻すこともできなくなり大変なことになります。
この状態にしてしまった場合の対処は、常に下にカーソルが移動するけど頑張って「デフォルトにもどす」を選択して「決定」を押すか、起動していないときにレジストリを編集してなおすか、再インストールとなります。

DirectInputの仕様

実装したことない方向けにDirectInput8のコントローラ入力の取得について少し捕捉します。
スティックがない昔たくさんあったデジタルパッドと言われる方向キー(十字キー)だけのコントローラーは、方向キーがX軸Y軸に設定されていました。
その後スティックが二つあるアナログコントローラーが作られ、多くのアナログコントローラーは左スティックがX軸Y軸、右スティックがX回転Y回転に設定しているものが多く作られました(DualShock4はなぜか右スティックはZ軸Z回転のようです)。
方向キーはどうなったのかというと視点切替(POV=Point of View、ハットスイッチとも呼ばれます)に割り当てられています。
POVは軸ではなく方向なので値は角度の100倍で取得されます(多くは0,4500,9000,13500,18000などの固定値で上が0で時計回り)。
古いプログラムで移動が左スティックだけになっているのは大抵はPOVを考慮していないのが原因です。
そういうプログラムで方向キーを使いたい場合は、入力を読み替える外部ツールを使用するか、アナログがないデジタルパッドを使用するかどちらかになるでしょう。

アスカ見参のパッド設定

アスカ見参は、移動入力もカスタマイズできるように出来ていたのは優秀でしたが、軸の範囲の設定をX軸とY軸しか行っていないのに、他の軸も範囲を設定した前提で値を読み取っていた不具合で移動設定は触ると危険なメニューとなっています。
なおレジストリで「KCfg_PAD_DIRT」の値を5に設定するとPOVにも設定でき、POVにもちゃんと対応していることがわかります。

XInput対応コントローラーの話

XInputに対応しているコントローラーもDirectInput8でコントローラーとして検出されます。
逆にXInputに対応していないコントローラーはXInputではコントローラーとして検出されません。
DirectInput8でXInputに対応しているコントローラーを使用すると、左トリガーはZ軸の+値、右トリガーはZ軸の-値となっており軸を共有する設定にされています。
何が問題かというと、両方入力すると値が相殺されることになり両方入力していない値として取得されてしまいます。
それ以外の点に関しては特に問題はなさそうなのでトリガーを使用しない、または同時に使用しないのであれば使用できないこともないといった事になりますが、アスカ見参は多くのボタンを使用する仕様となっているためそうもいかないことになります。
一般的な対応策は、XInputで入力を読み取り入力を置き換えるツールを導入することになります。

2017年12月17日日曜日

オプション-負荷軽減

オプション-負荷軽減

負荷を下げるための設定

アスカ見参のゲームループ

普通は「内部処理→画面描画→次回処理時間待ち→内部処理」を繰り返すが、「次回処理時間待ち」の部分で、「次の時間になったか確認→次の時間になったか確認」を繰り返すだけの処理となっているようで「次回処理時間待ち」にも常にCPUを全力で使用し続ける作りになっています。
今どきのCPUコアの数が多いPCなら、一つが100%のままでも他があるので問題ないと言えますが、バッテリ稼働のPCの場合は無駄な負荷となるとバッテリの消費となるのであまり良くはないです。

描画毎にSleep

上記の仕様により負荷がかかるため、描画が終わった直後に固定のSleepを設定することで、CPUリソースを開放し負荷を下げる設定です。
ただしSleepの数値が多すぎる場合や、アスカ見参自体が重いときでもSleepするため、この設定のせいで、アスカ見参の処理が遅くなったり、間に合わなかった描画を飛ばされたり(カクカク)することもあります。
1フレームは1/60秒=16.66…ミリ秒ですので、17ミリ秒以上に設定すると1秒間に60回は絶対描画できなくなりますので16ミリ秒までしか設定はありません。
なおこの設定により、アスカ見参が遅くなる可能性はありますが、速くなることはありません。
バッテリ稼働ではない余裕のあるPCで実行する場合は、設定しないほうが処理落ちしにくいということになります。
ノートPCなどでは設定しておくべきかと思います。