UnityUnityメモ

Unityでタイムアタックゲームを作ろう!ベストタイムを記録・表示する方法

Unity

1. はじめに

この記事では、Unityを使ってタイムアタックゲームを作る方法をステップバイステップで解説します。基本的な操作から始めて、以下のような機能を実装していきます。


  • プレイヤーキャラクターの操作:キューブを十字キーで動かすシンプルなコントロール。
  • ゴール判定:特定のオブジェクトに触れたらクリアと判定。
  • タイム計測:プレイ中のタイムをリアルタイムで表示。
  • ベストタイムの保存と表示:最速記録をプレイヤーPrefsを使って保存。

さらに、リセットボタンを追加して、保存されたベストタイムを簡単にリセットする方法も紹介します。

Unity初心者の方でもわかりやすいように、具体的な手順やコードを丁寧に解説しています。Unityの基本操作だけでなく、スクリプトを活用したゲームロジックの組み方も学ぶことができます。

Unityを触ったことがないという方はコチラの記事から見てみてください!



2. ゲームの基本設定

タイムアタックゲームを作るための準備として、まずは基本となるゲームオブジェクトをUnityシーンに配置して設定していきます。このステップでは、プレイヤーとして操作する「キューブ」と、ゴール地点として使用する「Sphere」を配置します。


2.1 キューブをプレイヤーとして配置する

  1. キューブをシーンに追加する
    • ヒエラルキーウィンドウで右クリック。
    • 「3D Object」→「Cube」を選択します。
    • 新しく追加されたキューブを「Player」と名前を変更しておきましょう。
  2. キューブに物理演算を追加する
    • インスペクターウィンドウで「Add Component」をクリック。
    • 検索バーに「Rigidbody」と入力し、追加します。
    • Rigidbodyを追加することで、物理的な動きや衝突がシミュレートされるようになります。
  3. キューブを見やすくする
    • 「Player」オブジェクトを選択した状態で、インスペクターウィンドウの「Transform」を調整します。
      • Position: (0, 1, 0) (地面から少し浮いた位置に設定)
      • Scale: 必要に応じて大きさを調整してください。

2.2 ゴール用のSphereを配置する

  1. Sphereをシーンに追加する
    • ヒエラルキーウィンドウで右クリック。
    • 「3D Object」→「Sphere」を選択します。
    • このSphereはゴール地点になるので、名前を「Goal」と変更します。
  2. ゴールを判定するためのタグを追加する
    • 「Goal」オブジェクトを選択し、インスペクターの「Tag」セクションに移動。
    • ドロップダウンメニューを開き、「Add Tag…」を選択。
    • 新しいタグ「Goal」を追加し、保存します。
    • 再度「Goal」オブジェクトを選択し、タグを「Goal」に設定します。
  3. コライダーの設定
    • 「Goal」オブジェクトのインスペクターで「Sphere Collider」の「Is Trigger」にチェックを入れます。
    • これにより、プレイヤーがSphereに触れた際のイベントをトリガーとして使用できるようになります。
  4. ゴールの位置を調整する
    • 「Goal」オブジェクトの「Transform」を以下のように設定してみましょう。
      • Position: (0, 1, 10) (プレイヤーの初期位置から少し離れた位置)
      • Scale: (1, 1, 1) (デフォルトサイズを使用)

2.3 配置の確認

  • シーンビューで「Player」と「Goal」が適切な位置に配置されているか確認します。
  • 「Player」は地面の中心に、「Goal」は少し離れた場所に配置されている状態にします。

以上で、ゲームの基本設定は完了です。次のステップでは、タイムを表示するUIを作成し、ゲームの進行を視覚化する方法を解説します!



3. UIでタイムを表示する

タイムアタックゲームでは、現在のプレイタイムやベストタイムを画面上に表示することで、プレイヤーが進捗を確認できるようにすることが重要です。このセクションでは、UnityのTextMeshProを使用してタイムを表示する方法を説明します。


1. TextMeshProをインストール

TextMeshProを使用するには、プロジェクトにインポートされている必要があります。以下の手順で確認またはインポートを行います。

  1. Unityの上部メニューから 「Window」「Package Manager」 を選択します。
  2. 「Unity Registry」 を選び、「TextMeshPro」 を検索します。
  3. インストールされていない場合は、「Install」 をクリックしてインポートします。

2. タイム表示用UIの配置

タイムを表示するUIをシーンに追加しましょう。

  1. ヒエラルキーウィンドウを右クリック し、「UI」「Text – TextMeshPro」 を選びます。
  2. 作成されたUIを画面上で見やすい位置に移動します。
    • インスペクターで 「Rect Transform」 を調整して配置を決定。
  3. UIの名前を分かりやすく 「CurrentTimeText」 に変更します。
  4. インスペクター「Text」 フィールドで、デフォルトのテキストを「Time: –」に設定します。

