C
C++
console

コンソールゲーム制作 第1章 描画(3)

前回

コンソールゲーム制作 第1章 描画(2)
前回はコンソールでゲームを作るならWriteConsoleOutputが適切であるという結論が出たので今回はその使い方を説明します。

WriteConsoleOutputの使い方

この記事ではそんなに細かくは解説しないので、わからない場合は下記リンクでご確認ください。
MSDN - Write Console Output

writeconsoleoutput.h
BOOL WriteConsoleOutput(
  HANDLE hConsoleOutput,      // スクリーンバッファのハンドル
  CONST CHAR_INFO *lpBuffer,  // データバッファへのポインタ
  COORD dwBufferSize,         // コピー元バッファのサイズ
  COORD dwBufferCoord,        // コピー元長方形の左上隅のセル
  PSMALL_RECT lpWriteRegion   // 書き込み先長方形
);

第一引数:スクリーンバッファハンドル
・自分で変更していなければ標準のハンドルをGetStdHandle(STD_OUPUT_HANDLE)で取得できます。
第二引数:データバッファへのポインタ
・自分で用意した画面の大きさ分のセル情報の配列(例:画面サイズ100x20の場合、CHAR_INFO[20][100]の配列へのポインタを使用する)
・上で用意した配列の大きさですが、COORD型なのでX,Yで表します。上記と同じの場合はCOORD(X=100,Y=20)になります。
第三引数:コピー減長方形の左上隅のセル
・書き込みのスタート座標です。左上からスタートしたい場合はCOORD(X=0, Y=0)になります。
第四引数:書き込み先長方形
・上のスタート位置から長方形のエリア作ってそのエリア内で書き込みます。用意してきたセル分丁度書き込みたい場合はSMALL_RECT(left=0, top=0, right=99, bottom=19)になります。

実際のソースコード

main.cpp
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CHAR_INFO ci[20][100] = {};
COORD buffer_size = { 100, 20 };
COORD start_coord = { 0, 0 };
SMALL_RECT sr = { 0, 0, 99, 19 };

WriteConsoleOutput(handle, (CHAR_INFO*)ci, buffer_size, start_coord, &sr);

呼び出し自体はこれでできますが、一番重要なのは画面に表示する内容が格納されているCHAR_INFOの配列です。

char_info.h
typedef struct _CHAR_INFO {
  union {
    WCHAR UnicodeChar;
    CHAR  AsciiChar;
  } Char;
  WORD  Attributes;
} CHAR_INFO, *PCHAR_INFO;

UnicodeChar, AsciiChar, Attributesの3要素が入っていますが、プロジェクトの設定がマルチバイト文字かUnicode文字かで利用されるものは変わります。UnicodeならUnicodeCharマルチバイトならAsciiCharです。
今回はマルチバイトで行きます。

AsciiCharCHAR型になっているので1バイト文字が一文字入ります。(例:'a', 'c', '', '-'...)
そしてAttributesには色の情報が入りますがWORD型です。コンソールに設定されている色を確認するにはコンソールのプロパティを確認します。
image.png
色は自由に変えられますが、同時に利用できるのが16色です。
それぞれの色は番号を持っていて、左から0~15です。
Attributesには文字の色だけではなく背景色も一緒に入っていて4ビットずつ使っています。
なので設定する際は背景色は色番号
16、文字色は色番号になります。
(例:文字-黄(15)、背景-赤(5)の場合は 5 * 16 + 15 = 95になります。)

左上のセルに緑背景、青文字の'B'を表示したい場合は

ci[0][0].AsciiChar = 'B';
ci[0][0].Attributes = 6 * 15 + 7;

になります。

次回

以上がWriteConsoleOutputの解説です。
このままではチラつきのない描画は可能ですが、扱いが面倒くさいので次回はprintfに近い感覚で
WriteConsoleOutputを使った描画ができるようにプログラムを組みます。

ありがとうございました。