3 / 4 地形とゴールの描画
配布済みの地形配列と描画用の補助関数を使って Stage::Draw を実装し、Gameの描画順へ接続します。
配置用セルと地形セル
CSVの 2(開始位置)と 1(ゴール)は位置の目印です。ローダーはそれぞれのマスの中心座標を専用の変数へ保存し、地形配列 cells_ には StageCell::Empty を入れています。レンガと苔石は地形の種類として配列に残ります。
この分離によって、地形を順に描く処理と、開始位置の利用・ゴールの描画を別々に扱えます。地形衝突は第19回で実装します。
実装済みの描画用補助関数
Stage.cpp の tileDefinitions は、地形の種類と画像の対応を記録する定義表です。次は既存コードの抜粋です。
constexpr TileDefinition tileDefinitions[] =
{
{ StageCell::Brick, ImageId::Tile, true },
{ StageCell::Moss, ImageId::TileMoss, true }
};各行は地形の種類、画像ID、固い地形かを表す値の順です。最後の値は後の地形衝突で利用します。配布済みの DrawTile はこの表で画像を選び、指定された左上座標へ TileSize 四方で描きます。Stage::Draw からはマスの位置と種類を渡せば使えます。
新しい地形を増やす場合は、列挙値・画像ID・素材の登録も必要です。登録方法は第24回で扱います。ここでは既存の2種類を描き分けます。
Stage::Drawの実装
Source/Platformer/Stage.cpp の Stage::Draw を、次の関数で置き換えます。static_cast<void>(images); の仮の処理は残しません。
void Stage::Draw(const ImageManager& images) const
{
for (int y = 0; y < mapHeight_; y++)
{
for (int x = 0; x < mapWidth_; x++)
{
const StageCell cell = cells_[y][x];
if (cell == StageCell::Empty)
continue;
DrawTile(x * TileSize, y * TileSize, cell, images);
}
}
const dxgame::Rect goalDrawRect = GetGoalDrawRect();
images.Draw(ImageId::Goal, goalDrawRect);
}外側のループで行、内側で列を進めます。空白なら continue でそのマスを飛ばし、地形なら x * TileSize、y * TileSize を左上座標として描きます。32ピクセルのタイルでは、0列目はx=0、1列目はx=32です。
ゴールは地形配列から分けてあるため、ループの後で描きます。GetGoalDrawRect は保存したゴール座標に表示用の矩形を合わせる、実装済みの関数です。
Gameの描画順への接続
Game.cpp の Game::Draw で、背景を描いた直後、プレイヤーを描く前に呼び出しを追加します。地形をプレイヤーより先に描くことで、重なった場所でもプレイヤーが見えます。
void Game::Draw() const
{
DrawBackground();
stage_.Draw(images_);
player_.Draw(images_);
DrawHud();
DrawDebug();
}ビルドして実行し、CSVに対応するレンガ・苔石・ゴールが表示されることを確かめます。プレイヤーが地形を通り抜けるのは、この回では地形衝突が未実装だからです。
配置変更の確認
プロジェクト直下の Assets/Maps/Stage01.csv をコピーして保存します。画面内にあるレンガの 10 を一つだけ 11 へ変更し、どのマスが変わるか予想してからビルド・再実行します。表示が変わらない場合は、編集したCSVがプロジェクト直下のものか確認します。
次に、開始位置の 2 を隣の空白へ移してください。元のマスは 0 にして、2 が一つだけになるようにします。予想した位置から開始するかを確かめ、比較が終わったら保存したCSVへ戻します。
- 行・列の添字から、タイルの左上座標を計算できる
- 背景、地形とゴール、プレイヤーの順に描画できる
- CSVの地形と開始位置を変え、予想と表示を比較できる