【ゲーム開発のためのC#入門講座・応用学習編】クラスの扱い方を学ぼう【#3】

2022-01-184.0_C#応用学習編

おさらい

オブジェクト指向では、データと処理をひとつにまとめることができます。

このことにより、

  • 関連性のあるデータと処理をワンセットで提供できるようになった
  • 「モノ(オブジェクト)」として捉えられるようになり、「関数(データ)」ではなく「モノ.動作()」という記述でコードが書けるようになった

という恩恵を得られるようになりました。

これが「直感的でわかりやすく、再利用もしやすいプログラムを作りたい」という時代のニーズと合っていたことで、オブジェクト指向は世に広く普及していったんですね。

改めて、クラスって?

そんなオブジェクト指向の根底を支えている技術が、データと処理をひとまとめにする機能「クラス」です。

クラスというのは関連性のある複数データをまとめた構造体と、そのデータを扱うための関数を合体させたものと考えるとわかりやすいかなと思います。

// 関連性のある複数データをまとめた構造体
public struct BattleCharacter
{
    public string Name = "";
    public int Level = 0;
    public int HP = 0;
    public int ATK = 0;
}
​
// そのデータを扱うための関数
static int Attack(BattleCharacter attacker)
{
    return attacker.ATK + attacker.Level * 2 / 5;
}
​
// 合体させると、クラスになる
public class BattleCharacter
{
    public string Name = "";
    public int Level = 0;
    public int HP = 0;
    public int ATK = 0;
​
    public int Attack()
    {
        return ATK + Level * 2 / 5;
    }
}

クラスの構文は下記の通りです。

public class クラス名
{
    public データ型 データ名 = 初期値;
    
    public 戻り値 メソッド名(引数)
    {
        ……処理内容……
    }
}

おや、関数のところに見慣れない単語がありますね。それに「static」のおまじないもなくなっています。

オブジェクト指向では、クラスで定義した関数のことを「メソッド」と呼びます。単純に呼び方の問題なので、引数や戻り値など、扱い方は関数と変わりません。

「static」についてはいずれ解説する予定なので、今は「クラスにすると、staticのおまじないは省略してもいいらしい」という風に理解してもらえればありがたいです。

なお、データやメソッドはひとつもなくてもOKですし、もっとたくさん追加することも可能です。

皆さんがまとめたいようにまとめることができるので、少しずつ色んなことを試していきましょう。

クラスは設計図

クラスはよく設計図に例えられます

どういうことなのか、前回作ったプログラムで確認してみましょう。

BattleCharacter link = new BattleCharacter();
link.Name = "リンク";
link.Level = 10;
link.HP = 25;
link.ATK = 10;
​
BattleCharacter goblin = new BattleCharacter();
goblin.Name = "ゴブリン";
goblin.Level = 5;
goblin.HP = 10;
goblin.ATK = 7;
​
while (true)
{
    goblin.HP -= link.Attack();
    if (goblin.HP <= 0)
    {
        break;
    }
    link.HP -= goblin.Attack();
    if (link.HP <= 0)
    {
        break;
    }
}
​
if (goblin.HP <= 0)
{
    Console.WriteLine("勝利!");
}
else
{
    Console.WriteLine("ゲームオーバー!");
}
​
public class BattleCharacter
{
    public string Name = "";
    public int Level = 0;
    public int HP = 0;
    public int ATK = 0;
​
    public int Attack()
    {
        return ATK + Level * 2 / 5;
    }
}

このプログラムにおけるクラス「BattleCharacter」を見てみましょう。

「Name」や「Level」といったデータは定義されていますが、「Name」の初期値はブランクですし、「Level」の初期値は0です。「リンク」でも「ゴブリン」でもないですよね。

// ↓この時点では名無しだしレベルは0なので、何者でもない
public class BattleCharacter
{
    public string Name = "";
    public int Level = 0;
    public int HP = 0;
    public int ATK = 0;
​
    public int Attack()
    {
        return ATK + Level * 2 / 5;
    }
}

実際に作成された個々のデータが「リンク」だったり「ゴブリン」だったりします。

// ↓リンクというモノ(オブジェクト)
BattleCharacter link = new BattleCharacter();
link.Name = "リンク";
link.Level = 10;
link.HP = 25;
link.ATK = 10;
​
// ↓ゴブリンというモノ(オブジェクト)
BattleCharacter goblin = new BattleCharacter();
goblin.Name = "ゴブリン";
goblin.Level = 5;
goblin.HP = 10;
goblin.ATK = 7;

つまりクラスはあくまで「こういうデータを持っていて、こういう動作ができるもの」という設計図に過ぎないんですね。

その設計図をもとに作られたデータこそがモノ(オブジェクト)にあたる訳です。

// こういうデータを持っていて、こういう動作ができるもの、という設計図
public class BattleCharacter
{
    public string Name = "";
    public int Level = 0;
    public int HP = 0;
    public int ATK = 0;
​
    public int Attack()
    {
        return ATK + Level * 2 / 5;
    }
}
​
// ↓設計図をもとに生み出されたモノ(オブジェクト)
BattleCharacter link = new BattleCharacter();
link.Name = "リンク";
link.Level = 10;
link.HP = 25;
link.ATK = 10;
​
// ↓設計図をもとに生み出されたモノ(オブジェクト)
BattleCharacter goblin = new BattleCharacter();
goblin.Name = "ゴブリン";
goblin.Level = 5;
goblin.HP = 10;
goblin.ATK = 7;

このような考えから、オブジェクト指向ではクラスから作成したデータのことをインスタンス(実体)と呼びます

