====== プレイ画面を完成させていく ======
=== 前回までの状態 ===
{{:game-engineer:classes:2023:something-else:summertime-special-cource:20230804-175753-041.png?300|}}
枠だけ表示できている
こんな状態、これをもう少しかっこつけていく。\\
- 枠の内部に色を塗る
- 枠の大きさを調整
- 枠内にタイル番号を描画
この処理を追加していく\\
==== 枠の内部を塗る ====
- **枠の内部に色を塗る**
- 枠の大きさを調整
- 枠内にタイル番号を描画
これは実は簡単で、すでにRectの配列は作ってあるので、各Rectを好きな色で塗っていけばよい。\\
PlayDrawを書き換えるよ。\\
タイルの塗りつぶし
void PlayDraw(Board& _board)
{
// 背景の色を設定する | Set the background color
Scene::SetBackground(Palette::Lemonchiffon);
//StringはSiv3Dだけでつかえる stringの上位互換型
String PlayStr = U"プレイ画面";
FontAsset(U"TITLE_FONT")(PlayStr).drawAt(Scene::Center(), Palette::Cadetblue);
for (int j = 0; j < BOARD_HEIGHT; j++)
{
for (int i = 0; i < BOARD_WIDTH; i++)
{
//タイル矩形の塗りつぶし
_board.tileRec[j][i].draw(好きな色で塗ればいいよ);
//タイル枠を書く
_board.tileRec[j][i].drawFrame(2, 0, Palette::Red);
}
}
}
{{:game-engineer:classes:2023:something-else:summertime-special-cource:masu1.png?300|実行結果}}
タイル塗りつぶし実行結果
なんかうまく行ったっぽいけど、枠を消してみる。\\
{{:game-engineer:classes:2023:something-else:summertime-special-cource:masu2.png?300|}}
タイル領域塗りつぶし(枠なし)
そりゃそうだよね。タイルが、画面いっぱいに隙間なく敷き詰められるように計算しているし、同じ色で塗ってるもんね。
全部同じ色になる。。。\\
そこで次。\\
==== 枠の大きさを調整 ====
- 枠の内部に色を塗る
- **枠の大きさを調整**
- 枠内にタイル番号を描画
ちょっと見やすくするために、枠の大きさを調整して、タイルとタイルの間に隙間を作る。\\
これも簡単。枠を上下左右2ピクセルずつ縮小して、その分ずらして枠の真ん中にタイルが表示されるように調整する。\\
表示の時に毎フレーム調整してもそんなに手間にはならないけど、初めから位置をずらして登録してみよう。\\
InitBoardをいじっていく。\\
{{:game-engineer:classes:2023:something-else:summertime-special-cource:shukusho2.png?300|枠のサイズ調整}}
枠調整後のイメージ
枠の大きさを調整する
void InitBoard(Board& _board)
{
for (int j = 0; j < BOARD_HEIGHT; j++)
{
for (int i = 0; i < BOARD_WIDTH; i++)
{
_board.tile[j][i] = j * BOARD_WIDTH + i + 1;
_board.tileRec[j][i] = Rect{ ここで、座標をずらして登録する };
}
}
}
{{:game-engineer:classes:2023:something-else:summertime-special-cource:wakuari.png?300|}}
調整結果
あとはDrawFrameとかで内側何ピクセルか塗るとかすると、ちょっと見やすくなる。(ついでにシラーっと”プレイ画面”の描画を前に出した)\\
そこは好き好きで!\\
{{:undefined:wakucomp.png?300|}}
枠完成
==== タイル番号の表示 ====
- 枠の内部に色を塗る
- 枠の大きさを調整
- **枠内にタイル番号を描画**
あとは、枠の中にタイル番号を表示する。\\
タイル番号は
struct Board
{
// 行 列
int tile[BOARD_HEIGHT][BOARD_WIDTH];
Rect tileRec[BOARD_HEIGHT][BOARD_WIDTH];
};
のBorad::tile[行][列]に入っている。\\
これ取ってきて、その場所の、Rectの真ん中に表示してあげるとそれっぽくなる。\\
Mainに、ナンバー表示用のFontAssetを追加する。\\
(別にTITLE_FONTとか使いまわしてもいいよ。\\
下のSDFフォントってやつを使うと、FONTを拡大縮小しても、表示のクオリティが下がることないらしいよ。\\
(っていう意味では、TITLE_FONTの大きさ変更して表示してもよかったな。)
詳しくは、[[https://zenn.dev/reputeless/books/siv3d-documentation/viewer/tutorial-font#14.16-%E8%87%AA%E7%94%B1%E3%81%AB%E6%8B%A1%E5%A4%A7%E7%B8%AE%E5%B0%8F%E3%81%A7%E3%81%8D%E3%82%8B%E3%83%95%E3%82%A9%E3%83%B3%E3%83%88%E3%82%92%E4%BD%BF%E3%81%86%EF%BC%88sdf-%2F-msdf%EF%BC%89|公式ページの解説]]をみてね。\\
FontAsset::Register(U"TILEFONT", FontMethod::SDF, 75, Typeface::Bold);
矩形の中心座標は\\
//左上x,y 幅高さがwidthの四角形
Rect rec{x, y, width};
//その四角形の中心座標
rec.center();
で取得できる。これを、FontAsset().drawAt(四角形の中心座標)で描画すると、**フォントの真ん中を、四角形の真ん中に合わせて描画**してくれる(超便利すぎ機能)\\
=== 数値と文字列の変換 ===
もう一つ、数値→文字列の変換が必要になる。これもSiv3Dには便利な関数が登録されている。\\
ただし、Siv3DのString型にのみ変換できる。\\
(std::stringとかに変換したいときは、別の変換関数を使うけど、似たような関数があるからあとで調べてみて)\\
(ってのも、Siv3Dだけできても、ゲーム業界じゃ通用しないので、C++の標準関数も勉強しないとダメです)\\
int a = 100;
//数値→文字列(String型)の変換
String str = ToString(a);
タイル番号を描画
void PlayDraw(Board& _board)
{
// 背景の色を設定する | Set the background color
Scene::SetBackground(Palette::Lemonchiffon);
for (int j = 0; j < BOARD_HEIGHT; j++)
{
for (int i = 0; i < BOARD_WIDTH; i++)
{
_board.tileRec[j][i].draw(Palette::Burlywood);
_board.tileRec[j][i].drawFrame(2, 0, Palette::Saddlebrown);
FontAsset(U"TILE_FONT")(_board.tile[j][i]をStringに変換した文字列)
.drawAt(_board.tileRec[j][i]の真ん中の座標);
}
}
//StringはSiv3Dだけでつかえる stringの上位互換型
String PlayStr = U"プレイ画面";
FontAsset(U"TITLE_FONT")(PlayStr).drawAt(Scene::Center(), Palette::Cadetblue);
}
{{:game-engineer:classes:2023:something-else:summertime-special-cource:boardnumb.png?300|}}
タイル番号表示まで
==== 空白タイルの設置 ====
最後に空白タイルを設置する。\\
設置するって言っても、もともとコンソール版でも以下のように設定して、設定された番号をスルーしていた。\\
const int BLANK_POS = 16;
つまり描画処理でボードのタイル番号がBLANK_POSの時だけスルーすればよい\\
こう書くとできそうな気がする。\\
for (int j = 0; j < BOARD_HEIGHT; j++)
{
for (int i = 0; i < BOARD_WIDTH; i++)
{
if(タイル番号 != BLANK_POS)
{
タイルの描画処理;
}
}
}
当然これでもよいが、今回は新登場で、ループ制御構文のcontinueを使ってみよう。\\
continueを使うと条件に合った時だけスルーできる。\\
continueによるループ制御
#include
using namespace std;
int main() {
//1~10までの奇数だけ表示
for(int i=1; i<=10; i++){
if(i % 2 == 0)
continue;
cout << i << " " ;
}
}
結果:\\
1 3 5 7 9
こうすることで、ブロックが1個減るのでコードが見やすくなる(はずと信じてる)。\\
=== スペースの設置実際のコード ===
空白部分を設置
void PlayDraw(Board& _board)
{
// 背景の色を設定する | Set the background color
Scene::SetBackground(Palette::Lemonchiffon);
for (int j = 0; j < BOARD_HEIGHT; j++)
{
for (int i = 0; i < BOARD_WIDTH; i++)
{
_board.tile[j][i]にBLANK_POSを見つけたらcontinueでskipする
_board.tileRec[j][i].draw(Palette::Burlywood);
_board.tileRec[j][i].drawFrame(2, 0, Palette::Saddlebrown);
FontAsset(U"TILE_FONT")(ToString(_board.tile[j][i])).drawAt(_board.tileRec[j][i].center());
}
}
{{:game-engineer:classes:2023:something-else:summertime-special-cource:blankpos.png?300|}}
skip処理の描画結果
次は、ついに数字を入れ替えて営く処理を書いていこう\\
;#;
[[game-engineer:classes:2023:something-else:summertime-special-cource:slidepuzle-siv3d-5|その5 タイルのスライド処理へ]]
;#;