====== プレイ画面を完成させていく ====== === 前回までの状態 ===
{{: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 タイルのスライド処理へ]] ;#;