【Unity】チュートリアルの「Roll a Ball」をやってみる話 #11
記事をご覧いただき、誠に有難うございます。
投稿主の無能です。
今回は、制限時間を設けてみたいと思います。
制限時間を設ける
現状だと、ゲームには失敗する要素が無いので、時間さえ掛けることができれば、誰にでも絶対にクリアできてしまう状態になっています。
そこで、制限時間を設けて、制限時間内にクリアできなければステージ失敗、という風にしてみようと思います。
制限時間を表示するテキストを作る
まずは制限時間を表示するテキストを作ります。
UI_GameStatusを選択してメニュー Game Object > UI > Text - TextMeshPro を選択して、「CountDownTimer」というテキストを作成します。
UI_GameStatusを選択してメニュー Game Object > UI > Text - TextMeshPro を選択
「CountDownTimer」という名前でテキストを作成
テキストは色は赤にして、テキストの内容はスクリプトで操作するので、今回は「00」にします。
設定は自由に調整してください。
参考に、このような形になりました。
テキストを設定した
中央揃え・Bold(太字)・フォントサイズ48
Gameビュー
カウントダウンする仕組みを作る
制限時間なので、カウントダウンをしていく仕組みを作ります。
カウントダウンをする制限時間は任意で決められるものとします。
ここでは仮に10秒としておきます。
そして制限時間の10秒から、一定間隔、即ち時間を引いてあげれば良さそうです。
式として表すと
制限時間 - 一定間隔(時間) = カウントダウン
では実際に記述しますので、ProjectビューのScriptsフォルダからGameManagerスクリプトを開きます。
このような変数を追加します。
// 制限時間
public int countStartTime;
// 引き算される制限時間
private int currentTime;
// 制限時間を表示するテキスト
public TextMeshProUGUI UICountDownTimer;
このような記述になります。
private void Start()
{
// 制限時間を引き算される制限時間に代入
currentTime = countStartTime;
}
関数名は「CountDownTimer」とします。
関数を作成するにはStart関数やUpdate関数と同じでこのような記述になります。
このようになります。
あれ、エラーが出ています。
カウントダウンは、先程作成した変数currentTimeから時間を引いて、UICountDownTimerで表示させる、という流れになります。
このような記述になります。
void CountDownTimer()
{
// 制限時間からdeltatimeを引く
currentTime -= 1 * Time.deltaTime;
// 制限時間を表示する
UICountDownTimer.SetText("残り時間 : " + currentTime.ToString("00.00"));
}
エラー
currentTimeの型宣言をintからfloatに変えます。
このようになります。
currentTimeをintからfloatに変更
エラーが消えた
このTime.deltaTimeですが、直前のフレームから今のフレームまでの時間を表しています。
このTime.deltaTimeは結構使うので、他のdeltaTimeもあわせて覚えておきましょう。
検索すると丁寧な説明が出てきます。
そして演算子の「-=」ですが、右辺を引いた値を代入する、という意味になります。
四則演算の通りに「+=」「-=」「*=」「/=」があります。
ではスクリプトを保存して、Unityに戻ります。
GameManagerにCount Start TimeとUI Count Down Timerが追加されています。
Count Start TimeとUI Count Down Timerが追加されている
Count Start Timeは10秒、UI Count Down TimerはCountDownTimerを設定する
Gameビュー
エラーも出ていないし…
コンソールはメニュー Window > General > Console で出せる
またはCtrl+Shift+Cキーでキーボードショートカットできます。
エラーが出ていないのに、処理が行われないということは、処理がそこまで到達していない、ということになります。
今回はUpdate関数内でCountDownTimer関数を呼んでいない、という事が原因です。
例えるなら、折角助っ人を呼んだのに割り当てる仕事が無くて、助っ人がずっと棒立ちしているような感じです。
このようになります。
ではスクリプトを保存して、Unityでゲームを実行して確認します。
このような些細な事はスクリプトを書いていると往々にして起こります。
ですので留意しておくと共に、こまめにUnityでゲームを実行して確認する癖をつけておきましょう。
ではUpdate関数内でCountDownTimer関数を呼びましょう。
このように記述します。
// CountDownTimerでカウントダウン
CountDownTimer();
これをゼロ以下になったらゼロにする、制限時間になったらステージ失敗の処理をする、という2つの処理を追加します。
まずはゼロ以下になったらゼロにする、という処理を追加します。
GameManagerスクリプトに戻ります。
カウントダウンを制御する
カウントダウンをある一定の値になったら処理しない、という風な制御を追加します。
まずはカウントダウンをする・しないのbool値を追加します。
このような記述になります。
// カウントダウンを制御する
private bool isCountDown = true;
覚えておきましょう。
このようになります。
次に、Update関数内で呼んだCountDownTimer関数に追加していきます。
次に、CountDownTimer関数でゼロ以下になった時の処理を追加します。
このような記述を追加します。
// currentTimeが0以下の場合
if (currentTime <= 0)
{
// currentTimeを0にする
currentTime = 0;
// カウントダウン処理をしない
isCountDown = false;
}
このような記述になります。
// カウントダウンする場合
if (isCountDown == true)
{
// CountDownTimerでカウントダウン
CountDownTimer();
}
このifの条件の部分ですが、カッコ内がtrueであれば波カッコ内を処理する、というものでした。
ですので、bool値を条件として記述する場合、一般的な書き方としては
// カウントダウンする場合
if (isCountDown
{
// CountDownTimerでカウントダウン
CountDownTimer();
}と言う風に、比較演算子を省略して記述します。
比較演算子を用いて記述する場合、意味としては
true == true
と言う意味になるから省略する、という事ですね。
逆にfalseの場合は
ではスクリプトを保存して、Unityでゲームを実行して確認します。
これでカウントダウンがゼロ以下になったらカウントダウンが止まるようにできました。
// カウントダウンする場合
if (!isCountDown)
{
// CountDownTimerでカウントダウン
CountDownTimer();
}という風に、bool値の変数の前に「!」(エクスクラメーションマーク)を付けて、意味を逆にします。
上記の比較演算子を用いる記述方法も勿論合っていて問題無いのですが、スクリプトの処理がより分かりやすい書き方をする、というのも、スクリプトを書く上で重要な点となりますので、気を付けておきたいところです。
このようになります。
CountDownTimer関数が呼ばれないことを確認するので、10秒以上待機してください。
Gameビュー
次にステージ失敗を作ります。
StageFailedのテキストは黒にしました。
では、GameManagerスクリプトにステージ失敗の処理を追加します。
では、新たにStageClear関数とStageFailed関数を作ります。
そして、StageClear関数にUpdate関数内で記述したステージクリアの処理を切り取って持ってきます。
ここで、ステージクリア・失敗に関わらず、「ステージが終了した」という事をUpdate関数に知らせて、余計な処理をさせないようにします。
ステージ失敗のUIを作る
まずステージ失敗のUIを作成します。
UI_GameStatusを選択してメニュー Game Object > UI > Text - TextMeshPro でテキストを作成します。
StageClearと同様に設定します。
名前を「StageFailed」にします。
UI_GameStatusを選択してメニュー Game Object > UI > Text - TextMeshPro でテキストを作成する
名前を「StageFailed」にする
StageFailedはこのように設定しました。
Gameビュー
テキストを設定
ではこのStageFailedを非アクティブにします。
StageFailedを非アクティブにする
Gameビュー
ステージ失敗の処理を追加する
ステージ失敗の処理をGameManagerスクリプトに追加します。
ステージクリアの処理に似たような処理ですので、GameManagerスクリプトをより分かりやすくする(見やすくする)ように改修もしてしまいましょう。
このような記述になります。
// ステージクリアの処理
void StageClear()
{
}
// ステージ失敗の処理
void StageFailed()
{
}
このようになります。
このようになります。
Update関数内のステージクリアの処理を切り取る
StageClear関数内に貼り付ける
具体的には、StageClear関数を毎回呼ばないようにする、という処理をさせます。
先程切り取ったUpdate関数内のif文の処理に、StageClear関数を呼ぶ処理を記述します。
このように記述します。
// countがゼロになったら
if (count == 0)
{
StageClear();
}
このようになります。
Debug.Log("Stage Clear");
ではスクリプトを保存して、Unityに戻ります。
今回はステージクリアの処理がどうなっているのかを見るので、制限時間は余裕を持ってクリアできるようにしてください。
ステージクリアの処理が呼ばれると、コンソールは画像の様になっています。
コンソール画面
これは明らかに無駄な処理という事が分かります。
無駄な処理は何故ダメなのか?という事になりますが、このような無駄な処理が積み重なって重い処理へ発展してしまうことがあるからです。
このように小さな処理は、昨今のPCでは問題にならない程度のものでしょう。
しかし、このような処理が積み重なると、メモリを圧迫したり、CPUの処理能力を奪ってしまう原因になってしまいかねません。
最近のゲームなどは尚更、注意深く無駄な処理を軽減させようとするでしょう。
このような小さなプログラムだからこそ、無駄な処理を極力無くしていきましょう。
では変数を追加していきます。
追加するのは、ステージ失敗の時に表示するGameObject、ステージクリア・失敗に関わらず終了をUpdate関数に知らせるbool値になります。
このように記述します。
// ステージ失敗のUI
public GameObject UIStageFailed;
// ゲーム終了のフラグ
private bool isStageFinish = false;
ちょっとスクリプト内がごちゃついてきたので、整理してこのようになりました。
このような記述になります。
// ステージ終了フラグをtrue
isStageFinish = true;
このようになります。
次にStageFailed関数を記述します。
StageClear関数をコピーして、UIStageClearをUIStageFailedに変えてあげればいいだけです。
このようになります。
次に、Update関数内のステージクリアの処理をしているif文に処理を追加します。
ステージクリアの処理とステージ失敗の処理を分けます。
このように記述します。
// countがゼロになったら
if (count == 0)
{
// ステージが終了していない
if (!isStageFinish)
{
StageClear();
}
}
// カウントダウンしていない
else if (!isCountDown)
{
// ステージが終了していない
if (!isStageFinish)
{
StageFailed();
}
}
このようになります。
まずelse ifから説明します。
if文は、ifの条件の場合に当てはまらない場合に、else if(エルス イフ)で更に分岐することができます。
最初のifで収集アイテムを表すcountがゼロである場合、ここまではステージクリアで記述していました。
次のelse ifを付け加えることによって、else ifの前にあるifの条件に当てはまらない場合に、条件に合致するかを判断します。
そしてelse ifの条件に合致すれば、else ifの波カッコ内を処理する、という流れになります。
次に、if文の中にifが入っている状態ですが、この状態を「入れ子」(いれこ)と呼びます。
一般的には「nest」(ネスト)と呼ばれます。
ステージクリアの処理だと、まず最初のifで収集アイテムの数がゼロである、という処理をクリアします。
次にあるifでステージが終了していない場合にStageClear関数を呼ぶようになっています。
そして、ステージが終了している場合は、条件内の処理を実行しないようにしています。
これで先程、Debug.Logで試したStageClear関数が何度も呼ばれることが解消されます。
最初のうちは、何が何だか分からないとなりますが、スクリプトを書き慣れていけば自然と出来るようになっていきます。
条件分岐が入れ子になっている場合(if文がネストしている場合)は、大きい処理から落ち着いて読み解くようにしましょう。
最後に、Update関数内のカウントダウンの処理に追加します。
ステージが終了したらカウントダウンを止める
ステージが終了したら、カウントダウンを止める処理を追加します。
Update関数内のカウントダウンする処理にこのように記述します。
// カウントダウンする場合
if (isCountDown)
{
// ステージが終了していない
if (!isStageFinish)
{
// CountDownTimerでカウントダウン
CountDownTimer();
}
}
このようになります。
ではスクリプトを保存して、Unityに戻ります。
追加した項目を設定する
では追加した項目を設定しましょう。
まずはGameManagerに追加したUI Stage Failedです。
ここにStageFailedを設定しましょう。
効果音ラボさんから文字表示の衝撃音1という効果音をダウンロードしました。
前回オーディオ設定の仕方を説明したので、ここでは割愛します。
このような設定になりました。
StageFailedに効果音を設定した
制限時間は適切な値を設定しましょう。
ステージクリアの場合はカウントダウンが停止するかを、ステージ失敗の場合はStageFailedが表示され、効果音が鳴るか確認します。













































コメント
コメントを投稿