2023プログラミング:Unityのプログラミング3

再スタート機能の追加

再スタート機能を追加します。ProjectウィンドウのAssetsフォルダの中、Scenesフォルダ内のSampleSceneをリネームし、GameSceneと名称変更します。(右クリックしてRenameを選択し、名称変更)

Scene全体を管理するスクリプトを作成するため、空のゲームオブジェクトを作成します。
Heerarchyウィンドウの+ボタンを押し、Create Emptyを選択します。GameObjectという名称のゲームオブジェクトが作成されるので、GameSceneControllerという名称に変更します。

ProjectウィンドウのAssetsフォルダの中、ScriptsフォルダにGameSceneControllerという名称のスクリプトを作成し、ゲームオブジェクトGameSceneControllerにアタッチします。

スクリプトGameSceneControllerを開き、スクリプトを記述します。

GameSceneController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameSceneController : MonoBehaviour
{
  public static int score = 0;
  private Text scoreText;

  void Start()
  {
     GameObject gameScoreText = GameObject.Find("ScoreText");
     scoreText = gameScoreText.GetComponent<Text>();
     score = 0;
  }

  public void OnFailed()
  {
     Invoke("OnLoadGameScene", 1.5f);
  }

  private void OnLoadGameScene()
  {
     SceneManager.LoadScene("GameScene");
  }

  public void AddScore(int num)
  {
     score += num;
     scoreText.text = score.ToString();
  }

}

落下判定の処理をControllerスクリプトに追記します。

Controller.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Controller : MonoBehaviour
{
     private float speed = 3f;
     private float verticalInput = 0f;
     private Rigidbody CharacterRigidbody;
     private bool isStop;//追記

     void Start()
     {
          CharacterRigidbody = GetComponent<Rigidbody>();
          isStop = false;//追記
     }

     void Update()
     {
     //追記=====>
          if (isStop)
          {
              return;
          }

          if (transform.position.y < 0.5)
          {
               isStop = true;
               GameObject gameSceneController = GameObject.Find("GameSceneController");
               GameSceneController script = gameSceneController.GetComponent<GameSceneController>();
               script.OnFailed();
           }//=====>追記
           else//追記
          {//追記
               verticalInput = Input.GetAxis("Vertical");
               if (Input.GetKey("right"))
               {
                    CharacterRigidbody.transform.Rotate(0, 10, 0);
               }
               else if (Input.GetKey("left"))
              {
                   CharacterRigidbody.transform.Rotate(0, -10, 0);
              }
          }//追記
       }

       void FixedUpdate()
       {
            //追記=====>
            if (isStop)
            {
                 return;
            }
            //=====>追記
            if (CharacterRigidbody.velocity.sqrMagnitude < 5f)
            {
                 Vector3 CharacterForward = CharacterRigidbody.transform.forward;
                 Vector3 moveVector = speed * (CharacterForward * verticalInput);
                 moveVector.y = 0;
                 CharacterRigidbody.AddForce(moveVector, ForceMode.Impulse);
            }
       }

}

キャラクターがステージから落下するとリスタートする機能が追加されました。動作確認してみましょう。

アイテムの作成
報酬となるアイテムを作成します。ゲームオブジェクトを作成し、名称をItemとし、マテリアルを設定しておきます。

Itemゲームオブジェクトをステージに配置し、inspectorウィンドウのColliderコンポーネントのIs Triggerにチェックマークを付けます。
Colliderコンポーネントはアタッチするゲームオブジェクトの形状によって特性が変化します(BoxColliderやSphere Colliderなど)。

ColliderコンポーネントのIs Triggerにチェックを入れることで、オブジェクトは重力などの物理法則を影響を受けなくなり、衝突判定が取得できるようになります。
Is Triggerが有効なゲームオブジェクトが他のゲームオブジェクトに接触すると、OnTriggerEnterメソッドが呼び出されます。

Itemスクリプトの作成
ScriptsフォルダにItemという名称のスクリプトを作成し、ゲームオブジェクトItemにアタッチします。Itemスクリプトに以下の内容を記述します。

Item.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Item : MonoBehaviour
{
     void OnTriggerEnter(Collider other)
     {
          Destroy(gameObject);//画面からゲームオブジェクトを消す
     }
}

スクリプトがアタッチされたゲームオブジェクトItemをプレファブ機能を使ってインスタンスとして複製します。
ProjectウィンドウのAssetsフォルダに新しくPrefabsという名称のフォルダを作成します。
PrefabsフォルダにHierarchyウィンドウのItemゲームオブジェクトをドラッグアンドドロップで移動します。
Prefabsフォルダに移動したItemゲームオブジェクトをHierarchyウィンドウにドラッグアンドドロップして戻すと、Itemインスタンスが作成されます。同じようにして、Prefabsフォルダ内のItemゲームオブジェクトをHierarchyウィンドウに必要な数だけドラッグアンドドロップしてItemインスタンスを複数生成します。

アイテムにキャラクターが衝突すると画面から消えるようになりました。動作確認してみましょう。

画面にスコアを表示する
UI(ユーザーインターフェース)のCanvasを作成します。Hierarchyウィンドウの+ボタンを押して、UIからCanvasを選択します。
CanvasのInspectorウィンドウのScale FactorからScale With Screen Sizeを選択し、X 500,Y400に設定します。
次に文字を表示するために、Hierarchyウィンドウの+ボタンを押して、UIからTextを選択します。TextのInspectorウィンドウのRect TransformコンポーネントにPos X 180, Pos Y 110, PosZ 0と入力します。TextエリアにSCOREと入力するとゲーム画面に表示されます。Font Sizeは20〜24ポイントにしておきます。

続けて、HierarchyウィンドウのCanvasの子であるUI要素のTextを複製(Duplicate)します。複製されたText(1)の名称をScoreTextに変更します。
ScoreTextのInspectorウィンドウのRect TransformコンポーネントにPos X 280, Pos Y 110, PosZ 0と入力し、Textエリアに数字の0を入力しておきます。

アイテムを取得するとスコアが加算される処理をItemスクリプトに追記します。

Item.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Item : MonoBehaviour
{
     void OnTriggerEnter(Collider other)
     {
          GameObject gameSceneController = GameObject.Find("GameSceneController"); //追記
          GameSceneController script = gameSceneController.GetComponent<GameSceneController>();//追記 
          script.AddScore(100); //追記

          Destroy(gameObject);
     }
}

アイテムを取得するとスコアが100点加算されるようになりました。動作確認してみましょう。

参考資料
Unityの2021年以降のバージョンでは、テキストを扱うにはTextMeshProが使用されます。TextMeshProを使ったコードを以下に記載します。

GameSceneController.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using TMPro;//追記

public class GameSceneController : MonoBehaviour
{
  public static int score = 0;
  private TextMeshProUGUI scoreText;//変更

  void Start()
  {
     GameObject gameScoreText = GameObject.Find("ScoreText");
     scoreText = gameScoreText.GetComponent<TextMeshProUGUI>();//変更
     score = 0;
  }

  public void OnFailed()
  {
     Invoke("OnLoadGameScene", 1.5f);
  }

  private void OnLoadGameScene()
  {
     SceneManager.LoadScene("GameScene");
  }

  public void AddScore(int num)
  {
     score += num;
     scoreText.text = score.ToString();
  }

}

Item.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;//追記

public class Item : MonoBehaviour
{
     void OnTriggerEnter(Collider other)
     {
          GameObject gameSceneController = GameObject.Find("GameSceneController"); 
          GameSceneController script = gameSceneController.GetComponent<GameSceneController>(); 
          script.AddScore(100); 

          Destroy(gameObject);
     }
}