設計図に例えられる理由、納得がいったでしょうか?

クラスを設計図として考えると、「new」というキーワードも少しニュアンスが変わってきます。

これまでは「参照型のデータを作成し、その分のヒープメモリを確保しろ」という命令でした。ですが、オブジェクト指向においては「クラスから新しくインスタンスを作成しろ」という命令だとも言えます。

/*
    ①「BattleCharacter」というクラス(設計図)から
    ②新しく(new)
    ③「link」というインスタンス(実体)を作成しろ
    という命令とも言える
*/
BattleCharacter link = new BattleCharacter();

クラス(設計図)からインスタンス(実体)を作成し、インスタンスの動作(メソッド)の積み重ねでプログラムを構築する。

これがオブジェクト指向の基本的な考え方となります。

Unityでの活躍ポイント

オブジェクト指向が登場する前から関数の再利用は行われていました。が、オブジェクト指向の登場によりクラスが追加されたことで、さらに再利用できる範囲が大きく広がりました。

Unityでゲーム開発を行う際も、MicrosoftやUnity Technologiesが作った色んなクラスを再利用することができます。

// AudioSourceというクラスに音楽再生用のデータと処理(メソッド)がまとまっているよ!
AudioSource audioSource = GetComponent<AudioSource>();
// 「Play」メソッドを実行するだけで音楽を再生できるよ!
audioSource.Play();

自力で音楽を再生するためのデータや処理を実装しろなんて言われたら到底できる気がしません。が、誰かが作ってくれた超便利なクラスを再利用することで、こんな風にほんの数行で音楽を再生するコードが書ける訳です。

再利用しやすいということが、プログラミングにおいてどれほど重要か、よくわかりますね。

モノ(オブジェクト)だとかインスタンス(実体)だとか、扱っているものが抽象的なのでどうしても分かりにくさはあります。ただ、なぜオブジェクト指向というものが世に広まったのか、何となくでも実感が湧いていれば幸いです。

もし皆さんが将来的にとても便利なクラスを作ることができたら、その時はぜひそのクラスを再利用できるようにしてあげてください。

それを再利用した人がより便利なクラスを作り、その便利なクラスを再利用した人がさらに便利なクラスを作っていく。

そういうことの繰り返しで、プログラミングは発展を続けています。

実践演習

それでは、改めて実際にクラスを作ってみましょう。

演習①新しいクラスを作ってみよう!

仕様

下記のデータとメソッドを持つクラス「Cleric」を作成してください。
<データ>
string型「Name」。初期値は""(ブランク)
int型「MP」。初期値は0
<メソッド>
・「Heal」
 戻り値:int型
 引数 :なし
 処理 :MPが5以上だったら、MPから5引いた上で、戻り値として20を返す。
     5未満だったら何もせずに0を返す。

テンプレート
Cleric healer = new Cleric();
healer.Name = "ヒーラーちゃん";
healer.MP = 50;

Console.WriteLine(healer.Name + "の残りMP:" + healer.MP);
int healPoint = healer.Heal();
Console.WriteLine(healer.Name + "の残りMP:" + healer.MP);
Console.WriteLine("回復量:" + healPoint);

// ↓ここにクラスを定義しよう!

// ここまで

演習②Microsoftが作ったクラスを再利用しよう!

仕様

Microsoftが作ったクラス「Random」は、
ランダムな数値を生成するためのデータと処理をまとめたクラスです。
メソッド「Next」は「0~引数で指定した数値未満」のランダムな数値を返します。
上記を使って、0~9までのランダムな数値を出力するプログラムを作成してください。

テンプレート
// ↓ここでRandomクラスのインスタンスを作ろう!

// ここまで
for (int i = 0; i < 5; i++)
{
    // ↓Nextメソッドを使って、
    //  ランダムな数値をコンソール画面に出力しよう!
    
    // ここまで
}

答え合わせ

演習①の答え

Cleric healer = new Cleric();
healer.Name = "ヒーラーちゃん";
healer.MP = 50;

Console.WriteLine(healer.Name + "の残りMP:" + healer.MP);
int healPoint = healer.Heal();
Console.WriteLine(healer.Name + "の残りMP:" + healer.MP);
Console.WriteLine("回復量:" + healPoint);

// ↓ここにクラスを定義しよう!
public class Cleric
{
    public string Name = "";
    public int MP = 0;

    public int Heal()
    {
        if (MP >= 5)
        {
            MP -= 5;
            return 20;
        }
        else
        {
            return 0;
        }
    }
}
// ここまで

演習②の答え

// ↓ここでRandomクラスのインスタンスを作ろう!
Random random = new Random();
// ここまで
for (int i = 0; i < 5; i++)
{
    // ↓Nextメソッドを使って、
    //  ランダムな数値をコンソール画面に出力しよう!
    Console.WriteLine(random.Next(10));
    // ここまで
}

まとめ

  • クラスとは、データと動作(メソッド)をひとまとめにした設計図
  • クラスから生み出したデータのことをインスタンス(実体)と呼ぶ
  • クラス(設計図)からインスタンス(実体)を作成し、インスタンスの動作(メソッド)の積み重ねでプログラムを構築する、というのがオブジェクト指向の基本的な考え方
  • クラスを再利用して、効率のよいプログラミングやゲーム開発を目指そう

次回以降は、クラスのさらなる詳細な使い方を学習していきます。お楽しみに!

それでは、今回もお疲れ様でした!

また次の記事でお会いしましょう!

Posted by yuumekou