0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

こんにちは,Kaito です!
この記事ではUnityで定義されているenumを例に,C#のenum(列挙型)について基礎から解説していきます.

これは私が所属している徳島大学ゲームクリエイトプロジェクトの勉強会で使用するものです.
興味がありましたら,UnityroomX公式アカウントなども見に来てください!

この記事の目標

この記事の目標はUnityのenumを通じて以下を理解することです.

  • enum(列挙型)の基本構文と定義方法を理解する
  • Unity内で使われているenumの実例を知る
  • 角度から状態(State)を判定し,switch文と組み合わせる実践的な使い方を身につける

1. enum(列挙型)とは?基本構文と作り方

enum(イーナム) とは,関連する複数の定数(変わらない値)をひとまとめにして,名前を付けたものです.「列挙型」とも呼ばれます.

数字の「0」や「1」だけで状態を管理すると,「1ってなんの状態だっけ…?」と後から分からなくなってしまいますが,enumを使えば人間の言葉で状態を管理できるようになります.

enumの定義方法

enumは以下のように enum キーワードを使って定義します.クラスの外や上に書くことが多いです.
enumキーワードの後にenumの名前を付けて,波括弧 {} の中に列挙したい定数をカンマ , で区切って書きます.

// プレイヤーの状態を定義するenumの例
public enum PlayerState
{
    Idle,   // 待機
    Walk,   // 歩き
    Jump,   // ジャンプ
    /* その他の状態も追加可能 */
    Attack  // 攻撃
}

このように定義しておくと,スクリプト内で PlayerState.Walk のように直感的に扱うことができます.

実際に自分でenumを作って確認してみよう!

見るだけでなく,実際に自分で好きなenumを定義して,正しく作れているか確認してみましょう.今回は確認のために,一時的にコンソールに文字を出力する Debug.Log を使います.

using UnityEngine;

// 1. 自分の好きなenumを定義してみる(例:好きなフルーツ)
public enum FavoriteFruit
{
    Apple,
    Banana,
    Orange
}

public class enumTest : MonoBehaviour
{
    // 2. 作ったenumを変数として宣言し,初期値を入れる
    public FavoriteFruit myFruit = FavoriteFruit.Banana;

    void Start()
    {
        // 3. 正しく定義できているか,ToString()で文字列に変換して確認する
        // ToString()は値を文字列(テキスト)に変換するメソッド
        Debug.Log("私の選択したフルーツは: " + myFruit + " です");
        
        // ※ ToString() 等の文字列変換を省いて Debug.Log(myFruit); と書いてもUnityが自動で文字にしてくれます!
    }
}

このスクリプトを適当なゲームオブジェクトにアタッチして実行し,Consoleタブに 私の選択したフルーツは: Banana です と表示されれば大成功です!自分で新しいenumを定義して定義したenumでも正しく動くことを確認してみてくださいね.

💡 【発展】enumの正体は「整数」?(※初心者は後回しでもOKだけど知っていてほしい!)

実は,enumの実体は単なる**整数(int型)**です.
先ほど定義した PlayerState は,裏側では自動的に一番上から 0, 1, 2, 3... と連番が振られています.

  • PlayerState.Idle = 0
  • PlayerState.Walk = 1
  • PlayerState.Jump = 2
  • PlayerState.Attack = 3

この仕組みを知っていると,C#の機能を使って以下のような便利な操作が可能になります.セーブデータを作るときなどに必須の知識なので,頭の片隅に置いておきましょう!

整数とenumの変換(キャスト)
// enumから整数へ変換((int) をつける)
int statenum = (int)PlayerState.Walk; // 結果は 1

// 整数からenumへ変換(セーブデータの読み込み時などに便利!)
PlayerState loadedState = (PlayerState)2; // 結果は PlayerState.Jump

// 文字列へ変換して表示することも可能
string stateName = PlayerState.Attack.ToString(); // 結果は "Attack"
その数値がenumに存在するか確認する(IsDefined)
// 3 は Attack として定義されているので true
bool isExist1 = Enum.IsDefined(typeof(PlayerState), 3); 

