ルーグの備忘録

主にC#についてまとめてます。

【C#】classとインスタンス

classとは

後述するインスタンスを作るために定義できる設計図。
変数や関数は全てclassの中に書く。classの中に書かれた変数をメンバー変数、関数をメソッド(メンバー関数)という。

定義方法

1. public(アクセス修飾子)
2. class
3. クラス名
4. {}の中にクラスの実装
の順に書く。

// public class クラス名
public class Person
{
    // 具体的な実装
    // 変数とかメソッドとかを書く

    public string m_Name = Lisa;

    public void ChangeName(string name)
    {
        m_Name = name;
    }
}

publicは省略可能で、省略してもpublic扱いとなる。classは基本的に全てpublicとしてしか使えず、privateなど他のアクセス修飾子を付けるとエラーとなる。(しかし厳密にいうと、内部クラスというものにはpublic以外のアクセス修飾子を付けることができる)
自作したクラスはintやstringと同じようにデータ型として扱うことができる。

// Person型の変数を定義
private Person m_Person;

インスタンスとは

classを設計図として作られた実体のこと。classはただの設計図だから、classのままだと利用することができない(少し例外はある)。なので利用するときはそのclassを元にインスタンスを生成して使う。

インスタンスの生成(newキーワード)

newキーワードを使う。

// インスタンスが生成されて m_Person にインスタンスが入る
private Person m_Person = new Person();

インスタンスの変数やメソッドを参照する

// m_Nameの値を取得 nameに代入
string name = m_Person.m_Name;

// ChangeNameメソッドを呼び出す
m_Person.ChangeName("Bob");

このとき、参照したい変数やメソッドのアクセス修飾子がprivateになっていると参照できないので注意。エラーが出るときはpublicになっているかどうかを確認する。

実践 ~インスタンスの取得~

インスタンスの取得について、よくありそうなCharacterクラスを例にとって解説する。

/// <summary>
/// Characterクラス
/// </summary>
public class Character : MonoBehaviour
{
    /// <summary>
    /// ヒットポイント
    /// </summary>
    private int m_Hp = 100;

    /// <summary>
    /// 攻撃力
    /// </summary>
    private int m_Atk = 10;

    /// <summary>
    /// ダメージを受けるメソッド
    /// </summary>
    /// <param name="atk">相手の攻撃力</param>
    /// <returns>被ダメージ後の残りHp</returns>
    public int OnDamage(int atk)
    {
        // Hpをatkだけ減らす
        m_Hp -= atk;

        // 被ダメージ後のHpの値を返す
        return m_Hp;
    }

    /// <summary>
    /// 攻撃をするメソッド
    /// </summary>
    /// <param name="enemy">敵のCharacterインスタンス</param>
    private void OnAttack(Character enemy)
    {
        int remainingHp = enemy.OnDamage(m_Atk);
    }

    /// <summary>
    /// 衝突時のコールバック
    /// </summary>
    /// <param name="collision">衝突したゲームオブジェクト</param>
    private void OnCollisionEnter(Collision collision)
    {
        Character enemy = collision.gameObject.GetComponent<Character>();
        OnAttack(enemy);
    }
}

OnAttackメソッド内の

int remainingHp = enemy.OnDamage(m_Atk);

にて、相手のCharacter型のインスタンスのOnDamageメソッドを呼ぶことでダメージを与えている。
問題は「どうやって相手のCharacter型のインスタンスを取得するか」だが、それはOnCollisionEnter関数で取得をしている。

解説

イベント関数

イベント関数とは、MonoBehaviourを継承したクラスで実行される特別な関数。簡単にいうと、class名の隣に「: Monobehaviour」が付いてるとなぜか使えてしまう便利なメソッドである。
実装すると、特定のタイミングでその関数を勝手に呼んでくれる優れもの。馴染み深いであろうStart関数やUpdate関数もイベント関数の一種である。

OnCollisionEnter関数

OnCollisionEnter関数は、衝突した瞬間に呼ばれるイベント関数。引数に衝突した相手の情報が詰まったCollision型のインスタンスを勝手に持ってきてくれる。
Collisionっていう型はUnityが用意しているクラス。今回は

collision.gameobject

で衝突した相手のGameObject型のインスタンスを取得している。
GameObjectっていう型もUnityが用意しているクラス。後述するGetComponent関数を実行するために必要。

GetComponent関数

そもそもコンポーネントとは

ゲットコンポーネントの「コンポーネント」とは何か。
コンポーネントとは、インスタンスである。Unityではインスタンスのことをコンポーネントってよく呼ぶ。それだけ。
GameObject型のインスタンス = GameObjectコンポーネント である。

用法
// 取得したいクラスのインスタンス = GameObject型のインスタンス.GetComponent<取得したいクラス名>();
private void OnCollisionEnter(Collision collision)
{
    Character enemy = collision.gameObject.GetComponent<Character>();
    OnAttack(enemy);
}

※ 衝突したGameObjectがCharacterコンポーネントを所持していないとエラーが出るので注意。

つまり、一連の流れを超絶細かく順序立てて説明するとこうなる。

1. 引数から衝突した相手のCollisionコンポーネントをもらう。

2.

collision.gameObject

までで、GameObjectコンポーネントを参照。

3.

collision.gameObject.GetComponent<Character>()

までで、Characterコンポーネントを取得。

4.

Character enemy = collision.gameObject.GetComponent<Character>();

で、ローカル変数enemyに、取得したCharacterコンポーネントを代入。

5. OnAttackメソッドの引数にenemyを渡して呼び出す。

インスタンスコンポーネント)の取得にはGetComponent関数を使う。インスタンスの取得ができるようになると、自由にゲームを作れるようになるのでぜひ理解して欲しい。

インスタンスコンポーネント)についての理解がまだふわふわしている方はこれを読むと何か得るものがあるかも。
hakase0274.hatenablog.com