PC Engine emulator
”Ootake”
エミュレータの大きな問題である「操作遅延」解消へのこだわり
「パソコン環境による遅延」の解消方法については、こちらのページへ
 


English version is click here.

こんにちは。PCエンジンエミュレータ「Ootake」を製作しています中村です。
エミュレータを製作している方に、是非こだわって欲しいところがあります。

これまでに、たくさんの各機種のエミュレータが公開され、利用されていますが、
「操作感覚」にこだわっているエミュレータは稀で、多くのエミュレータが、実機と比べて
操作してからの反応が遅い「遅延問題」をかかえています。

アクションゲームやシューティングゲームは、「操作遅延」があると、そのゲームの難易度自体
も上がってしまいます。よく、エミュレータで昔得意だったゲームをプレイしても、思うように
進めなくて「腕がにぶったな〜」とか「昔と比べて面白くないな〜」という声が聞かれます。

もちろん、歳で腕がにぶることもあるのかもしれませんが、たいていの場合「操作遅延のある
エミューレータでプレイしてしまった」ことが一番の原因
なのではないでしょうか。
人間、30歳や40歳になっても、そう「極端には」衰えないものです。

例えば、スーパースターソルジャーの2分モードを「Ootake」と「MagicEngine」で真剣に
プレイし比べてみてください。「Ootake」では私の腕でさえ50万点を越えるプレイができますが
「MagicEngine」では操作の遅延が大きいため思うように自機の切り返しができず、
50万点越えは絶対に無理だろうと感じました。(標準的なWindowsXP SP2環境にて確認)

これは、「得点の違い」だけではなく「ゲームの楽しさ」にも大きく影響します。
正直、「MagicEngine」でスーパースターソルジャーをプレイしても、キビキビと自機が動いてくれない
ために、自機との一体感が無く、「本来はあるはずの作品の楽しさ」を感じられませんでした。

残念ながら、現役ゲームマシン用の商品として売られているリバイバル作品タイトル(エミュレータ
動作)の中にも、誰にでも感じられるぐらい大きな遅延があるゲームも多く存在しています。
(そういうタイトルを発売するメーカーは、ゲームに対する愛着が全く無いのだと思います)

このことは「そのゲーム作品自体の評価」まで誤ったものにしてしまう危険性も含んでいます。
ですので、「Ootake」は特に「実機と同様の感覚で楽しめるかどうか」
厳しくチェックしながら開発しています。
それが、過去の名作ゲームに対する最低限の敬意だからです。

"Ootake"で実施している「操作遅延」解消の方法

Ootakeでは、2つの作戦で、操作遅延を解消(軽減)しています。

1つ目の作戦は・・・
「ジョイパッドの状態を見る命令」が来たら、常に「そのときの最新のWindowsジョイパッド入力状態」を取得(更新)している。
です。

おそらく、多くのエミュレータでは、1フレーム(1/60秒)に1回だけ「Windowsのジョイパッド入力状態」を取得しているため、その取得直後のタイミングでジョイパッドを入力した場合、最大1フレームぶん入力が遅れることになります。

それを上記の1つ目の作戦(入力を見る命令が来たら、常に状態を取得)を使うことで、この問題での遅延は解消できます。

ただし、この作戦は、ゲームによって(入力待ちが多いゲーム)は処理が「かなり重く」なってしまい、実用的な速度が出せません。

そこで、Ootakeでは、連続で「ジョイパッドの状態を見る命令」が来た場合、「Windowsのジョイパッド入力状態」の取得する回数を制限する仕組みを入れています。

具体的には、「Windowsのジョイパッド入力状態」の取得したら、そのときに「処理中だった走査線ラインNo.」を記録しておいて、次に「ジョイパッドの状態を見る命令」が来たときに「まだ同じ走査線ラインNo.での処理中」だった場合は、「Windowsのジョイパッド入力状態」の取得を省きます。
(つまり、「1ラインに1回」が最も多いの取得(更新)回数となります)

こうすることで、反応が充分に早く、かつ処理が重くなりすぎないように対策しています。
※それでも、この処理でエミュレータはだいぶ重くなります。それでも、「作品の楽しさを損なわないため」には必要な処理と思っています。

2つ目の作戦は・・・
エミュレートする処理を「約1/240秒(1/60秒を4分割)」単位で区切ることで、「実機での時間経過状態」に近づけている。
です。

