C応用9 ドット絵を使う(ダブルバッファ)
C応用9 ドット絵を使う(ダブルバッファ)
ドット絵を表示するプログラムを使って、ダブルバッファの仕組みを学んでいきます。また、コンソールウィンドウでドット絵を表示するプログラムは、CPUへの負担が大きく、非常に遅いプログラムになってしまいます。このように遅いプログラムを、どのように性能改善するかについても、体感してもらいます。
コンソールウィンドウにドット絵を表示する場合、画像データの1ピクセル(1ドット)を全角1文字にして、背景色で色を表示させるようにします。このため、フォントサイズを小さく、画面サイズを大きくする必要があります。この操作をプログラムを実行する度に行うのは大変なので、フォントサイズと画面サイズの変更をプログラムで行う様にしています。ただ、この変更を行うためのWindowsAPIはWindowsターミナルと呼ばれるコンソールウィンドウでは動作しません。このため、本章のプログラムを実行するためには、コンソールウィンドウを、Windowsコンソ-ルホストにしなければなりません。Windows11(2022Update)より前のバージョンでは、Windowsコンソ-ルホストが既定のコンソールウィンドウでしたが、Windows11(2022Update)以降、Windowsターミナルが既定のコンソールウィンドウになっているため、本章のプログラムを動かすためには、コンソールウィンドウの設定を変更する必要があります。WindowsターミナルからWindowsコンソールホストに変更する方法については、「2022年11月の月例WindowsUpdateへの対応 」を参照ください。
障害物をよけながら、決められた燃料で、どれ位飛べるかを競うゲームを作成します。
画像ファイルのキャラクタを読み込み、ドット絵として表示します。CPU負荷の高いプログラムのため、非常に遅く、キャラクタ表示もチラチラしてゲームできる状態になっていません。
ダブルバッファ方式に変え、更に性能改善することで、ゲームが出来るレベルにまでプログラムを成長させていきます。
・ドット絵を使ったプログラム
練習問題64では遅さを、練習問題65ではダブルバッファ方式により画面のチラツキが無くなることを、練習問題66では性能改善を体感してもらいます。
・背景を横スクロールさせて空飛ぶ飛行機に見せる
空を飛ぶ飛行機は、背景の絵を横スクロールさせ、飛行機は同じ位置に表示することで実現します。
・フォントと画面サイズを変更
1ドットを全角1文字で表示させるため、フォントサイズを小さく、画面サイズを大きくします。
・背景は回転させるイメージ
背景を単純に横スクロールさせるだけでなく、連続的に回っているイメージにするための工夫をする。
・ダブルバッファでチラツキがなくなる
表画面と裏画面を用意し、見せる画面を瞬時に切替えることで画面のチラツキが無くなります。
・負荷の高い関数を見つけて性能改善
性能改善は、CPU負荷の高い関数を見つけることから始めます。今回のプログラムの中では、WriteConsoleの負荷が高いため、呼出し回数を減らす、出力文字数を減らすことをします。
右下のYouTube動画の説明の所に、ベースのプログラムをダウンロードするURLが記載されていますので、これをダウンロードしてビルド・実行してみてください。背景全体を毎回、書き直すロジックにしているため、コンピュータへの負荷が高く、ドット絵の動きがカクカクとしてしまっています。
これを、スムーズな動きにするため、ダブルバッファ方式に変更しますが、今回は、その準備をします。ダブルバッファ方式にするためには、printf関数ではなく、WriteConsole関数による表示に変更しなければなりません。WriteConsole関数による表示を行うMyPrintf関数がMyPrintf.cppに用意してあります。printf関数を、MyPrintf関数に変更し、 WriteConsole関数による表示に変更します。
(注意) WriteConsole関数で表示する場合、プロジェクトのプロパティの文字セットを「マルチバイト文字セットを使用する」に変更してください。「Unicode文字セットを使用する」だと、文字化けが発生します。
練習問題64で、printf関数からWriteConsole関数に変更すると、若干速くなりますが、相変わらず、チラついた表示のままです。今回は、ダブルバッファ方式に変更します。YouTube動画のコメントの所に、ダウンロードするURLが記載してあります。これは、ダブルバッファ方式に変更したMYPRINTF.cppとMYPRINTF.hです。練習問題64のプログラムのMYPRINTF.cppとMYPRINTF.hを、ダウンロードしたファイルに置き換えます。
ダブルバッファ方式に変更する場合は、ダブルバッファのための初期処理、終了処理と、表画面と裏画面の切り替えが必要になりますので、これらを行う関数呼出しをmain.cppに追加します。また、FPSとインジケータ表示は、表画面と裏画面同時に表示する必要がありますので、これらの表示については、表画面と裏画面同時に表示する関数呼出しに変更します。
これらの変更により、画面のチラツキはなくなります。
練習問題65のダブルバッファ方式に変更することで、ドット絵の動きがスムーズになりますが、動きは遅いままです。画面への書き込み回数を減らすことで、性能改善できます。画面への書き込み回数を減らす方式(まとめて表示方式)に変更したMYPRINTF.cppをダウンロードするためのURLが、YouTube動画の説明の所に書いてありますので、練習問題65のMYPRINTF.cppと置き換えます。この置き換えにより動きをかなり速く改善できます。更に、表示するデータ量を減らす工夫を加えることで、更に性能改善できます。
プレイヤーとボスの追いかけっこゲームを作成します。
大きなフィールドの中を歩くプレイヤーと、プレイヤーを追いかけるボス、プレイヤーはボスから逃げながら宝箱を探します。5つの宝箱を探すとプレイヤーは勇者に変身します。プレイヤーが勇者になるとボスは逃げだし、勇者になったプレイヤーがボスに追いつくとゲームクリアになります。勇者になる前にボスに追いつかれるとゲームオーバーになります。
大きなフィールドの中の位置分を表示し、プレイヤーの移動に合わせて、画面表示をスクロールさせる、というプログラムを作成した所、新たな性能問題に遭遇しました。この問題をどのように解決していったかを説明します。
・大きなフィールドの中の一部分を表示するウィンドウ
画面には「画面バッファ」と「ウィンドウ」という属性があります。大きな画面バッファの中の一部分をウィンドウの枠の中に表示するイメージになります。今回、大きなフィールドは「画面バッファ」の中に全てセットし、その一部分を「ウィンドウ」として表示します。プレイヤーの移動は、背景は変更せず、プレイヤーを移動させると共に、「ウィンドウ」の位置をずらすことで実現します。
・「歩く」は複数画像データの入った画像ファイルでアニメ表示
キャラクタの「歩く」は、歩く姿を複数の画像データに分解したデータを持つ画像ファイルを使って、アニメ表示します。上下左右に動くキャラクタは、歩く方向と何枚目の画像データを表示しているかをカウントするカウンタを構造体メンバに持たせることで実現します。
・性能劣化に対する新たな性能改善策の適用
大きな「画面バッファ」の一部分を「ウィンドウ」に表示する方法では、カーソル位置変更をWindowsAPIで行う必要があります。この方法だと、WriteConsoleの回数が増えてしまい、性能が劣化してしまいます。このため、新たな性能改善施策として、動いた部分だけを表示するようにしました。再表示領域を多めにとることにより、移動する前のキャラクタを消しながら、新たな場所に表示できるようになり、WriteConsoleの出力文字数を減らすことができ、性能改善できます。
プレイヤーとボスの追いかけっこゲームです。YouTube動画の説明の所に、ダウンロードのURLが書かれているので、そこからプログラムをダウンロードすると、ビルド・実行できます。ある程度は、性能改善したのですが、画面全体に、背景色が少しずつ変化する色を使っているため、どうしても動きが遅くなってしまいます。背景を黒一色にすることで、動きを速くすることができます。コンソールウィンドウにドット絵を表示する場合は、背景を1色にとどめる等の配慮が必要です。
プレイヤーが勇者になると、ボスがひげ出しますが、ダウンロードしたプログラムのままだと、壁にぶつかった途端、ボスは停止するので直ぐに捕まえることができてしまいます。ボスの逃げるロジックを用意しましたので、このロジックを追加してみます。壁にぶつかると、壁づたいに逃げ続けます。この逃げる関数は、YouTube動画の説明欄に、もう一つURLを記載しているので、そこからダウンロードしてください。