0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C++でローグライクを作成してみる - 3. マップを表示する

Posted at

概要

まず,タイル情報を表すクラスを作成し,そのタイルを縦横に(自由に)並べる.タイルの配列情報から,いわゆるゲームの「マップ」を画面に表示する.

はじめに

前回

前回は,画面に文字列が表示できるようになるところまで行きました.まだまだHello World状態です.

今回

文字が表示できるようになったので,次は文字を並べてマップを表示することが目標です.
よくあるRPGのタイルマップのシステムのイメージで,まずはタイル(文字)と対応するenum classを作成します.その列挙体の各要素とタイル情報を結び付け,マップそのものは列挙体の要素を並べることで記憶します.
そして,出力部でマップの配列とタイル情報を読み込んで画面に描画します.

開発環境

Windows11 Home 25H2
Visual Studio Community 2022

使用している外部ライブラリ:
SDL3 (version: 3.2.26)
SDL3_ttf (version: 3.2.2)

タイル情報の作成

まず,使うタイル(文字)の種類の数だけ,列挙体として名前を付けておきます.

enum class TileType : short
{
    WALL,
    FLOOR,
    STAIR_DOWN,
    STAIR_UP
};

そして,各タイルが持つべき情報を構造体として宣言します.

struct TileData
{
    char mChar[2];
    struct SDL_Color mColor;
    struct TTF_Text* mText;
};

ここではタイルの文字,色,TTF_Text(描画情報)を含めていますが,いずれは見た目の情報に限らず,例えばキャラクターが通れる/通れないのフラグなども入れるのが妥当でしょう.(文字や色はTTF_Textから読み出せるので実のところこれは冗長ですが)
では,列挙体の要素と構造体のインスタンスをゲームの初期化部分で結び付けておきます.具体的には,列挙体の要素をKeyとする連想配列(std::unordered_map)を用意します.

const SDL_Color temp = { 255, 255, 255, 255 };
mTileInfo[TileType::FLOOR] = { ".", temp, TTF_CreateText(mEngine, mFont, ".", 0) };
mTileInfo[TileType::WALL] = { "#", temp, TTF_CreateText(mEngine, mFont, "#", 0) };
mTileInfo[TileType::STAIR_DOWN] = { ">", temp, TTF_CreateText(mEngine, mFont, ">", 0) };
mTileInfo[TileType::STAIR_UP] = { "<", temp, TTF_CreateText(mEngine, mFont, "<", 0) };

また,初期化部分でマップを表す二次元配列を作っておきましょう.
今回はまだ自動生成したりはしないので適当にタイルを並べます.

// std::vector< std::vector<TileType> > DungeonMap;
const int x = 100;
const int y = 100;
DungeonMap.resize(y);
for (int i = 0; i < y; ++i) {
	for (int j = 0; j < x; ++j) {
		DungeonMap[i].emplace_back(TileType::WALL);
		if (j > x / 10 && j < x * 9 / 10 && i > y / 10 && i < y * 9 / 10) {
			if ((j * 67 + i * 89) % 41 > 4) {
				DungeonMap[i][j] = TileType::FLOOR;
			}
		}
	}
}
DungeonMap[15][7] = TileType::STAIR_UP;
DungeonMap[13][10] = TileType::STAIR_DOWN;

マップの表示

ゲームの出力部分(これまではHello Worldだった部分)を書き換えます.
マジックナンバーが多めなのは許していただくとして,先ほど用意した100×100マスの内,左上の20×25マスを表示します.

SDL_SetRenderDrawColor(mRenderer, 0, 0, 0, 255);
SDL_RenderClear(mRenderer);

for (int i = 0; i < 20; ++i) {
	for (int j = 0; j < 25; ++j) {
    	TTF_DrawRendererText(mTileInfo[DungeonMap[i][j]].mText, j * 30.0f, i * 30.0f);
	}
}
SDL_RenderPresent(mRenderer);

image.png

きちんと表示できました!

さらに,このままだとマップの右下部分を見るために,入力に応じて描画する範囲をずらしてみます.
入力システムについては次回検討しますが,今回のところは適当に入力を得たと仮定して,画面左上のマップ座標をmap_x, map_yに保持しておきます.
マスを描画する部分のコードに配列の範囲外メモリアクセスを防ぐ条件文を追加しつつ,マップ配列の適切な場所を読み込みましょう.

if (i + map_y >= 0 && i + map_y < 100 && j + map_x >= 0 && j + map_x < 100) {
    TTF_DrawRendererText(mTileInfo[DungeonMap[i + map_y][j + map_x]].mText, j * 30.0f, i * 30.0f);
}

image.png

map_x, map_yに最大・最小を設けなければどこまでも何もない空間に進んでしまいますが,一応マップの中を動くことができるようになりました.

おわりに

ようやく見た目がゲームを目指していることが分かるようになって一安心です.次回はキー入力について検討します.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?