次に、ベストタイム用のUIを追加します。

  1. 同様に、「UI」「Text – TextMeshPro」 を選んで追加。
  2. 作成されたUIを画面上で見やすい位置に配置します。
  3. UIの名前を 「BestTimeText」 に変更します。
  4. 「Text」 フィールドを「Best Time: –」に設定します。

3. リセットボタンの配置

ベストタイムをリセットするためのボタンを追加します。

  1. ヒエラルキーウィンドウを右クリック し、「UI」「Button – TextMeshPro」 を選びます。
  2. 作成されたボタンを画面上の適切な位置に配置します。
  3. 名前を 「ResetButton」 に変更します。
  4. ボタンテキスト を「Reset」に変更します。
    • インスペクター内で 「Text」 フィールドをクリックして編集。

これでUIの配置と設定が完了です!次のステップでは、スクリプトでこれらのUI要素を活用し、タイムを動的に更新する仕組みを作ります。



4. スクリプトを作成

このセクションでは、タイム計測やベストタイムの保存・表示、リセット機能を実装するためのスクリプトについて詳しく解説します。


タイム計測の仕組みを追加

まず、プレイヤーの動きとタイム計測を行うためのスクリプトを作成します。

  1. スクリプトを作成する
    プロジェクトウィンドウで右クリックし、「Create」→「C# Script」を選択します。新しいスクリプトの名前を PlayerController としましょう。
  2. スクリプトを編集する
    作成したスクリプトをダブルクリックして開き、以下のコードを入力します。
using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class PlayerController : MonoBehaviour
{
    public float speed = 5f; // プレイヤーの移動速度
    private float currentTime = 0f; // 現在のタイム
    private bool isTiming = true; // タイマーのオン/オフ
    public TextMeshProUGUI currentTimeText; // 現在のタイム表示用UI
    public TextMeshProUGUI bestTimeText; // ベストタイム表示用UI

    void Start()
    {
        DisplayBestTime(); // ベストタイムを画面に表示
    }

    void Update()
    {
        // タイマーの更新
        if (isTiming)
        {
            currentTime += Time.deltaTime;
            currentTimeText.text = "Time: " + currentTime.ToString("F2") + "s";
        }

        // プレイヤーの移動
        float moveHorizontal = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");
        Vector3 movement = new Vector3(moveHorizontal, 0.0f, moveVertical);
        transform.Translate(movement * speed * Time.deltaTime);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Goal")) // ゴールとの衝突を判定
        {
            isTiming = false;
            SaveBestTime(); // ベストタイムを保存
        }
    }

    // ベストタイムを表示
    private void DisplayBestTime()
    {
        if (PlayerPrefs.HasKey("BestTime"))
        {
            float bestTime = PlayerPrefs.GetFloat("BestTime");
            bestTimeText.text = "Best Time: " + bestTime.ToString("F2") + "s";
        }
        else
        {
            bestTimeText.text = "Best Time: --";
        }
    }

    // ベストタイムを保存
    private void SaveBestTime()
    {
        if (!PlayerPrefs.HasKey("BestTime") || currentTime < PlayerPrefs.GetFloat("BestTime"))
        {
            PlayerPrefs.SetFloat("BestTime", currentTime);
            PlayerPrefs.Save();
            DisplayBestTime();
        }
    }

    // ベストタイムをリセット
    public void ResetBestTime()
    {
        PlayerPrefs.DeleteKey("BestTime");
        PlayerPrefs.Save();
        DisplayBestTime();
    }
}

スクリプトの設定

スクリプトが完成したら、Unityエディターで以下の設定を行います。

  1. スクリプトをアタッチ
    ヒエラルキーウィンドウで「Player」オブジェクトを選択し、作成した PlayerController スクリプトをドラッグ&ドロップしてアタッチします。
  2. UI要素を割り当てる
    スクリプト内で使用する CurrentTimeTextBestTimeText フィールドには、それぞれヒエラルキー上の「CurrentTimeText」と「BestTimeText」のオブジェクトをドラッグ&ドロップして割り当てます。

リセットボタンの機能を追加

リセットボタンでベストタイムをリセットできるように設定します。

  1. ボタンの設定
    ヒエラルキーウィンドウで「ResetButton」を選択し、インスペクターの「On Click ()」セクションを確認します。
  2. スクリプトのリセット機能を追加
    「On Click ()」の「+」ボタンをクリックして新しいイベントを追加します。「Player」オブジェクトを「オブジェクト」欄にドラッグ&ドロップし、ドロップダウンメニューから PlayerControllerResetBestTime() を選択します。

以上でスクリプトの設定は完了です。これで、タイム計測やベストタイム保存、リセット機能が正しく動作するはずです。次のセクションでは、テストプレイの方法とゲームの改善案について解説します。



5. テストプレイ

ここでは、完成したタイムアタックゲームをテストして、より良いゲームにするための改善ポイントについて解説します。

5.1 テストの準備

