メソッドとクラス
プログラムが大きくなると、すべての処理を一か所に書くのは難しくなります。メソッドで処理を分け、クラスで関連するデータと処理をまとめると、読みやすく変更しやすい構造になります。
メソッド
メソッドは名前を付けてまとめた処理です。引数で値を受け取り、戻り値で結果を返せます。
using System;
class Program
{
static int Add(int a, int b)
{
return a + b;
}
static void Main()
{
int result = Add(3, 4);
Console.WriteLine(result);
}
}
Addはint型の引数aとbを受け取り、合計をint型で返します。Add(3, 4)の結果は7なので、コンソールには7が表示されます。voidは戻り値がないことを表します。returnは呼び出し元へ値を返し、その時点でメソッドを終了します。
クラスとインスタンス
クラスはデータと処理をまとめる設計図です。クラスから作った実体をインスタンスと呼びます。
class Player
{
public string Name;
public int Hp;
public void TakeDamage(int damage)
{
Hp -= damage;
}
}
class Program
{
static void Main()
{
Player player = new Player();
player.Name = "Aoi";
player.Hp = 100;
player.TakeDamage(20);
Console.WriteLine(player.Hp);
}
}
new Player()でPlayerのインスタンスを作り、playerという変数からNameやHpへアクセスします。TakeDamage(20)を呼び出すとHpから20が引かれるため、出力は80です。
アクセス修飾子とフィールド
publicはクラスの外からアクセスできることを示し、privateはそのクラスの内部にアクセスを制限します。データを不用意に外部から変更させないため、フィールドをprivateにし、必要な操作だけをメソッドとして公開する設計がよく使われます。
using System;
class Player
{
private int hp = 100;
public int GetHp()
{
return hp;
}
public void TakeDamage(int damage)
{
if (damage > 0)
hp = Math.Max(0, hp - damage);
}
}
この例ではhpを外部から直接変更できません。TakeDamageを通してダメージを適用し、HPが0未満にならないようにしています。
UnityのComponent設計
UnityではMonoBehaviourを継承したクラスをComponentとしてGameObjectに追加できます。移動、体力、アイテム検知などを役割ごとに分けると、機能を再利用しやすくなります。一方、MonoBehaviourを継承しない通常のC#クラスも、データや計算処理をまとめるために使えます。
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
[SerializeField] private int hp = 100;
public void TakeDamage(int damage)
{
hp = Mathf.Max(0, hp - damage);
Debug.Log($"HP: {hp}");
}
}
Mathf.Maxは2つの値のうち大きい方を返すUnityのメソッドです。この例ではHPが0未満にならないようにしています。SerializeFieldを付けるとprivateフィールドをInspectorから設定できます。
よくある間違い
- メソッドの戻り値の型とreturnする値の型が一致していない。
- 戻り値が必要なメソッドでreturnを書き忘れる。
- インスタンスを作る前に、インスタンスのメンバーへアクセスする。
- staticメソッドとインスタンスメソッドの呼び出し方を混同する。
- すべての処理を1つの巨大なクラスに詰め込む。
この章の要点
メソッドは処理をまとめる単位、クラスはデータと処理をまとめる設計図、インスタンスはクラスから作った実体です。UnityではこれらをComponentとして組み合わせ、ゲームオブジェクトの役割を構成します。