// 99 は定義されていないので false
bool isExist2 = Enum.IsDefined(typeof(PlayerState), 99); 
enumの要素数を確認する
// PlayerStateの要素数(この場合は4つ)を取得する
int stateCount = Enum.GetValues(typeof(PlayerState)).Length; // 結果は 4

2. Unityで使われているenumの例

少し難しい話をしていたので,ここで一旦リラックスして,Unityの中で実際に使われているenumの例を見てみましょう.小話としてリラックスして読んでくださいね.
実は,皆さんはすでにUnityの中で無意識にenumを使っているかもしれません.代表的なものを2つ紹介します.

KeyCode

キーボードの入力を判定する時によく使う KeyCode もenumです.

if (Input.GetKeyDown(KeyCode.Space))
{
    // スペースキーが押された時の処理
}

もしこれがenumでなかったら,Input.GetKeyDown(32) のように,スペースキーに割り当てられた数字を暗記しなければならず,非常に不便です.

ForceMode

Rigidbodyに力を加える時に使う ForceMode もenumです.

// 瞬間的な力を加える
// Rigidbodyコンポーネントへの参照
rb.AddForce(transform.forward * 10f, ForceMode.Impulse);

ForceMode.Force(継続的な力)や ForceMode.Impulse(瞬間的な力)など,力の加え方を分かりやすい名前で指定できます.


3. 実践:State型のenumを作って4方向を判定する

それでは,実際に独自のenumを作ってゲーム開発に役立ててみましょう.
今回は,キャラクターが向いている「4方向」を管理する DirectionState というenumを定義します.

// 4方向を定義するenum
public enum DirectionState
{
    Right, // 右
    Up,    // 上
    Left,  // 左
    Down   // 下
}

任意の角度から方向を判定する

キャラクターの回転角度(0°〜360°)から,今どの方向を向いているかを計算し,enumで返すメソッドを作ってみましょう.(※ここでは右方向を0°となるオブジェクトの初期の向きが右である前提となります.)

using UnityEngine;

public class DirectionController : MonoBehaviour
{
    void Update()
    {
        // 例:Z軸の回転角度を取得して判定する
        float currentAngle = transform.eulerAngles.z;
        DirectionState myState = ConvertAngleToDirection(currentAngle);
        
        // スペースキーを押した時に,向いている方向に応じたアクションを実行
        if (Input.GetKeyDown(KeyCode.Space))
        {
            PerformAction(myState);
        }
    }

    // 角度からenumの方向を判定するメソッド
    public DirectionState ConvertAngleToDirection(float angle)
    {
        angle %= 360f; // 角度を0〜360の範囲に収める
        if (angle < 0f) angle += 360f;

        // 角度に応じて方向を判定
        if (angle >= 315f || angle < 45f)
        {
            return DirectionState.Right;
        }
        if (angle >= 45f && angle < 135f)
        {
            return DirectionState.Up;
        }
        if (angle >= 135f && angle < 225f)
        {
            return DirectionState.Left;
        }
        if (angle >= 225f && angle < 315f)
        {
            return DirectionState.Down;
        }
        return DirectionState.Right; // 念のためデフォルト
    }

    // enumとswitch文を組み合わせた処理
    public void PerformAction(DirectionState currentState)
    {
        // switch文はenumと相性抜群!
        switch (currentState)
        {
            case DirectionState.Right:
            // この部分に右を向いているときの処理を書くこともできる
                Debug.Log("右");
                break;
            case DirectionState.Up:
                Debug.Log("上");
                break;
            case DirectionState.Left:
                Debug.Log("左");
                break;
            case DirectionState.Down:
                Debug.Log("下");
                break;
        }
    }
}

このように,「数値を判定してenumに変換する」「enumを使ってswitch文で処理を分岐させる」 という流れは,ゲーム開発において非常に強力なパターンです.


4. 【演習】4方向から「8方向」判定に発展させてみよう!

4方向の判定ができたら,次は少しレベルアップして8方向(上下左右+斜め)の判定に挑戦してみましょう!