エミュレータを動かしたときに、性能が高く「処理速度に余裕があるパソコン」の場合、下図(1/60秒間の流れ)のように

->[ エミュレート処理 ]->[    V-Sync信号が来るまでお休み   ]->[描画処理]->(先頭へ)

となって、「V-Sync信号が来るまでお休み」する時間が長くなります。(逆に、「性能がギリギリのパソコン」の場合、この「お休み」が少なくなり「エミュレート処理」の時間が長くなります)

この「お休み」の時間はジョイパッドの入力判定を行うことはできないので、「お休み」の時間が多い「処理速度に余裕があるパソコン」ほど、ジョイパッドの入力可能期間が狭くなり、1フレーム遅れて入力されてしまう原因になります。そこで下図(1/60秒間の流れ)のように

->[エミュ]->[休]->[エミュ]->[休]->[エミュ]->[休]->[エミュ]->[休]->[描画処理]->(先頭へ)

として、約1/240秒毎に休みを入れる(休みを1度にせずに分割する)ことで、実機に近い時間経過の流れを作り、ジョイパッドの入力判定も遅れないようにしています。

また、実はジョイパッドの反応だけでなく、「休み」が少なく「性能がギリギリのパソコン」でのエミュレート処理のほうが、「実機での時間経過の状況」に近いため、エミュレートの精度(タイマ割込みや、それを利用した内蔵音源BGM等)も高まります。

ですので、Ootakeでは上記の作戦で、 「処理速度に余裕があるパソコン」でも、「性能がギリギリのパソコン」に近い動き(=実機の時間経過に近い動き)になるような仕組みで動かしています。特にPSG(波形メモリ+ノイズ)の音色の再現に、このことは重要となっています。
※Ootakeの"Volume"メニューで"Light PSG"を選んでいる場合は、通常の1/60秒毎の動作になります。
 


最も大きな「操作遅延」となってしまう原因について

上に記載したOotakeの「2つの作戦」では、最大で1フレームの遅延を防ぐものです。

それ以上に問題となる「大きな操作遅延(約2〜4フレーム)」は、また別の原因があります。
それは、「WindowsのDirectX(Direct Input)の問題」です。

「Windowsの"Direct Input"」は、うまく使わないと大きな遅延が発生してしまいます。
使うライブラリによっても異なってくるようですが、Ootakeの製作環境(MinGW+DirectXライブラリ)の場合、ソースに

#define DIRECTINPUT_VERSION 0x0500

と記述して、"Direct Input"の「バージョン5」(古め)を利用することで、もっとも少ない入力遅延を実現しています。(WindowsXP上で動作確認)

このバージョンを上げてコンパイルしてしまうと、Ootakeでも大きな入力遅延が発生します。推測ですが、「最近バージョンの"Direct Input"を作った方(マイクロソフト社員さん)よりも、古いバージョン5の"Direct Input"を作った方(マイクロソフト社員さん)のほうがゲーム好きで遅延削減にこだわりを持っていた可能性」か、「ライブラリが古いので、最新バージョンの"Direct Input"と相性が合わず遅延が起きてしまう可能性」などが考えられます。

ちなみに、問題が発生していない素晴らしいファミコンエミュレータの"Nestopia"のソースをざっと見させてもらったところ、"Direct Input"のバージョンを下げている様子は見られなかったので、ライブラリが新しければ大丈夫なのかもしれません。Ootakeでは、バージョンを5に下げることで少ない入力遅延を実現しています。

残念ながら、この遅延問題が発生しているエミュレータは多く、素晴らしいファミコンエミュレータの"VirtuaNES"や、MSXエミュレータの"BuleMSX"でも問題が生じていて、非常にもったいないです。この問題が生じていない"Nestopia"や、"ParaMSX(最新β)"と、アクション,シューティングゲームを真剣にやり比べてみると差は顕著です。("VirtureNES","BuleMSX"で改善されると、1ユーザーとして嬉しいです)

※2008.9.20日追記。"BuleMSX"はver2.8でだいぶ改善されたようです。素晴らしい!!
※上記は"WindowsXP SP2"環境で動作を確認したものです。
 

2008.05.06 Written by Kitao Nakamura.


「パソコン環境による遅延」の解消方法についても記載しました。
「パソコン環境による遅延」の解消方法
こちらのページをご覧ください。


"Ootake" Homepage へ 戻る


 


This page is link free. このページはリンクフリーです。

Copyright(C)2006-2008 Kitao Nakamura.