msオーダーの制御が必要になった自作ドラクエ。
ここにきて内部的な話しになり、目に見えない部分の為か進捗が悪くなる。
スムーズなマップスクロール処理の実現にあたり、大まかには下記の検討が必要となる。
・正確なタイマー制御(16ms,16ms,17msのリズムを刻む)
・1000ms内に60回の画面更新を行う
・その上で、この60回の更新に合わせたメインループ処理にする
元々、そんな作りになる事なんて当然想定していない、というか何も考えていなかったので、まずはメインループの処理を大きく見直そうと考え、そこから着手する。
ほとんどのゲームプログラムは下記の様な流れとなっている。
ゲーム処理
↓
処理した内容を表示画面に反映
↓
画面更新
↓
以下ループ
現状のプログラム構造だと、これら処理が各関数内にちらばっており、個別に処理が走っている状況。
これを全て、ゲーム処理後に同じ画面更新処理が走る様にしなければならないり
関数毎に独立した画面更新処理を作成した為、ここの大幅変更が必要となる。
トライ&エラーでコーディングしながら確認をしたが、下記の部分でかなり苦戦した。
メニュー処理、つまりプレイヤーからの入力を待っている状態。
この時においても画面更新処理を一つの箇所で実施しなければならず、統合するのに苦労した。
※苦肉の策でイレギュラーな処理にした為、あまり美しくないコードだが...
後は戦闘画面、これもメニュー処理と似ているが、プレイヤーからの入力によって画面更新が多彩に変化する画面においても、同様に画面更新を統合しなければならない。
ここも同様に美しくは無いが何とか実装はできた。
後はゲーム全体の処理を一定のタイミングを刻んで画面更新する処理を追加していくが、難しいのがマップスクロールにおける画面全体を移動方向にずらしていく処理。
画面はプレイヤーが指定した方向に対して、全体を1ドットずつずらす必要がある。
キャラクタチップは1キャラあたり16ドットなので、16ドット分のスクロールを実施する事になる。
更にスクロール処理中はキャラクタが動いているかの様にモーションさせる必要がある為、この時にキャラクタチップを入れ替えていく必要がある。
また、16ドットのスクロールが終えたら終了ではなく、その後もプレイヤーから連続してトリガーが入っていれば更にスクロールを続ける必要がある為、切れ目が発生しない様にしなければならない。
ある程度はスクロール処理が実現できたのだが、この「切れ目なく」が、どうしても一瞬止まってしまう現象が発生する。
しかも必ずではなく時々、というのが非常に厄介。
ここを改善する為に対策を考えた。
この現象は一般的にティアリングと呼ばれる現象らしく、別途説明しているfpsの考えと同じだが、要は画面更新が適切に行われていない。
これを防ぐ手法としてダブルバッファリング処理が必要になってくる事が分かった。
ダブルバッファはその名の通り、バッファを二つ設ける事。
画面更新におけるバッファとは画面データを保持する領域、メモリ、つまりVB6で言えばPictureBoxまたはそのデータを確保しているhDCの意味となる。
このバッファを二つに分け、内部バッファと外部バッファに振り分けて、内部バッファを更新して、ある程度の処理が終わったら内部から外部にコピーして初めて画面が表示されるというものだ。
元々はこの様な分け方はしておらず、外部バッファのみで、内部処理しつつ画面表示していた。これが原因でティアリングが発生している可能性がある事が分かり、ここでまた全体修正が必要になる。
fps制御、ダブルバッファ処理、ティアリング対策、これらをネットの情報を頼りに実現しようとするが、VB6ではこの様なプログラムを作っているサンプルが見つからない。
しかし他言語(VC等)の参考情報は大量に見つかるので、それらを参考にして自作するしか無いという結論に至り、ここで更に時間を要する事になる...。
続きはまた次回。