i-school - クラスとコンポーネント

クラスとコンポーネントの関連性

クラス


 Unity で作成されたスクリプトは、そのファイル名とともに「クラス」と呼ばれます。
例えば、Test.csというスクリプト・ファイルであれば、それは「Testクラス」と呼ばれます。
(正確には、monobehaviourを継承しているクラスは、GameObjectにアタッチすることによってクラスとしてインスタンス化されます。)

 これは、スクリプト内で確認することが出来ます。

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

// class と定義されている
public class Sample : MonoBehaviour {

}

 この class の部分を書き換えることで、クラス以外のスクリプトを作成することができます。
ただし、Unity で新しく作成したスクリプトは最初から class と宣言・定義されますので、
この宣言部分を変更しない限り、特に最初の内は、スクリプトを作成する = クラスを作成すると考えて問題ありません。


ゲームオブジェクトのコンポーネント


 Create Empty コマンドを実行して新しく作成したゲームオブジェクトには、必ず Transfrom コンポーネントがアタッチされています。
それ以外のコマンドを実行して作成したゲームオブジェクトには、Transfrom コンポーネントに加えて、そのゲームオブジェクトの役割に応じた複数のコンポーネントがアタッチされています。

 これらのコンポーネントはゲーム開始前において設定した状態でゲームが開始されますが、ゲームの進行状況に応じて、コンポーネントの内容を変更する必要が出てきます。

 アクションゲームに例えると、プレイヤーであれば移動やジャンプに際しての位置情報の更新(Transformコンポーネント)、攻撃用のボタンの判定、などです。
その際、ゲームオブジェクトの各コンポーネントが利用されるわけですが、これらに対して命令を出す役割を持つのがスクリプトで該当の処理を書き込んだ「クラス」になります。

 つまりコンポーネントとは、ゲームオブジェクトに対して、ゲーム内における役割を与えるためのものであり、
それをゲーム中で動的に制御し、数値などをリアルタイムで変更するためのブリッジ(橋渡し)を行うのが、スクリプトの役割になります。


クラスとコンポーネントとの関わり


 スクリプトである「クラス」に処理したい内容(命令)を書くことで、その内容に沿ってゲーム中のコンポーネントを変更することができます。
先程の例でいうと、プレイヤーの位置情報を更新する処理を書き込めば、プレイヤーの移動が実装できます。
ただし、「クラス」をゲームオブジェクトにアタッチしただけでは、それらのコンポーネントを変更するための権利がありません。

 そのため、必ずアクセスしたい型やクラスとその変数を「クラス」内で宣言し、アクセスしたいコンポーネントをその変数に代入(取得)する必要があります
これにより、始めてクラスからコンポーネントへのアクセスが可能になります。


変更できる対象


 コンポーネントに対して「クラス」からアクセスできるのは「インスペクタ―で見えている情報(=publicの情報)」のみになります。

 クラスも同様で、publicで宣言した変数やメソッドは、他のクラスからもアクセスできる「見える」状態となるため、「ゲーム中に外部から変更可能な情報」になります。
よく見てみると「クラス」自体もpublicで作成されていますので、これにより他のクラスで宣言をして利用することが可能になっています。


サンプル用のSampleクラス


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

// publicでクラスは作成される = 外部からのアクセスを可能な状態にしている。
public class Sample : MonoBehaviour{

    // クラス内の宣言フィールド(メソッドが始まる前の場所であればいい)で、型と変数をセットで宣言をする。ここで宣言した変数はメンバ変数と呼ばれる。
    // まずは、このクラス内で使用する変数を宣言する。宣言と同時に初期化(イコール演算子を使っての代入)をしなければ、自動的に型に合わせた値が初期値として入る。
    // 外部からアクセスしたい変数は修飾子をpublicで宣言をする。そうでない場合(クラス内でのみ使用し、外部からはアクセスさせない)はprivateで宣言する。
    private int x;           // このクラスでのみ使用可能。初期化と値の代入がないので、変数xの中身は初期値の0。
    public float y = 5.5f;   // このクラスで利用できる上に、外部からのアクセスも可能。初期化し代入しているので、変数yの中身は5.5。
    public bool flag;        // このクラスで利用できる上に、外部からのアクセスも可能。初期化と値の代入がないので、変数xの中身は初期値のfalse。

    // 各コンポーネントやクラスの情報を利用する場合には、変数を用意して宣言する。
    // ここにはコンポーネントやクラスを代入し、このクラス内で利用できる状態を作る。
    // この時点では変数の中身は空(null)。
    private ActionTest actionTest;    // クラスの場合、型の部分にクラス名を書く。そのあとに変数を宣言する。
    private Transform transform;   // コンポーネントの場合、型の部分にコンポーネント名を書く。そのあとに変数を宣言する。
}


値の代入


 値とは、int型であれば整数であり、string型であれば文字列となる、変数の内容の総称です。
[同じ型の変数の値 = 同じ型の値] と書くことで、右辺の新たな値を左辺の変数の値として代入できます。これは省略化された書式であり、丁寧に書くと以下のようになります。

   private int x;    // [修飾子 型 変数] の順番で書き、宣言する。privateに関しては省略でき、その場合は[型 変数]の順番になる。

   x = new int();    // 初期化 new + 型名()で書く。
   x = 5;            // 値を代入する。

 本来はこのような手順で書くのですが、C#では[変数 = 値]の書式で初期化と同時に変数に値を代入することが可能になっているため、そちらを使用しています。


宣言フィールド以外で宣言された変数について


 変数には利用範囲があり、それは[スコープ]と呼ばれます。

 宣言フィールドにて宣言した変数は、そのクラス内であれば、いずれの場所であっても変数名を書くだけで利用が可能な状態になっています。
それとは別に、各メソッド内にて宣言をする変数もあります。これは、そのメソッドの中でしか利用する目的がないため、利用場所を絞って利用する場合に使われます。
注意点があり、宣言フィールド以外で宣言した変数には修飾子は設定できず、必ず初期化するか、あるいは値を代入しなければなりません。

public class Sample : MonoBehaviour{

    string call;    // privateを省略した宣言フィールドで変数の宣言。初期化の強制はない。値を代入すればその値が適用され、代入しなければ初期値が入る。

    void Start()
    {
        string name = "佐藤さん";   // 型と変数の宣言し、値を代入。メソッド{ ]内で宣言しているため、この変数のスコープはこのメソッド{ }内のみになる。
        call = "こんにちは";        // callには値が代入されていないため、ここで値を代入する。
        Debug.Log(call);            // callの値を確認する。
    }

    // Update is called once per frame
    void Update()
    {
        if (call == "こんにちは") {          // 条件に当てはまる場合には、{ }内の処理を行う。
            string reply = "こんばんは";     // 型と変数の宣言し、値を代入。if文{ }の中で宣言しているので、この変数のスコープはif文の{ }中のみになる。
            call = reply;                    // callにreplyの値を代入する。
            Debug.Log(call);                 // callの値が変更されているか確認する。
        }
    }
}

 試しに、メソッド内で宣言したnameを別のメソッドで書いてみましょう。また、if文内で宣言したreplyをUpdateで書いてみましょう。
いずれもスコープの範囲が確認できます。