Unity C# スクリプトの基本的な書き方 (1)

Unity で C# スクリプトを書くチュートリアルです。

対象読者は「Unity を少しいじったことがあって、少しスクリプトも触ったけれどあまり慣れていない」という方です。

はじめに

スクリプトファイルをつくると、最初に以下のようなスクリプトのひな形が用意されます。
これをもとにスクリプトを書いていきます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Move : MonoBehaviour {

    void Start() {

    }

    void Update() {

    }

}

※以下のコード例では、 public class ... のくだりを省略して void Start() や void Update() のみを示します。


イベント関数

イベント関数 は、特別な関数名をつけておくことで 何かが起こったときにUnity側が実行してくれる関数 です。

スクリプトファイルを作成すると Start()Update() というイベント関数が最初から用意されています。
たとえば Start 関数は、そのスクリプトを付けたオブジェクトが出現したときに実行されます。

よく使うイベント関数として、以下のようなものがあります。
ここではざっと眺めて「ふーん、そんなものがあるんだな」という認識でOKです。
  • Start
    オブジェクトが作成された直後に呼び出される(正確には作成後最初の1フレーム目)
    void Start() { ... }
  • Awake
    オブジェクトが作成された直後に呼び出される(Start よりも先に呼び出されます)
    void Awake() { ... }
  • Update
    毎フレームに1回呼び出される
    void Update() { ... }
  • FixedUpdate
    常に一定間隔で呼び出される (物理演算と同期)
    void FixedUpdate() { ... }
  • OnTriggerEnter, OnTriggerStay, OnTriggerExit
    衝突判定が起きたときに呼び出される
    (詳しくは「衝突判定」で紹介します)
    void OnTriggerEnter(Collider other) { ... }
    void OnTriggerStay(Collider other) { ... }
    void OnTriggerExit(Collider other) { ... }

(より詳細な説明は Unity のドキュメント「イベント関数の実行順」が参考になります。)



1. コンソール

Unity には Console (コンソール) ウィンドウ というものがあります。
ここにはスクリプトのエラーメッセージ等が表示されます。

実は、自作のスクリプトからコンソールにメッセージを表示することもできます。
Debug.Log(~) を使います。
void Start() {
    Debug.Log("こんにちは");
}


「こんにちは」と表示される

最初に Debug.Log(~) を紹介した理由は、バグやミスを修正するときに役立つからです。

よくあるミスとして、変数の値が想定外になっていることが非常に多いです。このような場合、Debug.Log() で表示することで悪の根源を浮き彫りにできます。

バグやミスの修正すべき箇所がわからないときは Debug.Log() のことを思い出してください。


2. 移動 と 回転

Unity では Transform というオブジェクトが位置・回転・大きさなどを管理しています。
スクリプトからは this.transform と書けば、自分自身の Transform にアクセスできます。

移動

Transform の Translate 関数 を使って移動させてみます。
1フレームごとにz軸方向へ 0.5 ずつ動いていきます。
void Update() {
    this.transform.Translate(new Vector3(0, 0, 0.5f));
}
ここで出てきた Vector3 は3次元ベクトルのことです。
つまるところ x, y, z の値が組になっただけのものです。

回転

Transform の Rotate 関数 を使うと、オブジェクトを回転できます。
1フレームに5°ずつグルグル回転します。
void Update() {
    this.transform.Rotate(new Vector3(0f, 0f, 5f));
}

transform.position と transform.rotation

transform.position と transform.rotation を使うと、位置や回転を直接参照したり代入したりできます。
たとえば、
Debug.Log(this.transform.position);
とすると、現在の座標をコンソールに出力できます。

また、
this.transform.position = new Vector3(1, 1, 1);
とすればオブジェクトは (1, 1, 1) に移動します。



3. キー入力

GetKey / GetKeyDown / GetKeyUp



GetButton / GetButtonDown / GetButtonUp



GetAxis




4. 衝突判定

下準備

衝突判定するには、ぶつかる側 or ぶつかられる側に Rigidbody をつけておく必要があります。
また、ここでは OnTrigger~系 のイベント関数を使いたいので、衝突判定をする側のコライダの Is Trigger を有効にしておきます。

衝突判定には OnCollision~系 のイベント関数もありますが、挙動が不安定なことが多く、経験上実際にはあまり使わないことが多いです(OnCollision~系ではコライダが接している場所の座標を取得できるなど、使わざるを得ないこともありますが……)。


衝突判定のイベント関数

OnTriggerEnter : コライダに衝突した瞬間に呼び出される
void OnTriggerEnter(Collider other) {
    Debug.Log("OnTriggerEnter: " + other.tag);
}

