クラスは「設計図」で、オブジェクトはその設計図から作られた「実体」です。
たとえば Player というクラスを設計図として定義しておくと、
その設計図から player1・player2 という別々の実体(インスタンス)を何個でも生成できます。
それぞれの実体は独立した名前・HP などの値を持ちます。
Player クラス(設計図)
├── player1(HP: 100、名前: "勇者")
└── player2(HP: 80、名前: "魔法使い")
💡 C言語経験者向け:C言語の struct に近い概念ですが、
データ(フィールド)だけでなく、処理(メソッド)も一緒に持てる点が大きく異なります。
// クラスの宣言
class Player
{
// フィールド(メンバー変数)
string name;
int hp;
// コンストラクタ(インスタンス生成時に呼ばれる初期化処理)
public Player(string name, int hp)
{
this.name = name;
this.hp = hp;
}
// メソッド(処理)
public void TakeDamage(int damage)
{
hp -= damage;
if (hp < 0) hp = 0;
}
public void ShowStatus()
{
Console.WriteLine($"{name} の HP:{hp}");
}
}// new を使ってインスタンスを生成する
Player player1 = new Player("勇者", 100);
Player player2 = new Player("魔法使い", 80);
player1.TakeDamage(30);
player1.ShowStatus(); // 勇者 の HP:70
player2.ShowStatus(); // 魔法使い の HP:80(別インスタンスなので影響を受けない)フィールドやメソッドへのアクセス範囲をコントロールします。
| 修飾子 | アクセスできる範囲 |
|---|---|
public |
どこからでもアクセス可能 |
private |
クラス内からのみアクセス可能 |
protected |
クラス内と派生クラスからアクセス可能 |
internal |
同じアセンブリ(プロジェクト)内からアクセス可能 |
class Player
{
public string name; // どこからでも読み書き可能
private int hp; // クラス内からのみアクセス可能
protected int level; // 派生クラスからもアクセス可能
}原則として、フィールドは private にして外部から直接変更できないようにします。
必要な場合だけ public メソッドやプロパティ経由でアクセスさせる設計が基本です。
Unity では public フィールドは Inspector に表示されますが、
public を多用すると外部から意図せず変更されるリスクがあります。
[SerializeField] 属性を使うと、private のまま Inspector に表示できます。
using UnityEngine;
class PlayerController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 5.0f; // Inspector に表示される
[SerializeField] private int maxHp = 100; // Inspector に表示される
private int currentHp; // Inspector には表示されない(内部管理用)
}フィールドを直接公開する代わりに、プロパティ経由でアクセスすることで 「値の検証」や「読み取り専用化」などを実現できます。
💡 C言語経験者向け:getter 関数と setter 関数をひとつの構文にまとめたような仕組みです。
class Player
{
private int hp;
public int Hp
{
get { return hp; } // 値を返す
set
{
if (value < 0) value = 0; // 0 未満にならないよう検証
hp = value;
}
}
}Player player = new Player();
player.Hp = 100; // set が呼ばれる
int h = player.Hp; // get が呼ばれる
player.Hp = -10; // 自動で 0 に補正される検証が不要な場合は短く書けます。
class Player
{
public string Name { get; set; } // 読み書き可能
public int Score { get; set; } = 0; // 初期値付き
}class Player
{
private int hp = 100;
public int Hp { get { return hp; } } // get のみ(外部から変更不可)
// 式形式でも書ける(C# 6 以降)
public bool IsDead => hp <= 0;
}static を付けると、インスタンスを生成しなくても使えるフィールドやメソッドを定義できます。
また、すべてのインスタンスで値が共有されます。
class GameManager
{
public static int TotalScore = 0; // 全インスタンスで共有される
public static void AddScore(int amount)
{
TotalScore += amount;
}
}GameManager.AddScore(100); // インスタンス不要で呼び出せる
Console.WriteLine(GameManager.TotalScore); // 100🎮 Unity での使用例:Unity 組み込みの Mathf クラスのメソッドも static です。
float distance = Mathf.Abs(-5.0f); // 絶対値:5.0
float clamped = Mathf.Clamp(hp, 0, 100); // hp を 0〜100 に収めるstatic フィールドはすべてのインスタンスで共有されます。
片方のインスタンスが値を変えると、もう片方にも影響します。
class Counter
{
public static int count = 0;
}
Counter a = new Counter();
Counter b = new Counter();
Counter.count = 10;
// a も b も同じ count を参照している
// Counter.count は 10(意図しない共有に注意)this は「自分自身のインスタンス」を指します。
フィールド名とパラメータ名が同じ場合に区別するために使います。
class Player
{
private string name;
private int hp;
public Player(string name, int hp)
{
this.name = name; // this.name はフィールド、name はパラメータ
this.hp = hp;
}
}this を省略できる場合は省略で構いませんが、
名前が被る場面では明示的に使うと可読性が上がります。
public void TakeDamage(int damage)
{
hp -= damage;
}public bool IsAlive()
{
return hp > 0;
}引数を省略した場合に使われる初期値を設定できます。
public void TakeDamage(int damage, bool showLog = true)
{
hp -= damage;
if (showLog)
{
Console.WriteLine($"{damage} ダメージを受けた");
}
}player.TakeDamage(20); // showLog = true(デフォルト)
player.TakeDamage(20, false); // ログを出さない同じ名前で引数の異なるメソッドを複数定義できます。
class Player
{
public void Attack()
{
Console.WriteLine("通常攻撃");
}
public void Attack(int damage)
{
Console.WriteLine($"{damage} ダメージの攻撃");
}
public void Attack(string skillName, int damage)
{
Console.WriteLine($"{skillName}:{damage} ダメージ");
}
}player.Attack(); // 通常攻撃
player.Attack(50); // 50 ダメージの攻撃
player.Attack("ファイア", 80); // ファイア:80 ダメージUnity のスクリプトは MonoBehaviour を継承したクラスとして作成します。
MonoBehaviour は Unity が提供する基底クラスで、
これを継承することで GameObject にアタッチして動作させられます。
using UnityEngine;
// MonoBehaviour を継承することで GameObject にアタッチできる
public class PlayerController : MonoBehaviour
{
// Start はシーン開始時に1回呼ばれる
void Start()
{
Debug.Log("ゲームスタート");
}
// Update は毎フレーム呼ばれる
void Update()
{
// 毎フレームの処理を書く
}
}Unity Inspector には以下の条件を満たすフィールドが表示されます:
publicフィールド[SerializeField]属性を付けたprivateフィールド
Inspector から値を変更することで、コードを書き換えずにパラメータ調整ができます。
public class EnemyController : MonoBehaviour
{
[SerializeField] private float moveSpeed = 3.0f; // Inspector で調整可能
[SerializeField] private int hp = 50; // Inspector で調整可能
private bool isDead = false; // Inspector には出ない
}Player player; // 宣言だけで null のまま
player.TakeDamage(10); // NullReferenceException が発生する
// 正しくは new でインスタンスを生成する
Player player = new Player("勇者", 100);class Counter
{
private int count = 0;
public static void Increment()
{
count++; // エラー:static メソッドから非 static フィールドにアクセスできない
}
}static メソッドからは static メンバーにしかアクセスできません。
MonoBehaviour を継承したクラスは new で生成できません。
PlayerController pc = new PlayerController(); // エラーになるUnity のコンポーネントは AddComponent で追加します。
PlayerController pc = gameObject.AddComponent<PlayerController>();// コンストラクタ:Player(string name, int hp)
Player player = new Player(100, "勇者"); // 順番が逆でコンパイルエラーになる
Player player = new Player("勇者", 100); // 正しい順番