テストを行う前に、以下の点を確認しましょう:

  1. シーン設定の確認
    • ゲームオブジェクト「Player」と「Goal」が正しく配置されているか確認します。
    • 「Player」にRigidbodyコンポーネントがアタッチされていること、「Goal」にTagが設定されていることを確認してください。
  2. UIの動作確認
    • 現在のタイム(CurrentTime)が正しく表示されているか。
    • ベストタイム(BestTime)が保存され、次回プレイ時にも正しく表示されるか。
  3. スクリプトのアタッチ
    • 「PlayerController」スクリプトが「Player」に正しくアタッチされているか。
    • スクリプト内でUIオブジェクト(CurrentTimeText、BestTimeText)が適切に割り当てられているか。

5.2 動作確認の手順

  1. ゲーム開始
    • 再生ボタンを押してゲームをスタート。
    • 十字キーで「Player」を操作し、「Goal」に触れるまでの時間を計測します。
  2. タイム計測とベストタイム保存の確認
    • ゲーム終了後、「CurrentTime」と「BestTime」が正しく更新されていることを確認してください。
    • プレイごとにかかったタイムが記録され、最も早いタイムが保存されているかチェックします。
  3. リセットボタンの確認
    • リセットボタンをクリックし、ベストタイムがリセットされて「Best Time: –」と表示されるか確認します。

5.3 改善ポイント

テスト中に気づいた問題や改善点があれば、以下のように調整しましょう:

  1. プレイヤーの操作性
    • 「Player」の動きが速すぎる場合は、スクリプト内のspeed変数を調整してください。
    • 例:public float speed = 3f; に変更。
  2. UIのデザイン
    • タイムが画面に見やすく表示されるように、フォントサイズや位置を調整しましょう。
    • TextMeshProオブジェクトのインスペクターで「Font Size」を変更し、テキストが重ならないように配置を最適化してください。
  3. リプレイ性の向上
    • ゴールに到達後、自動的にゲームをリセットする機能を追加すると、何度も繰り返し遊べるようになります。
    • スクリプトのゴール判定部分に以下のコードを追加してみましょう:
IEnumerator ResetGame()
{
    yield return new WaitForSeconds(3f); // 3秒後にリセット
    UnityEngine.SceneManagement.SceneManager.LoadScene(
        UnityEngine.SceneManagement.SceneManager.GetActiveScene().name);
}
  • 難易度調整
    • ゲームが簡単すぎる場合、ゴールまでの距離を伸ばしたり、障害物を追加して難易度を上げてみましょう。
    • 「3D Object」で壁や障害物を配置し、RigidbodyとColliderを活用してプレイヤーがぶつかるようにします。

これで、タイムアタックゲームのテストと改善のステップは完了です。



よくある質問(FAQ)

Q
プレイヤーがゴールに触れてもベストタイムが更新されないのですが?
A

ベストタイムが更新されない原因として以下が考えられます:

  • 「Goal」オブジェクトのタグ設定が間違っている
    スクリプトで「other.gameObject.CompareTag(“Goal”)」と記載されている場合、タグが「Goal」になっているか確認してください。
    タグが設定されていないと正しく動作しません。
  • スクリプトの「PlayerPrefs」部分が機能していない
    「PlayerPrefs.SetFloat」や「PlayerPrefs.Save」を正しく呼び出しているか確認しましょう。また、エラーが出ていないかコンソールで確認してください。
Q
ベストタイムを保存する他の方法はありますか?
A

Unityでは「PlayerPrefs」以外にも以下の方法でデータを保存できます:

  • ファイル保存(JSONやXML形式)
    システムファイルにデータを保存し、読み取る方法です。これにより、より多くのデータや複雑な構造を保存できます。
    using System.IO; string path = Application.persistentDataPath + "/besttime.json"; File.WriteAllText(path, JsonUtility.ToJson(bestTimeData));
  • クラウド保存(オンラインランキング対応)
    Unityのクラウドサービスや外部API(FirebaseやPlayFab)を使って、ベストタイムをオンラインで保存・管理できます。これにより、他のプレイヤーとの競争が可能になります。
Q
タイム計測のUIがうまく表示されない場合の対処法は?
A

タイム計測が表示されない場合、以下を確認してください:

  • TextMeshProのオブジェクトが正しく割り当てられているか
    インスペクターで「CurrentTimeText」と「BestTimeText」のフィールドに、該当するUIオブジェクトを割り当てたか確認してください。
  • タイム計測のスクリプトが更新されているか
    「Update」メソッド内で「currentTimeText.text =」が呼び出されていることを確認しましょう。間違った条件分岐により、更新が止まっている可能性があります。
  • UIが正しく配置されているか
    CanvasのRender ModeやUIの位置がカメラから見える範囲内にあるかを確認してください。必要に応じてCanvas Scalerの設定を調整してください。

おすすめのアセット

「HyperCasual – Puzzle Game Engine」は、シンプルで使いやすいパズルゲームテンプレートです。ブロックの移動やソートなど、ハイパーカジュアルなパズル要素を素早く構築でき、主にモバイル向けのゲーム開発に適しています。シンプルなスクリプトと最適化された設計で、カスタマイズしやすいのが特徴です。UnityのBuilt-inレンダリングパイプラインに対応しています。