シェルスクリプトマガジン

香川大学SLPからお届け!(Vol.67掲載)

著者:山内 真仁

以前、ゲームエンジン「Unity」を使ったレースゲームをSLPのチーム活動で
作成しました。その経験を生かして今回は、Unityとプログラミング言語「C#」を使って、簡単なレースゲームを作成する方法を紹介します。Unityの物理エンジンを使用することで、複雑なコードを書かなくてもリアルな挙動のゲームを作成できます。

シェルスクリプトマガジン Vol.67は以下のリンク先でご購入できます。

図12 「CarController.cs」ファイルに記述する内容

using UnityEngine;

public class CarController : MonoBehaviour
{
  public GameObject[] wheelMeshes = new GameObject[4];  // ホイールオブジェクトを格納する配列
  public WheelCollider[] wheelColliders = new WheelCollider[4];  // Wheel Colliderを格納する配列
  public float maxMotorTorque = 300f;     // 車輪に加える最大トルク
  public float brakeTorque = 500f;        // ブレーキのトルク
  public float maxSteerAngle = 25f;       // ステアリングの最大舵角
  float accel, steer;                     // アクセルとステアリングの入力値
  bool brake;                             // ブレーキをかけているかどうか
  // 画面を描画するたびに実行されるメソッド(実行間隔はフレームレートに依存)
  void Update()
  {
    steer = Input.GetAxis("Horizontal");    // ←→で旋回
    accel = Input.GetAxis("Vertical");      // ↑↓でアクセル
    brake = Input.GetKey(KeyCode.Space);    // スペースでブレーキ
    // Wheel Colliderの動きを見た目に反映する
    for (int i = 0; i < 4; i++) {
      wheelColliders[i].GetWorldPose(out Vector3 position, out Quaternion rotation);
      wheelMeshes[i].transform.position = position;
      wheelMeshes[i].transform.rotation = rotation;
    }
  }
  // フレームレートに依存せず、定期的に実行されるメソッド(0.02秒に1回)
  void FixedUpdate()
  {
    // Wheel Colliderに各パラメータを代入
    for(int i = 0; i < 4; i++) {
      if (i < 2) wheelColliders[i].steerAngle = steer * maxSteerAngle;  // ステアリング(前輪)
      wheelColliders[i].motorTorque = accel * maxMotorTorque;           // アクセル
      wheelColliders[i].brakeTorque = brake ? brakeTorque : 0f;         // ブレーキ
    }
  }
}

図14 CarController.csファイルに追加する記述

  GameObject brakeLight, headLight;  // ランプ類のオブジェクトを格納する変数
  // ゲーム開始時に1回のみ実行されるメソッド
  void Start()
  {
    // ランプ類のオブジェクトを探して取得
    brakeLight = GameObject.Find("SkyCarBrakeLightsGlow");
    headLight = GameObject.Find("SkyCarHeadLightsGlow");
  }
  void Update()
  {
    // ランプ類の点灯・消灯
    brakeLight.SetActive(brake);
    if (Input.GetKeyDown(KeyCode.H)) {
      headLight.SetActive(!headLight.activeSelf);
    }

図16 「Timer.cs」ファイルに記述する内容

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class Timer : MonoBehaviour {
  public Text timeText;     // タイム表示用のテキスト
  float startTime;          // 計測開始の時刻
  bool start, check, goal;  // 各地点の通過フラグ
  void Start() {
    // オブジェクトのコンポーネントを取得
    timeText = GameObject.Find("TimeText").GetComponent<Text>();
    timeText.text = "TIME  00.000";  // テキストの初期化
  }
  void Update() {
    // スタートしてからゴールするまでタイムを表示
    if (!goal && start)
      timeText.text = "TIME  " + (Time.time - startTime).ToString("00.000");
    // ゴール後に[R]キーを押すとリスタート
    if (goal && Input.GetKey(KeyCode.R))
      SceneManager.LoadScene(SceneManager.GetActiveScene().name);
  }
  // トリガーオブジェクトに侵入した時に呼び出されるメソッド
  void OnTriggerEnter(Collider other) {
    if (other.gameObject.name == "StartPoint") {
      if (check) {
        goal = true;  // チェックポイント通過済みならゴール
        timeText.color = Color.red;
      } else if (!start && !check) {
        start = true; // チェックポイントを通過していない場合、タイム計測開始
        startTime = Time.time;
      }
    } else if (start && other.gameObject.name == "CheckPoint")
      check = true;   // チェックポイントを通過
  }
}