Unityでのゲーム開発において、C#は主要なプログラミング言語として採用されています。
C#の特徴のひとつに、オブジェクト指向プログラミング(OOP)があります。OOPは、現実世界の「物事」をプログラム内で再現するための考え方で、コードの再利用や保守性の向上に大いに役立ちます。
本記事では、C#の基礎である「クラス」と、OOPの基本概念である カプセル化、継承、ポリモーフィズム について、初級者向けに丁寧に解説していきます。
さらに、記事の最後には学んだ内容を確認できる演習問題とその解答例も掲載しています。実際に手を動かして試してみることで、理解が深まるでしょう。
C#におけるクラスとオブジェクト
クラスとは?
C#における クラス(class) とは、オブジェクト(実体)を生成するための設計図のようなものです。
例えば、ゲームで「プレイヤー」を表現する場合、「プレイヤー」クラスを作成して、その中に体力や攻撃力などのデータを持たせることができます。
public class Player
{
// フィールド(変数)
public string name;
public int health;
public int attackPower;
// メソッド(関数)
public void Attack()
{
Console.WriteLine(name + "が攻撃した!");
}
}
このように、クラス内にはデータ(フィールド)とそのデータに対する処理(メソッド)を定義します。
オブジェクトとは?
クラスを基に作成された 実体(インスタンス) を オブジェクト と呼びます。以下のコードのように、クラスを使ってプレイヤーオブジェクトを生成できます。
Player player1 = new Player();
player1.name = "勇者";
player1.health = 100;
player1.attackPower = 10;
player1.Attack(); // 出力: 勇者が攻撃した!
このように、同じクラスから複数のオブジェクトを生成し、それぞれに異なる状態(プロパティの値)を持たせることができます。
カプセル化(Encapsulation)
カプセル化とは?
カプセル化とは、データとそのデータに対する操作をひとまとめにし、外部から直接アクセスされないように保護する仕組みです。
これにより、オブジェクト内部のデータが不正に変更されるリスクを減らし、プログラムの信頼性と安全性を高めることができます。
C#でのカプセル化
C#では、アクセス修飾子(public、private、protected など)を用いることで、フィールドやメソッドの公開範囲を制限できます。
例えば、プレイヤーの体力(health)を外部から直接変更されないようにするために、private を使って隠蔽します。そして、体力の取得や変更には専用のメソッドやプロパティを用意します。
カプセル化の実装例
public class Player
{
// 体力は直接アクセスできないようにprivateで宣言
private int health;
// コンストラクタで初期体力を設定
public Player(int initialHealth)
{
health = initialHealth;
}
// 体力を取得するためのメソッド
public int GetHealth()
{
return health;
}
// ダメージを受けた場合の処理
public void TakeDamage(int damage)
{
if (damage < 0) return; // 負の値は無視
health -= damage;
if (health < 0)
{
health = 0; // 体力が負になるのを防ぐ
}
}
// 回復処理のメソッド
public void Heal(int amount)
{
if (amount > 0)
{
health += amount;
}
}
}
このようにすることで、health への不正なアクセスを防ぎ、データの整合性を保つことができます。
継承(Inheritance)
継承とは?
継承とは、既存のクラス(親クラスまたはスーパークラス)の機能を引き継ぎ、新しいクラス(子クラスまたはサブクラス)を作成する仕組みです。これにより、共通の機能を親クラスにまとめ、コードの重複を避けることができます。
たとえば、すべてのキャラクターが持つ共通の機能を親クラスに定義し、戦士や魔法使いなどの個別のキャラクターは親クラスを継承して独自の機能を追加する、といった実装が可能です。
継承の実装例
// 親クラス:Character
public class Character
{
public string name;
public int health;
// 共通の移動メソッド
public void Move()
{
Console.WriteLine(name + "が移動した!");
}
// 仮想メソッド:攻撃。子クラスでオーバーライド可能
public virtual void Attack()
{
Console.WriteLine(name + "が通常攻撃をした!");
}
}
// 子クラス:Warrior(戦士)
public class Warrior : Character
{
public int attackPower;
// オーバーライドして戦士専用の攻撃を実装
public override void Attack()
{
Console.WriteLine(name + "が剣で攻撃! 攻撃力:" + attackPower);
}
}
上記の例では、Character クラスに共通のフィールドやメソッドを定義し、Warrior クラスがこれを継承して独自の攻撃方法を実装しています。
これにより、コードの再利用が促進され、保守性も向上します。
使用例
Warrior warrior = new Warrior();
warrior.name = "戦士";
warrior.health = 120;
warrior.attackPower = 15;
warrior.Move();
warrior.Attack();
ポリモーフィズム(Polymorphism)
ポリモーフィズムとは?
ポリモーフィズムとは、「同じメソッド呼び出しでも、異なるクラスで異なる動作を実現する仕組み」です。
継承と組み合わせることで、親クラス型の変数に子クラスのオブジェクトを代入し、実行時に適切なオーバーライドされたメソッドが呼ばれるようにできます。
これにより、柔軟な設計が可能となり、コードの拡張が容易になります。
ポリモーフィズムの実装例
以下は、Character クラスを基にした複数のキャラクタークラスで、Attack() メソッドの動作をオーバーライドしている例です。
// 基底クラス
public class Character
{
public string name;
public virtual void Attack()
{
Console.WriteLine(name + "が通常攻撃を実行!");
}
}
// 戦士クラス
public class Warrior : Character
{
public override void Attack()
{
Console.WriteLine(name + "が剣で斬りつけた!");
}
}
// 魔法使いクラス
public class Mage : Character
{
public override void Attack()
{
Console.WriteLine(name + "が魔法を放った!");
}
}
使用例
以下のコードでは、親クラス型の変数に異なる子クラスのオブジェクトを代入して、それぞれの Attack() が実行される様子を確認できます。
Character warrior = new Warrior { name = "戦士" };
Character mage = new Mage { name = "魔法使い" };
warrior.Attack(); // 出力: 戦士が剣で攻撃した!
mage.Attack(); // 出力: 魔法使いが魔法を使った!
このように、ポリモーフィズムにより、プログラム全体の柔軟性や拡張性が大幅に向上します。
演習問題
問題1: カプセル化
以下の仕様に従って「BankAccount」クラスを作成してください。
- private int balance という変数を持つ
- Deposit(int amount) メソッドで入金する(0以下の金額は入金不可)
- Withdraw(int amount) メソッドで引き出す(残高不足の場合は引き出し不可)
- GetBalance() メソッドで残高を取得する
解答例
public class BankAccount
{
private int balance;
public BankAccount(int initialBalance)
{
balance = initialBalance;
}
public void Deposit(int amount)
{
if (amount > 0)
{
balance += amount;
}
}
public void Withdraw(int amount)
{
if (amount > 0 && amount <= balance)
{
balance -= amount;
}
}
public int GetBalance()
{
return balance;
}
}
// 使用例
BankAccount account = new BankAccount(1000);
account.Deposit(500);
account.Withdraw(300);
Console.WriteLine(account.GetBalance()); // 出力: 1200
まとめ
- カプセル化 でデータを適切に管理する
- 継承 で共通のコードを再利用する
- ポリモーフィズム で動作を柔軟に変更する
Unityの開発でオブジェクト指向を活用すると、コードの整理や拡張がしやすくなります。ぜひ試してみてください!