3D避けゲームを作ってみよう
体験入学用教材(30~40分)
3D避けゲームを完成させよう
今回は、3本のレーンを左右に移動しながら、前から来る敵を避ける3Dゲームを作り完成させます。
完成しプログラムのすべてを最初から書くのではなく、用意されているプログラムのTODO部分を順番に、少しずつ穴埋めをしていき完成させます。
1つの課題が終わるたらびに、必ず
- プログラムを書く
- ビルド
してする - 実行
し、する - ゲーム画面の変化を確認
しする
という流れで進めましょうす。
今日の目標
今日の体験では、次のことを学びます。
プログラムから3Dモデルを読み込む方法数学の式を使って、移動の速完成さを求める方法速さ × 時間で、そのフレームの移動距離を求める方法キー入力でキャラクターを動かす方法時間に応じてスコアを増やす方法敵に当たったときにゲームオーバーにする方法
今日作せるゲーム
このゲームではを完成させると、次のようなことが起こできるようになります。
- プレイヤー、敵、背景が
3Dで画面に表示される 道路READYのカウントダウン後にゲームが前へ流れる敵が前から来始まる- 左右キーで
3本のプレイヤーがレーンを移動できする - プレイ時間
がたつとに応じてスコアが増える - 敵に当たるとゲームオーバーになる
今日の作業では、ゲームづくりでよく使う次の考え方にも触れます。
- 変数
- 関数呼び出し
Init()、Update()、Draw()- フレームとFPS
deltaTime- 入力処理
- 条件分岐
- 距離・時間・速さ
- 当たり判定
作業を始める前に
Visual StudioでPlayScene_Exercise.cppを開いてください。
ファイルを開いたら、Ctrl + Fで次の文字を検索します。
TODO
今回修正する場所には、TODO 01からTODO 06までの番号が付いています。
【画像挿入①】完成1つのTODOが終わったら、必ずビルドしてから実行してください。
エラーが出たゲーム画面場合は、次のスクリーンショットTODOへ進まず、今書いた場所を入れる
例:プレイヤー、道路、敵、スコアが見えている画面確認します。
エラーが出たときに確認すること
- 英字の大文字と小文字が合っているか
"を消していないか(と)の数が合っているか- 行の最後に
;が付いているか - 全角文字をコードの中へ入力していないか
1.ゲームは変数と関数で動いている
変数は、ゲームの情報を覚える箱
プログラムの中心は PlayScene、ゲームに必要な情報を変数に保存します。
今回いちばん注目する変数は、数値や状態に名前を付けて覚えておくためのは PlayScene 箱です。
このゲームでは、たとえば次の情報を変数で管理しています。
| 変数 | 覚えている情報 |
|---|---|
|
カウントダウンなどの残り時間 |
score_ |
現在のスコア |
scrollSpeed_ |
道路や敵が流れる速さ |
state_ |
READY、プレイ中、ゲーム |
backgroundHandle_ |
読み込んだ背景画像を使うための番号 |
画像や3Dモデルそのものを、変数の小さな箱へ入れているわけではありません。
画像やモデルを読み込むと、それを使うための番号や情報が作られます。プログラムは、その番号を変数に覚えておき、必要なときに画像やモデルを表示します。
変数の値が変化すると、ゲーム画面にも変化が起こります。
- 位置の値が変わると、キャラクターが移動する
stateTimer_が減ると、カウントダウンが進行むscore_が増えると、画面の得点が増える- プレイヤーの状態が変わると、走る・倒れるなどのアニメーションが切り替わる
関数は、処理を書くまとめた命令
台本関数は、何らかの役目処理をまとめて名前を付けたものです。
たとえば、次のような命令を関数として用意できます。
Jump();
このコードは、Jumpという名前の関数を呼び出しています。
関数を呼び出すときは、基本的に次の形で書きます。
関数名();
関数によっては、丸かっこの中へ情報を渡します。
LoadModel("ファイルの場所");
丸かっこの中へ渡す情報を引数と呼びます。
今回のプログラムでも、関数を使って次のような命令を出します。
player_->SetRunState();
stage_->StartScroll();
enemies_->SetSpawning(true);
つまり PlayScene を読むと、
いつゲームが始まるのかモデルを読み込む- 背景画像を読み込む
- プレイヤー
がどうを左へ移動くのかさせる - プレイヤーを右へ移動させる
- 敵との当たり判定を調べる
2.ゲームは処理を繰り返して動いている
ゲームの画面は、1枚の画像を表示して終わりではありません。
入力を調べ、キャラクターの位置やスコアを更新し、新しい画面を描く処理を何度も繰り返しています。
今回使うPlaySceneには、大きく分けて次の3つの処理があります。
| 関数 | 役割 | 実行される回数 |
|---|---|---|
Init() |
モデルや画像などを準備する | 最初に1回 |
Update() |
入力、計算、当たり判定などを行う |
ゲーム中に何度も |
Draw() |
現在のゲーム画面を描く | ゲーム中に何度も |
流れを図にすると、次のようになります。
ゲーム開始
↓
Init()
↓
┌──────────────┐
│ Update() │
│ ↓ │
│ Draw() │
└──────┬───────┘
│
└─ 何度も繰り返す
この繰り返しをゲームループと呼びます。
1フレームとは
Update()でゲームの状態を更新し、Draw()で画面を描く1回分を、1フレームと考えます。
1秒間に何フレーム処理したかを表す値がFPSです。
FPSは、Frames Per Secondの略です。
$$ \mathrm{FPS}=\text{1秒間に処理するフレーム数} $$
たとえば60FPSなら、1秒間に約60回、更新と描画を行います。
ゲームは1フレームごとに少しずつ状態を変えるため、キャラクターが滑らかに動いて見えます。
3.TODO 01:モデルと背景を読み込もう
探す場所:
PlayScene_Exercise.cppのか157行目あたりにあるTODO 01
この課題で変わること
現在のプログラムでは、モデルと背景のファイル名が仮の名前になっています。
正しいファイル名を指定すると、プレイヤー、敵、背景がゲーム画面に表示されます。
Init()を探そう
TODO 01はInit()の中にあります。
Init()は、ゲームを始める前に必要なものを準備する場所です。
次の3つの関数が並んでいます。
LoadPlayerModel("Assets/XXX.mv1");
LoadEnemyModel("Assets/XXXXXXX.mv1");
LoadBackgroundImage("Assets/XXXXXXXX.png");
それぞれの関数名を日本語で考えてみましょう。
| 関数 | 読み込むもの |
|---|---|
LoadPlayerModel |
プレイヤーの3Dモデル |
LoadEnemyModel |
敵の3Dモデル |
LoadBackgroundImage |
背景画像 |
.mv1は3Dモデルのファイル、.pngは画像ファイルです。
作業
Assetsフォルダの中を確認する- プレイヤーとして使うモデルのファイル名を探す
- 敵として使うモデルのファイル名を探す
- 背景として使う画像のファイル名を探す
XXXなどの仮の部分を、見つけたファイル名へ書き換えるAssets/や拡張子まで含めて、正確に入力する
書くときの注意
文字列は"で囲みます。
"Assets/ファイル名.拡張子"
次の部分は消さないつゲようにしてください。
- 最初と最後の
" Assets/- モデルの
.mv1 - 画像の
.png - 行末の
;
動作確認
ビルドして実行します。
次の3つが表示されるか確認してください。
- プレイヤー
ムオーバーになるのか - 敵
- 背景
この時点では、READYの表示が分止まったままでも問題ありません。次の課題でカウントダウンを動かします。
4.TODO 02:カウントダウンタイマーを動かそう
探す場所:
PlayScene_Exercise.cppの395行目あたりにあるTODO 02
この課題で変わること
現在は、READYのカウントダウンが止まっています。
残り時間をフレームごとに少しずつ減らすことで、カウントダウンが進み、ゲームが始まるようになります。
今日の進め方deltaTimeとは
今日は、次の順番で進めます。
プレイヤーのモデルを表示する移動の速さを計算する- パソコンが1フレーム
で進む距離を計算処理する 左右キーでレーン移動させるスコアを増やす敵に当たったらゲームオーバーにする
大事1問終わるごとに、ビルド → 実行 → 動作確認をしてください。
課題01 プレイヤーを表示しよう
学ぶこと
ファイルパス文字列3Dモデルの読み込み
説明
ゲームの中の3Dモデル時間は、プログラムの中いつも完全に直接入っているわけで同じとはあ限りません。
前のフレームから今回のフレームまでに経過した時間を、ファイルの場所を指定deltaTimeに保存して読み込みいます。
$$
\Delta t=\text{前のフレームから今回までに経過したとえば時間}
$$
60FPS付近なら、プ1フレイヤームのモデル時間はおよそ次のファイル値です。
$$ \Delta t \approx \frac{1}{60} \approx 0.0167\ \text{秒} $$
30FPS付近なら、次のようになります。
$$ \Delta t \approx \frac{1}{30} \approx 0.0333\ \text{秒} $$
| FPS | 1フレームのおよその時間 |
|---|---|
| 60FPS | 約0.0167秒 |
| 30FPS | 約0.0333秒 |
30FPSでは1回に進む時間が大きく、60FPSでは1回に進む時間が小さくなります。しかし、1秒間に積み重ねると、どちらも約1秒になります。
タイマーを減らす考え方
現在の残り時間を(T_{\mathrm{now}})、次のフレームの残り時間を(T_{\mathrm{next}})とします。
毎フレーム、経過した時間だけ残り時間を減らします。
$$ T_{\mathrm{next}}
T_{\mathrm{now}}
\Delta t $$
プログラムでは、次の変数が対応しています。
| 数式 | プログラム |
|---|---|
| (T) | stateTimer_ |
| (\Delta t) | deltaTime |
作業
TODO 02を探します。
現在は、stateTimer_へ同じstateTimer_を代入しているため、値が変わりません。
Assets/run.mv1stateTimer_ = stateTimer_;
穴埋め問題
右辺を、次の空欄意味に、プレイヤーのファイル名を入れなる式へ変更してください。
constexpr現在の残り時間 const- char* PLAYER_MODEL_PATH =
"Assets/______.mv1";1フレームの経過時間
ヒント
使用する変数は次の2つです。
- 残り時間:
runstateTimer_ - 1フレームの経過時間:
deltaTime
想定解答
constexpr const char* PLAYER_MODEL_PATH =
"Assets/run.mv1";
動作確認
ビルドして実行します。
次の順番で変化するか確認してください。
- READYの数字が減る
- GOが表示される
- プレイヤー
の3Dモデルが表示され走るか確認 - 道路が動き始める
- 敵が出現する
5.関数を呼ぶと、複数のものが動き始める
カウントダウンが終了すると、プログラムはStartGameという関数を呼びます。
StartGameの中では、プレイヤー、道路、敵へそれぞれ命令を出しています。
StartGame
├─ プレイヤーを走る状態にする
├─ 道路のスクロールを始める
└─ 敵の出現を始める
1つの関数を呼ぶことで、ゲーム開始に必要な複数の処理をまとめて実行できます。
このように、複雑なゲームでも、処理を小さな関数へ分けることで分かりやすく整理できます。
6.TODO 03:左右キーの入力を完成させよう
【画像挿探す場所:PlayScene_Exercise.cppの105行目あたりにあるTODO 03
この課題で変わること
左矢印キーと右矢印キーを押したとき、プレイヤーへレーン移動の命令を出せるようにします。
入②】力処理とif
Update()はゲーム中に何度も呼ばれます。
その中でキーの状態を調べると、プレイヤーが表示キーを押したタイミングに反応できます。
if (条件)
{
条件が成立したときの処理
}
ifは、「もし条件が成立したら、中の処理を実行する」という命令です。
次のコードは、左矢印キーが押されたゲーム画面かを調べています。
if (Input::IsKeyDown(KEY_INPUT_LEFT))
{
// 左へ移動する命令
}
右矢印キーは、else ifで調べています。
else if (Input::IsKeyDown(KEY_INPUT_RIGHT))
{
// 右へ移動する命令
}
課題02作業
1レ
TODO 03-1とTODO 03-2の空いている場所へ、プレイヤーン分を移動させる関数呼び出しを書きます。
使用する関数名は次のとおりです。
| 方向 | 使用する関数名 |
|---|---|
| 左 | MovePlayerLeft |
| 右 | MovePlayerRight |
関数呼び出しの書き方を思い出してください。
関数名();
左側には左移動の関数、右側には右移動の関数を使います。
動作確認
ビルドして実行します。
この時点では、キー入力の処理は完成しますが、プレイヤーの移動速度が0.0fになっています。
そのため、左右キーを押しても、まだプレイヤーが動かないことがあります。
これは失敗ではありません。
キー入力の命令は完成
+
移動速度はまだ0
↓
移動する距離が0
次の課題で移動速度を計算すると、実際にレーン移動するようになります。
7.TODO 04:レーン移動の速さを計算しよう
探す場所:
PlayScene_Exercise.cppの26行目あたりにあるTODO 04
この課題で変わること
現在のプレイヤー移動速度は0.0fです。
レーン間の距離と、移動にかける時間から必要な速さを計算し、左右キーでプレイヤーが動くようにします。
距離・時間・速さの関係
一定の速さで移動するとき、距離、時間、速さには次の関係があります。
$$ d = vt $$
| 記号 | 意味 |
|---|---|
| (d) | 距離 |
| (v) | 速さ |
| (t) | 時間 |
今回は速さ(v)を求めたいので、式を次の形にします。
$$ v=\frac{d}{t} $$
つまり、
$$ \text{速さ}
\frac{\text{距離}}{\text{時間}} $$
です。
ミニワーク:必要な速さを求めよう
学ぶこと
距離
時間
速さ
定数
割り算
説明
このゲームでは、プレイヤーは3本のレーンを移動します。
レーンの位置は次のようになっています。
$$
左 = -12,
\quad 中央 = 0,
\quad 右 = 12
$$
つまり、中央レーンから右隣のレーンまでの距離は 12 が12.0です。
今回は、0.20秒でちょうど1レーン分の移動さを0.20秒で終わらせたいとします。
ここで使う次の式は次ですへ数値を入れて、必要な速さを計算してください。
$$
距離v
この式を、速さについて変形すると
$$
速さ = \frac{距離}{時間}
$$
になります。
今回の数値を代入すると、
$$
速さ =
\frac{12.0}{0.20}
\boxed{\qquad\qquad} $$
計算できたら、次の空欄へ記入してください。
必要な速さ:________
数値ではなく変数を使って式を書く
プログラムには、距離となり時間がすでに変数として用意されています。
つまり、1秒間に60進む速さにすれば、0.20秒で1レーン分移動できます。
【画像挿入③】レーンと距離の図を入れる
推奨画像ファイル:lane_speed_diagram.png
穴埋め問題
constexpr float LANE_DISTANCE = 12.0f;
constexpr float LANE_MOVE_TIME = 0.20f;
//
| 内容 | 変数名 |
|---|---|
| 1レーン分の距離 | LANE_DISTANCE |
| 1レーンの移動時間 | LANE_MOVE_TIME |
TODO 04では、次の空欄へ変数名を入れます。
constexpr float PLAYER_MOVE_SPEED =
________ / ________;
ヒント
数式の
- v=\frac{d}{t}
$$
と同じ順番になるように考えてください。
計算結果の数字を直接書くのではなく、距離
はLANE_DISTANCE - と時間
はを表す変数を使って式を書きます。LANE_MOVE_TIME
$$
想定解答
constexpr float PLAYER_MOVE_SPEED =
LANE_DISTANCE / LANE_MOVE_TIME;
確認
ビルドして実行するまだ左右キーは未完成なので、この時点では見た目の変化がなくてもよいただし、ビルドが通ることを確認する
課題03 1フレームで進む距離を求めよう
学ぶこと
deltaTime掛け算毎フレームの移動距離
説明
ゲ速さが決まっても、プレイヤームは、1回だを一度に1レーン分移動させるわけ画面を描いて終わりではありません。
1秒間に何十回も、次の処理をくり返しています。
入力を調べる
↓
ゲームの状態を更新する
↓
画面を描画する
この1回分を1フレームと呼びます。
実際には、フレームごとに経過少した時間ずつ位置を deltaTime とい変えています。
1フレームで進む距離は、次の式で求められます。
$$
移動距離\Delta =x=v\Delta 速さ \times 時間t
$$
プログラムでは、
| 記号 | 意味 |
|---|---|
| (\ |
そのフレームで |
| (v) | プレイヤーの速さ |
| (\Delta t) | 1フレームの経過時間 |
この細かい位置更新や、レーン中央で止める処理は完成済みです。
今回は、ゲームの仕様から速さを計算することになり注目します。
動作確認
【画像挿入④】1フレームごとの移動距離の図を入れるビルドして実行します。
推奨画像ファイル:左右矢印キーを押し、次のことを確認してください。frame_move_diagram.png
穴埋め問題
UpdatePlayerLaneMove(
______ * ______
);
ヒント
速さはプレイヤーが左右のレーンへ移動するplayerMoveSpeed_時間は1回の入力で隣のレーンへ移動するdeltaTime
想定解答
UpdatePlayerLaneMove(
playerMoveSpeed_ * deltaTime
);
0.20秒補足
この中の詳しい内部処理、たとえば
- で移動が終わる
は、今回は完成済みです。
今日は「速さ × 時間で距離を出している」という考え方だけ押さえましょう。
確認
ビルドして実行するこの時点ではまだ左右入力が未完成なので、見た目の変化がなくてもよいただし、移動距離の計算式が書けたことを確認する
課題048.TODO 左右キーでプレイヤーを動かそう
学ぶこと
キー入力if関数呼び出し
説明
今度は、左右キーが押されたとき05:時間に、レーン移動の命令を出します。
今回使う命令は次の2つです。
MovePlayerLeft();
MovePlayerRight();
穴埋め問題
if (Input::IsKeyDown(KEY_INPUT_LEFT))
{
______();
}
else if (Input::IsKeyDown(KEY_INPUT_RIGHT))
{
______();
}
ヒント
左へ動かす:MovePlayerLeft右へ動かす:MovePlayerRight
想定解答
if (Input::IsKeyDown(KEY_INPUT_LEFT))
{
MovePlayerLeft();
}
else if (Input::IsKeyDown(KEY_INPUT_RIGHT))
{
MovePlayerRight();
}
確認
ビルドし応じて実行する左右キーでプレイヤーがレーン移動するか確認する素早く2回押すと、2レーン移動できるか確認する
【画像挿入⑤】左右移動しているゲーム画面
課題05 スコアを増やそう
探す場所:
PlayScene_Exercise.cppの129行目あたりにあるTODO 05
学ぶこの課題で変わること
変数足し算時間経過
説明
ゲーム中現在は、時間がscore_へ同じscore_を代入しているたつほどめ、スコアが増えません。
1秒あたりの得点とdeltaTimeを使って、プレイ時間に応じてスコアを増やします。
1秒あたりの得点
プログラムには、次の定数が用意されています。
constexpr float SCORE_PER_SECOND = 100.0f;
これは、「1秒間プレイすると100点増える」という意味です。
今回ただし、Update()は1秒に1回ではなく、1秒あたり100点ずつ間に何度も呼ばれます。
そこで、1フレームで増えるようにしていやす得点を次の式で求めます。
$$ \Delta S=r\Delta t $$
| 記号 | 意味 | プログラム |
|---|---|---|
| (\Delta S) | 今回増やす得点 | これから計算する値 |
| (r) | 1秒あたりの得点 | SCORE_PER_SECOND |
| (\Delta t) | 1フレーム |
deltaTime |
$$
今回増える得点 = 1秒あたり現在の得点 \times deltaTime
$$
です。
そのため、スコアを(S_{\mathrm{now}})、次の更新式はスコアを(S_{\mathrm{next}})とすると、次のようになります。
$$
score_S_{\mathrm{next}}
S_{\mathrm{now}}
+
SCORE_PER_SECONDr\Delta \times deltaTimet
$$
穴埋め問題作業
TODO 05を探します。
現在は次のコードになっています。
score_ = score_;
次の形になるように空欄を考えてください。
score_ =
score_ + ________ * ________;
ヒント
使うものは次の2つです。
- 1秒あたりの得点
:SCORE_PER_SECOND 今回1フレームの経過した時間:deltaTime
想定解答
score_ = score_ + SCORE_PER_SECOND * deltaTime;
変数名は、すぐ上のコードや表から探してください。
動作確認
ビルドして実行します
る。
プレイ中、スコアが少しずつ増えていくか確認する- ゲーム
画面開始後にスコアが増える - 約1秒で、およそ100点増える
次のことを確認してください。
【画像挿入⑥】READY中はスコアが増えてないる
なぜ毎フレーム1点ではいけないのか
次のように毎フレーム固定で1点増やすとします。
1フレームごとに1点追加
60FPSなら1秒に約60点、30FPSなら1秒に約30点になります。
これではパソコンの処理速度によって得点の増え方が変わります。
deltaTimeを使うことで、FPSが変化しても、実際に経過した時間に合わせて得点を増やせます。
9.TODO 06:敵との当たり判定を有効にしよう
探す場所:
PlayScene_Exercise.cppの134行目あたりにあるTODO 06
この課題06で変わること
現在は、プレイヤーが敵に当たったら触れてもゲームオーバーになりません。
当たり判定を調べる関数を条件に使い、敵に当たったときだけ死亡処理を実行します。
trueとfalse
条件が成立していることをtrue、成立していないことをfalseで表します。
if (false)
{
// この中は実行されない
}
現在のプログラムは条件が常にfalseなので、敵に当たっても中の処理へ入りません。
戻り値
関数は、処理を行ったあとに結果を返すことがあります。
今回使う当たり判定の関数名はIsHitです。
この関数は、当たり判定の結果を次のどちらかで返します。
| 戻り値 | 意味 |
|---|---|
true |
敵に当たっている |
false |
敵に当たっていない |
作業
TODO 06を探します。
if (false)
falseの部分を、当たり判定を調べる関数呼び出しへ変更してください。
使用する関数名は次のとおりです。
IsHit
関数を呼び出すときは、関数名の後ろに丸かっこを付けます。
条件部分には、関数が返したtrueまたはfalseが使われます。
当たったときに実行される処理
条件がtrueになると、次の処理が実行されます。
敵に当たる
↓
死亡アニメーションへ切り替える
↓
道路の動きを止める
↓
敵の出現を止める
↓
ゲームオーバー画面へ移る
動作確認
ビルドして実行します。
次のことを確認してください。
- 敵へプレイヤーを当てる
- プレイヤーのアニメーションが変化する
- 道路が停止する
- 敵の出現が停止する
- ゲームオーバー画面へ移る
10.ゲーム全体の流れを確認しよう
今回完成させた処理を、ゲームループへ当てはめて確認します。
学ぶInit()で行ったこと
条件分岐プレイヤーモデルを読み込む真偽値敵モデルを読み込む- 背景画像を読み込む
- ゲームに必要なオブジェクトを準備する
Update()で行ったこと
- カウントダウンを減らす
- 左右キーの入力を調べる
- プレイヤーへ移動の命令を出す
- 時間に応じてスコアを増やす
- 敵との当たり判定を調べる
- ゲームの状態を切り替える
説明Draw()で行っていること
- 背景を描く
このプロジェクトでは、道路、草、木、プレイヤー、敵、スコアなどは、PlayScene::Draw()のあとに別の描画処理が自動的に表示します。
そのため、今回はDraw()のコードを変更していません。
11.完成チェック
次の項目をすべて確認してください。
- プレイヤーが
当たったかどうかは、IsHit()という関数で調べます。当たってい表示されるとき:true当たっていないとき:敵が表示されるfalse
-
背景が表示されるつまり、
if (IsHit())
は、**「もし敵に当たっていたら」**という意味です。
穴埋め問題
if (______)
{
LoadDeadMotion();
ChangeToGameOver();
return;
}
ヒREADYのカウント
IsHit()
想定解答
if (IsHit())
{
LoadDeadMotion();
ChangeToGameOver();
return;
}
確認
- ダウンが進む
ビルドして実行カウントダウン後にゲームが始まる- 左矢印キーで左へ移動する
- 右矢印キーで右へ移動する
- プレイヤーが約0.20秒で隣のレーンへ移動する
- ゲーム中にスコアが増える
- 敵に当たるとゲームオーバーになる
か確認する
12.今回学んだこと
変数
【画像挿ゲームの位置、時間、得点、状態などを覚えておくために使います。関数
処理をまとめた命令です。関数を呼ぶことで、モデルの読み込みやプレイヤーの移動などを実行できます。
ゲームループ
最初に
Init()を実行し、その後はUpdate()とDraw()を繰り返します。フレームとFPS
ゲームは1フレームずつ少しずつ状態を変えています。FPSは、1秒間に処理するフレーム数です。
deltaTime
前のフレームから今回のフレームまでに経過した時間です。
タイマー、移動、スコアなどを実際の時間に合わせて動かすために使います。
入
⑦】力処理
Update()の中でキー入力を調べ、押されたキーに応じて関数を呼びます。距離・時間・速さ
$$ v=\frac{d}{t} $$
という関係を使い、ゲームの仕様からプレイヤーの移動速度を求めました。
当たり判定
敵に当たっているかを関数で調べ、その結果が
trueのときだけゲームオーバー直前、またはゲームオーバー画面
まとめ
今回の体験では、完成済みのゲームに穴埋め処理を実行しながら、次のことを学びました。
3Dモデルの読み込み数式を使った移動速度の計算deltaTimeを使った1フレームの移動距離キー入力によるレーン移動スコアの更新当たり判定によるゲームオーバー
今日の特に大切な式は、次の2つです。
1. 速さを求める式
$$
速さ = \frac{距離}{時間}
$$
2. 1フレームで進む距離を求める式
$$
移動距離 = 速さ \times 時間
$$
ゲームプログラムでは、こうした数学の式が、そのままキャラクターの動きになります。
最後の自由調整
時間に余裕があれば、次の値を変えて遊んでみましょう。
constexpr float LANE_MOVE_TIME = 0.20f;
constexpr float SCORE_PER_SECOND = 100.0f;
試してみること
LANE_MOVE_TIMEを小さくすると、レーン移動はどう変わるかLANE_MOVE_TIMEを大きくすると、操作感はどう変わるかSCORE_PER_SECONDを大きくすると、スコアはどう変わるか
教員用メモ
この教材で完成済みにしているもの
背景画像の読み込みカウントダウンゲーム開始命令道路と敵の移動位置補正2レーン移動の内部処理ゲームオーバー遷移の内部処理
画像ファイル案
画像① 完成ゲーム画面画像② プレイヤー表示画面画像③lane_speed_diagram.png画像④frame_move_diagram.png画像⑤ 左右移動画面画像⑥ スコア増加画面画像⑦ ゲームオーバー画面