OnTriggerStay : コライダに衝突しているあいだずっと呼び出される
void OnTriggerStay(Collider other) {
    Debug.Log("OnTriggerStay: " + other.tag);
}
ちなみに、衝突したあとオブジェクトが完全に静止すると、コライダが接触しているにもかかわらず OnTriggerStay が呼び出されなくなります。
この現象は、コライダが静止すると計算量を節約するために物理演算をしなくなる「スリープモード」になることが原因です。
こういった状況で OnTriggerStay を呼び出すようにするには、次のような対処法があります。
  • OnTriggerStay を処理してほしいときになったらスリープを解除する(Rigidbody の Wakeup() を呼び出す)
  • Rigidbody の sleepThreshold を負の値(-1など)に設定する
2つ目の選択肢は常に物理演算をはたらかせ続けることになるため、あまりおすすめはしません。

OnTriggerExit : 衝突したコライダから離れるときに呼び出される
void OnTriggerExit(Collider other) {
    Debug.Log("OnTriggerExit: " + other.tag);
}



5. 時間関連

数秒待ってから実行 : Invoke関数

Invoke("関数名", 秒数) を実行すると、その秒数だけ待ったあと、指定した関数を呼び出してくれます。
下の例では、5秒後に自分自身を削除しています。ゲーム内では「数秒後に銃弾を消す」といった処理に使えます。
void Start() {
    Invoke("Terminate", 5.0f);
}
void Terminate() {
    Destroy(this.gameObject);
}


1フレームの秒数 : Time.deltaTime

Time.deltaTime で現在の1フレームあたりの所要秒数を取得できます。

Update関数内でプレイヤーを移動するときなどによく使います。
たとえばUpdate関数内で 0.1 ずつ移動させるような場合、処理が重くなったりしてフレームレートが変わると1秒あたりの進む量が変わってしまいます。
そこで、1フレームの所要時間 (Time.deltaTime) が長ければ、そのぶん移動量 (Translate関数の中身) も増やすようにします。
void Update() {
    transform.Translate(Vector3.forward * 0.1f * Time.deltaTime);
}



ここまで、Unity でスクリプトを書く際に頻出する命令を、ざっくりと紹介してきました。
しかし Unity は高機能で巨大です。このブログですべて紹介することは無理があります。我々も Unity のクラスすべてを完全に理解しているだなんて、口が裂けても言えません。

ではどうするかというと、やりたいことをどうすれば実装できるか考えるために、情報を仕入れておく必要があります。

スクリプトの情報はどこから仕入れる?


C#スクリプトに用意されているクラス構成・メンバを調べる方法として、次の3つがあります。

ググって先人の知恵を借りる ・ Unityの書籍を読む

検索エンジンを使って 「Unity 」+「やりたい内容」 を検索します。
何を使えばどんなことができるのか把握するときに役立ちます。
たまに、とても秀逸な記事に出会えることがあるかもしれません。

また、書籍から知ることもできます。インターネットにくらべて情報量が少ないこともありますが、わかりやすい説明も多いです。

ただ気をつけてほしいのは「情報は古くなる」という点です。Unityは頻繁にバージョンアップするため、どこかのブログに載っていた方法や、書籍のサンプルが最新版では動かない、なんてこともあります。

エディタで一覧を眺める

Visual Studio や Mono Develop で this. と打ってみてください。
this の中身の一覧が出てきます。そのなかに transform もあるはずです。
さらに続けて this.transform. まで打つと、transform の中身の一覧が出てきます。
そのなかに Translate や Rotate 関数、position や rotation などがあるはずです。
項目を選ぶと、解説まで出てきます(たいがい英語ですが)。
ここで紹介している方法のなかでも非常に手っ取り早いです。

この方法で「おっ、この関数は使えそう」というものが見つかれば、ググるときの検索キーワードにもできます。

スクリプトリファレンスを見る

Unity Technologies は、親切なことに Unity のほぼすべてのクラスの資料を公開しています。
それが「スクリプトリファレンス」です。


わからないクラスや関数に出会ったとき、これが役立ちます。
スクリプトリファレンスは、とにかく詳しく載っています。

たとえば、Googleで 「Unity Transform」と検索すると、Transformのリファレンスがひっかかります。
Transformクラスのページには、どんな変数や関数があるか、さらにその説明が記載されています。
変数や関数のページを見ると、サンプルコードが載っていることもあります。



ここまで Unity でよく利用するクラスを紹介してきました。
次回は、オブジェクトの設計図であるクラスの仕組みと作り方を見ていきます。

コメント