// スタート画面
function drawStartScreen() {
ctx.fillStyle = "#222";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#fff";
ctx.font = "32px sans-serif";
ctx.textAlign = "center";
ctx.fillText("ありくいアクション", canvas.width / 2, canvas.height / 2 - 100);
ctx.font = "16px sans-serif";
ctx.fillText("←→ 移動 | スペース ジャンプ | ↑ 攻撃", canvas.width / 2, canvas.height / 2 + 50);
ctx.fillText("スペースキーまたは画面をタップでスタート", canvas.width / 2, canvas.height / 2 + 150);
ctx.font = "12px sans-serif";
ctx.fillText("© 2025 たかまる", canvas.width / 2, canvas.height / 2 + 250);
}
// ゲームオーバー画面
function drawGameOver() {
ctx.fillStyle = "rgba(0,0,0,0.7)";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "#fff";
ctx.font = "bold 48px sans-serif";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("ゲームオーバー", canvas.width / 2, canvas.height / 2 - 20);
ctx.font = "24px sans-serif";
ctx.fillText("スペースキーまたは画面をタップで再スタート", canvas.width / 2, canvas.height / 2 + 40);
}
function mainLoop() {
if (gameStarted) return;
drawStartScreen();
requestAnimationFrame(mainLoop);
}
mainLoop();

イカクくん
fillは塗りつぶしだったよね!

たかまる
そうそう!
そしてRectはRectangle(長方形)だったよね!
.fillRect(x座標, y座標, width, height);
が基本形だよ。
fillText
ctx.fillText("ありくいアクション", canvas.width / 2, canvas.height / 2 - 100);

イカクくん
– 100がついてるけど、どうなるの?

たかまる
中央から上に100ずれるよ。


イカクくん
ここで幅が中央に指定されてるなら、
ctx.textAlign = “center”;
この中央寄せの指示って必要ないんじゃないの?
textAlign(横方向)

たかまる
テキストにも基準点があって、
デフォルトは左下なんだ。

イカクくん
ってことは、textAlign = “center”;がないと、
中央より右寄りで若干上に表示されてしまうのか。

textBaseline(縦方向)

イカクくん
んじゃ縦方向も中央寄せにしたい場合どうしたらいいの?

たかまる
textBaseline = “middle”;
だから、今回の場合だと
ctx.textBaseline = “middle”;
でOK!
ループ
function mainLoop() {
if (gameStarted) return;
drawStartScreen();
requestAnimationFrame(mainLoop);
}
mainLoop();
このコードは、スタート画面(タイトル画面)をアニメーションループで表示し続けるための基本構造。
ざっくり言うと:
- ゲームが始まったら実行を中断して抜ける。
(drawStartScreen()やrequestAnimationFrame()は実行されない) - ゲームが始まっていなければ、
- 毎フレーム
drawStartScreen()を呼び出して描画 requestAnimationFrame(mainLoop)で繰り返す
return
関数の中で return を書くと、その行で関数の実行を中断して抜ける。
戻り値を返すときにも使うが、今回は「処理の終了」が目的。
| 書き方 | 意味 |
|---|---|
return; | 関数の処理をそこで終了 |
return 値; | 関数の結果として値を返す |
if (...) return; | 条件が合えば関数を早く抜ける |
requestAnimationFrame(関数名);
「次の画面更新の直前に、この関数を呼んで!」とブラウザにお願いする関数。
ブラウザは画面を 1 秒間に 60 回くらい更新(リフレッシュ)している。(= 約60FPS)
✅ 実行の流れ
mainLoop()が実行されるgameStartedがfalseなのでdrawStartScreen()が実行される- 次のフレームで
mainLoop()が再度呼ばれる - …繰り返し(60FPS)
gameStarted = trueになると、returnで描画を停止

イカクくん
elseは使わないの?

たかまる
else がなくても処理が分かれる理由は、if の中で関数が途中終了するから。
あと{}で囲ってないから、ifが適用されるのは
if (gameStarted) return;
の、1行のみだよ。
// A: returnで早期終了するパターン
if (gameStarted) return;
drawStartScreen();
requestAnimationFrame(mainLoop);
// B: elseを使うパターン
if (gameStarted) {
return;
} else {
drawStartScreen();
requestAnimationFrame(mainLoop);
}
どちらも動作は同じ。
function mainLoop() {
if (gameStarted) return; // この行はゲームが始まったら実行を中断するだけの指示
drawStartScreen();
requestAnimationFrame(mainLoop);
}
// なので、ゲームが始まっていない時は↓と同じってこと
function mainLoop() {
drawStartScreen();
requestAnimationFrame(mainLoop);
}
mainLoop();
function mainLoop() {
if (gameStarted) return;
drawStartScreen();
requestAnimationFrame(mainLoop);
}
mainLoop(); // ←これのこと!

たかまる
これは単純に関数の 呼び出し(実行)だよ。
| 書き方 | 意味 |
|---|---|
mainLoop(); | mainLoopを1回だけ実行する |
requestAnimationFrame(mainLoop); | 次のフレームでまた実行して…を繰り返す |

たかまる
今回はここまで。
次のページでゲーム開始の処理を解説していくよ。
コメント