ヒント

  1. enumを追加する: まずは DirectionState に斜めの方向(UpRight, UpLeft, DownLeft, DownRight など)を追加しましょう.
  2. 角度を分割する: 360度を8つに分けるので,1つの方向が担当する角度は 360 ÷ 8 = 45度 になります.
  3. if文の条件を書き直す: 右方向(0度)を中心に45度の範囲を考えるなら,右方向は 0~45度 の範囲にしてもらってもよいです.この要領で ConvertAngleToDirection メソッド内の条件式を8つ分書いてみてください.

答えは一つではありません. ぜひ,自分の頭で考えて実装し,Debug.Log やswitch文を使って正しく判定できているかテストしてみてくださいね!

解答例1(ifを8個で判定:4方向の方針を拡張)
// 4方向の方針をそのまま拡張し、if文を8個並べた実装例
public enum DirectionState8
{
    Right,
    UpRight,
    Up,
    UpLeft,
    Left,
    DownLeft,
    Down,
    DownRight
}

public class DirectionControllerIfBased : MonoBehaviour
{
    void Update()
    {
        float currentAngle = transform.eulerAngles.z;
        DirectionState8 myState = ConvertAngleToDirectionIf(currentAngle);
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("現在の向き : " + myState);
        }
    }

    // 角度から8方向を判定(各方向を45度ずつ担当、右を0度基準)
    public DirectionState8 ConvertAngleToDirectionIf(float angle)
    {
        angle %= 360f;
        if (angle < 0f) angle += 360f;

        if (angle >= 0f && angle < 45f) return DirectionState8.Right;
        if (angle >= 45f && angle < 90f) return DirectionState8.UpRight;
        if (angle >= 90f && angle < 135f) return DirectionState8.Up;
        if (angle >= 135f && angle < 180f) return DirectionState8.UpLeft;
        if (angle >= 180f && angle < 225f) return DirectionState8.Left;
        if (angle >= 225f && angle < 270f) return DirectionState8.DownLeft;
        if (angle >= 270f && angle < 315f) return DirectionState8.Down;
        if (angle >= 315f && angle < 360f) return DirectionState8.DownRight;
        return DirectionState8.Right; // 念のためデフォルト
    }
}
解答例2(4方向判定の発展:8方向対応)
// 4方向の発想を拡張した8方向対応(マッピングテーブル+インデックス)
public enum DirectionState8
{
    Right,
    UpRight,
    Up,
    UpLeft,
    Left,
    DownLeft,
    Down,
    DownRight
}

public class DirectionControllerRefined : MonoBehaviour
{
    // 角度から8方向を判定(22.5度オフセットで45度幅を取る)
    public DirectionState8 GetDirectionFromAngleRefined(float angle)
    {
        angle %= 360f;
        if (angle < 0f) angle += 360f;

        // 右(0°)を基準に22.5度ずらして45度毎に分割
        int index = (int)((angle + 22.5f) / 45f) % 8; // 0..7

        DirectionState8[] map = {
            DirectionState8.Right,
            DirectionState8.UpRight,
            DirectionState8.Up,
            DirectionState8.UpLeft,
            DirectionState8.Left,
            DirectionState8.DownLeft,
            DirectionState8.Down,
            DirectionState8.DownRight
        };

        return map[index];
    }

    void Update()
    {
        float currentAngle = transform.eulerAngles.z;
        DirectionState8 myState = GetDirectionFromAngleRefined(currentAngle);
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Debug.Log("現在の向き: " + myState);
        }
    }
}

まとめ

今回はenumの基本的な使い方から,Unityでの実例,そして角度を用いた実践的なswitch文との組み合わせ,さらに演習問題まで学びました.

  • enumは数値を分かりやすい「名前」で管理するための機能
  • ToString()Debug.Log を使えば,現在の状態を簡単に文字で確認できる
  • KeyCodeForceMode など,Unityの標準機能でも多用されている
  • if文で複雑な数値をenumに変換し,switch文で処理を分けることで,バグが少なく読みやすいコードになる
  • 実は裏側の正体は「整数(int)」であり,変換などの応用的な操作も可能

謎の数字をコードから無くし,enumを使って誰が見ても分かりやすい綺麗なプログラムを目指しましょう!

0
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?