
育成ゲームらしさが出てくるのは、放っておくとペットのおなかが空いてくるところ!何もしないと少しずつ元気がなくなっていくから、つい様子を見に来たくなるんですよね。今回はペット育成ゲームのシリーズの3回目として、「おなか」と「きげん」の数字をスクリプトで持たせ、時間がたつと減っていくゲージを作ってみたいと思います!
- シリーズの目次:ペット育成ゲームの作り方
- 前回:#2 ペットを表示して、ぴょこぴょこ動かそう
今回作るもの
- ペットの状態(おなか・きげん・コイン)を数字で持つ
- 時間がたつと、おなかときげんが少しずつ減る
- 減った数字を、#1で作ったゲージに反映する
- どちらかが少なくなったら、#2で作った「しょんぼり」に切り替える
- 何時間で空になるかを決めて、減る速さを計算する(ゲームのバランスの考え方)
今回からスクリプトを書いていきます。作るスクリプトは3つです。
| スクリプト | 役割 | 付ける場所 |
|---|---|---|
| PetStatus | おなか・きげん・コインの数字 | どこにも付けない(ただのデータ) |
| PetController | 数字を時間で減らす、しょんぼりに切り替える | Pet |
| StatusView | 数字をゲージとコインの表示に反映する | StatusBar |
前回の続きから
- Unityのバージョンは6.3 LTS
- 記事作成時点では6000.3.22f1で確認しています
- テンプレートはUniversal 2D
- #2の状態:ペットが待機のアニメーションで動いていて、AnimatorのSad(Bool)で泣き顔に切り替わる
変数とUpdateについては6-4 変数でデータを保存しよう、6-3 Start関数とUpdate関数を理解しよう、スクリプトからUIを書き換える方法は9-4 スクリプトからUIを更新しようで紹介しています。
ペットの状態を数字で持とう(PetStatus)
まずは、ペットの状態をまとめて持つためのスクリプトを作りましょう。
- PetRaising/Scriptsで右クリック>Create>MonoBehaviour Script で「PetStatus」を作り、中身を次のように書き換える
using System;
using UnityEngine;
// ペットの状態(おなか・きげん・コイン)をまとめたデータ
[Serializable]
public class PetStatus
{
public const float Max = 100f;
[Range(0f, Max)] public float hunger = 80f; // おなか(0でペコペコ)
[Range(0f, Max)] public float mood = 80f; // きげん(0で最悪)
public int coins = 0;
}
- MonoBehaviourを継承しない
: MonoBehaviourが付いていない、ただのクラス。GameObjectには付けず、ほかのスクリプトの中で変数として使う
- [Serializable]
- 付けると、このクラスを変数にしたときにInspectorに中身が表示される
- #6では、このクラスをそのままJSONにして保存します
- [Range(0f, Max)]
- Inspectorにスライダーが出る。0〜100の間でしか入力出来なくなる
- const float Max
- ゲージの最大値。数字を直接100と書かずに名前を付けておくと、あとで変えたくなったときに1か所直せばOK
時間で数字を減らそう(PetController)
次に、数字を時間で減らすスクリプトです。
- PetRaising/Scriptsに「PetController」を作る
using UnityEngine;
// ペットの状態を時間で減らし、少なくなったらしょんぼりさせる
public class PetController : MonoBehaviour
{
[SerializeField] private PetStatus status = new PetStatus();
[Header("バランス")]
[SerializeField] private float hoursToEmptyHunger = 6f; // おなかが100から0になるまでの時間(時間)
[SerializeField] private float hoursToEmptyMood = 8f; // きげんが100から0になるまでの時間(時間)
[SerializeField] private float sadLine = 30f; // これより少ないとしょんぼりする
[Header("確認用")]
[SerializeField] private float timeScale = 1f; // 時間の進む速さ(確認するときだけ大きくする)
[Header("参照")]
[SerializeField] private Animator animator;
[SerializeField] private StatusView statusView;
private static readonly int SadHash = Animator.StringToHash("Sad");
public PetStatus Status => status;
private void Update()
{
float seconds = Time.deltaTime * timeScale;
status.hunger = Mathf.Max(0f, status.hunger - PerSecond(hoursToEmptyHunger) * seconds);
status.mood = Mathf.Max(0f, status.mood - PerSecond(hoursToEmptyMood) * seconds);
bool isSad = status.hunger < sadLine || status.mood < sadLine;
animator.SetBool(SadHash, isSad);
statusView.Show(status);
}
// 「何時間で空になるか」から、1秒あたりに減る量を計算する
private static float PerSecond(float hoursToEmpty)
{
return PetStatus.Max / (hoursToEmpty * 60f * 60f);
}
}
- Time.deltaTime
- 前のフレームから何秒たったか。これを掛けると、パソコンの速さ(フレームレート)に関係なく、1秒あたり同じだけ減る
- 詳しくは6-8 オブジェクトを動かそうで紹介しています
- Mathf.Max(0f, …)
- 0より小さくならないようにする。放っておいてもマイナスにはならない
- animator.SetBool
- #2で作ったAnimatorのSadを、スクリプトから切り替える
Animator.StringToHash("Sad")で名前を数字にしておくと、毎フレーム呼んでも軽い
- isSad
- おなかときげんの、どちらかが30より少なければしょんぼり
||は「または」。両方とも30以上なら、Idleに戻る
- public PetStatus Status => status;
- ほかのスクリプトから状態を読めるようにしておく(#4のボタンで使います)
ゲージに反映しよう(StatusView)
最後に、数字をゲージとコインの表示に反映するスクリプトです。
- PetRaising/Scriptsに「StatusView」を作る
using TMPro;
using UnityEngine;
using UnityEngine.UI;
// ペットの状態を、ゲージ(Image の Fill Amount)とコインの表示に反映する
public class StatusView : MonoBehaviour
{
[SerializeField] private Image hungerFill;
[SerializeField] private Image moodFill;
[SerializeField] private TMP_Text coinText;
public void Show(PetStatus status)
{
hungerFill.fillAmount = status.hunger / PetStatus.Max;
moodFill.fillAmount = status.mood / PetStatus.Max;
coinText.text = status.coins.ToString();
}
}
- fillAmount
- #1でゲージの中身をImage Type:Filledにしたので、0〜1で塗る長さが変わる
- 0〜100の数字を100で割って、0〜1にしている
- 表示だけを担当するスクリプトに分ける
- 数字を計算するPetControllerと、表示するStatusViewを分けておくと、見た目を作り直すときにPetControllerを触らなくて済む
スライムスクリプトを3つに分けるのは、最初はちょっと面倒に感じるかも・・・



「データ」「動き」「見た目」で分けておくと、あとで保存やショップを足すときにすごくラクになるよ!
スクリプトを付けよう


StatusBarにStatusViewを付ける
- HierarchyでStatusBarを選び、Add Component>StatusView
- 次のようにドラッグ&ドロップする
- Hunger Fill:HungerGaugeの子のFill
- Mood Fill:MoodGaugeの子のFill
- Coin Text:Coinの子のCoinText


PetにPetControllerを付ける
- HierarchyでPetを選び、Add Component>PetController
- 次のようにドラッグ&ドロップする
- Animator:Pet(自分自身。Petに付いているAnimator)
- Status View:StatusBar
- Petにはコンポーネントがたくさん付いているので、ほかのコンポーネントの▼を押して折りたたんでおくと見やすい


Inspectorに、Statusの中身(Hunger・Mood・Coins)がスライダー付きで表示されていればOK!これが[Serializable]の効果です。
動かして確認しよう
再生(▶)すると、ゲージが減っていく・・・はずなのですが、6時間で空になる速さなので、見ていてもほとんど変わりません。そこで確認用のTime Scaleの出番です。
- 再生中に、PetControllerのTime Scaleを3000にする
- 時間が3000倍の速さで進む。1秒で50分ぐらい進む計算です
- ゲージが目に見えて減っていき、おなかが30を切ったところでペットがしょんぼりすることを確認
- StatusのHungerを100に戻すと、ペットが元の顔に戻ることを確認


確認が終わったら、Time Scaleは1に戻しておきましょう。再生中に変えた値は、再生を止めると元に戻ります。



Time.timeScaleを使えば、ゲーム全体を早送り出来ます。でもそれだとペットのアニメーションまで速くなっちゃうので、今回は数字の減り方だけを早送りする変数を自分で作りました
ゲームのバランスを考えよう
「何時間で空になるか」はゲームの遊びやすさを大きく左右します。自分の場合は、次のような順番で決めています。
- プレイヤーが1日に何回ぐらい開くかを決める
- 朝・昼・夜の3回ぐらい見に来てほしい → 間はだいたい4〜6時間
- その間に、空になりすぎない速さにする
- 6時間で100から0になる速さなら、5時間あけても17残っている
- ぎりぎりまで減っていて「待ってたよ!」という感じになる
- きげんは、おなかより少しゆっくりにする
- 両方が同じ速さで減ると、いつも同時にしょんぼりしてしまう
- 減る速さをずらすと、「今日はおなかだけ」「今日はきげんも」と変化が出る
1秒あたりに減る量は、PetControllerのPerSecondで計算しています。
| 空になるまで | 1秒あたり | 1時間あたり |
|---|---|---|
| 6時間 | 約0.0046 | 約16.7 |
| 8時間 | 約0.0035 | 12.5 |
「1秒で0.0046減る」と書くとピンときませんが、「6時間で空になる」なら想像しやすいですよね。数字はInspectorから変えられるので、遊びながら調整してみてください。
今はゲームを閉じると時間が止まってしまいますが、#5で「閉じている間も時間が進む」ようにします。そのときも、この「1秒あたりに減る量」がそのまま使えます。
あとがき
今回はペットの状態を数字で持たせて、時間で減るゲージとしょんぼりの切り替えまで作りました。次回は「ごはん」「あそぶ」のボタンでお世話をして、ゲージを回復させたりコインをもらえたりするようにしたいと思います!
コメント
コメント一覧 (1件)
[…] 前回:#3 おなかときげんのゲージを作ろう […]