Unityゲームにおける状態管理とキャラクター制御スクリプトの概要解説資料(プレイヤー攻撃まで)

プレイヤーが攻撃できる機能を追加まで

1. 基本的な状態管理とキャラクターの基本クラス

1.1 MobStatus クラス

目的:
Mob(移動・攻撃可能なオブジェクト)の共通状態(NormalAttackDie など)を管理する抽象クラス。

主な機能:

  • 移動や攻撃が可能かどうかの判定 (IsMovable, IsAttackable)
  • ライフ管理 (LifeMaxLife)
  • 初期化処理: ライフのセットや Animator の取得
  • ダメージ処理: Life が 0 以下になると死亡状態への遷移を行う

1.2 EnemyStatus クラス

目的:
敵キャラクター固有の状態管理を実装するクラス(MobStatus の派生)。

主な機能:

  • NavMeshAgent を利用した移動制御(EnemyMoveクラスなどから呼び出し)
  • 移動速度を Animator に反映
  • 死亡時の後処理: 一定時間後にオブジェクトを破棄

1.3 PlayerStatus クラス

目的:
プレイヤーキャラクター固有の状態管理を実装するクラス(MobStatus の派生)。

主な機能(現状):

  • MobStatus と同様に、ライフや状態(Normal, Attack, Die)の管理
  • TODO コメントにあるように、将来的にプレイヤー特有の追加状態やパラメータを拡張可能
using UnityEngine;

public class PlayerStatus : MobStatus
{
    // TODO あとでプレイヤー向けにカスタムする
}

2. 攻撃制御と関連オブジェクト

2.1 MobAttack クラス

目的:
Mob の攻撃処理を制御するクラス。

主な機能:

  • 攻撃可能かどうかの判定 (AttackIfPossible)
  • 攻撃範囲内に侵入した対象への処理 (OnAttackRangeEnter)
  • 実際の攻撃時に対象へダメージを与える処理 (OnHitAttack)
  • 攻撃開始(OnAttackStart)および終了後のクールダウン処理

2.2 AttackRangeDetector オブジェクト

役割:
敵がプレイヤーを追跡・攻撃する際に、プレイヤーが「攻撃可能範囲」に入ったかを検知するトリガー用オブジェクト。

主な設定:

  • BoxColliderIs Trigger 設定)で範囲を定義
  • CollisionDetector スクリプトをアタッチし、OnTriggerEnter / OnTriggerStayEnemyMoveOnDetectObject などを呼び出す

2.3 MobAttackHitCollider オブジェクト

役割:
攻撃アニメーションのタイミングで有効化され、実際に「攻撃が当たった」ことを判定するトリガー用コライダー。

主な設定:

  • ColliderIs Trigger 設定)で攻撃判定用の範囲を定義
  • CollisionDetector スクリプトを用いて OnTriggerEnter / OnTriggerStay 時に MobAttack.OnHitAttack を実行し、相手にダメージを与える

3. キャラクターの移動および入力制御

3.1 EnemyMove クラス

目的:
敵キャラクターの移動制御およびプレイヤー追跡ロジックを実装するクラス。

主な機能:

  • NavMeshAgent を用いた経路探索
  • CollisionDetector からの通知(OnDetectObject)により、プレイヤー検知と障害物判定(RaycastNonAlloc など)
  • 障害物がなければ追跡、障害物があれば移動停止

3.2 PlayerController クラス

目的:
プレイヤーキャラクターの入力受付と動作(移動、回転、ジャンプ、攻撃)の管理。

主な機能:

  • Unityの PlayerInput コンポーネントを利用した入力管理(Move, Jump, Attack
  • CharacterController を使った移動処理と AnimatorMoveSpeed 更新
  • 入力方向に基づいた Quaternion.LookAt を用いた回転
  • 地上判定、ジャンプ処理、重力適用による落下処理
  • 攻撃入力があった際に、MobAttack.AttackIfPossible() を呼び出して攻撃状態へ移行

サンプルコード:

using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(PlayerInput))]
[RequireComponent(typeof(PlayerStatus))]
[RequireComponent(typeof(MobAttack))]
public class PlayerController : MonoBehaviour
{
    [SerializeField] private Animator animator;
    [SerializeField] private float moveSpeed = 3; // 移動速度
    [SerializeField] private float jumpPower = 3; // ジャンプ力
    private CharacterController _characterController; // CharacterControllerのキャッシュ
    private Transform _transform;                   // Transformのキャッシュ
    private InputAction _jump;                     // Jumpアクションのキャッシュ
    private InputAction _move;                     // Moveアクションのキャッシュ
    private InputAction _attack;                   // Attackアクションのキャッシュ
    private Vector3 _moveVelocity;                 // キャラの移動速度情報
    private PlayerStatus _status;
    private MobAttack _mobAttack;

    private void Start()
    {
        _characterController = GetComponent<CharacterController>();
        _transform = transform;
        _status = GetComponent<PlayerStatus>();
        _mobAttack = GetComponent<MobAttack>();

        var input = GetComponent<PlayerInput>();
        // PlayerInputの「Default Map」で指定されているアクションマップを有効化
        input.currentActionMap.Enable();

        // アクションマップからアクションを取得
        _move = input.currentActionMap.FindAction("Move");
        _jump = input.currentActionMap.FindAction("Jump");
        _attack = input.currentActionMap.FindAction("Attack");
    }

    private void Update()
    {
        // 地上判定のデバッグ表示
        Debug.Log(_characterController.isGrounded ? "地上にいます" : "空中です");

        // Attackアクション(例: マウス左クリック)で攻撃
        if (_attack.WasPressedThisFrame())
        {
            _mobAttack.AttackIfPossible();
        }

        // プレイヤーが移動可能な状態であれば移動入力を処理
        if (_status.IsMovable)
        {
            var moveValue = _move.ReadValue<Vector2>();
            _moveVelocity.x = moveValue.x * moveSpeed;
            _moveVelocity.z = moveValue.y * moveSpeed;

            // 移動方向にキャラクターを向ける
            _transform.LookAt(_transform.position + new Vector3(_moveVelocity.x, 0, _moveVelocity.z));
        }
        else
        {
            // 移動不可時は速度をゼロに
            _moveVelocity.x = 0;
            _moveVelocity.z = 0;
        }

        // ジャンプや落下処理
        if (_characterController.isGrounded)
        {
            if (_jump.WasPressedThisFrame())
            {
                Debug.Log("ジャンプ!");
                _moveVelocity.y = jumpPower;
            }
        }
        else
        {
            // 重力による加速
            _moveVelocity.y += Physics.gravity.y * Time.deltaTime;
        }

        // 実際にキャラクターを動かす
        _characterController.Move(_moveVelocity * Time.deltaTime);

        // 移動スピードを Animator に反映
        animator.SetFloat("MoveSpeed", new Vector3(_moveVelocity.x, 0, _moveVelocity.z).magnitude);
    }
}

ポイント:

  • RequireComponent 属性により、CharacterController, PlayerInput, PlayerStatus, MobAttack が必須コンポーネントとして設定されている
  • PlayerInput コンポーネントで定義されたアクション(Move, Jump, Attack)をスクリプトで取得して、プレイヤー操作を実装
  • MobAttack を呼び出すことで、共通の攻撃ロジックを再利用

4. 衝突判定の共通処理

4.1 CollisionDetector クラス

目的:
衝突(Trigger)判定を行い、Inspector で設定した UnityEvent(TriggerEvent)を発火させる。

主な機能:

  • OnTriggerEnterOnTriggerStay により、指定イベントを Invoke
  • 内部クラス TriggerEvent[Serializable] 属性を持ち、Inspector 上でメソッドを設定可能にしている

5. シーン上のオブジェクト配置とスクリプト間連携

5.1 シーン上の配置イメージ

  • AttackRangeDetector: 敵キャラクターの子オブジェクトとして配置。プレイヤーを認識できる範囲を示す。
  • MobAttackHitCollider: 攻撃時のみ有効化されるトリガー。武器や手・足の先端などに配置して、攻撃ヒットを判定。

5.2 Inspector 設定例

  • Collider の Is Trigger 設定:
    • AttackRangeDetectorMobAttackHitCollider の各 Collider で有効化
  • CollisionDetector の設定:
    • TriggerEvent に各クラス(EnemyMove, MobAttack など)の呼び出したいメソッドをアサイン

5.3 各クラス・オブジェクト間の連携

  • EnemyMove: AttackRangeDetectorTriggerEvent により、プレイヤー検知後に追跡開始
  • MobAttack: 攻撃開始時に MobAttackHitCollider を有効化し、攻撃ヒット判定を実行
  • CollisionDetector: 共通の衝突判定ロジックとして各オブジェクトで利用
  • PlayerController: PlayerInput からの入力に基づき移動やジャンプ、攻撃を制御。内部で MobAttack を呼び出すことで、敵と同様の攻撃システムを利用

6. 全体のまとめと設計図

6.1 システム全体の特徴

  1. モジュール設計:
    • 各クラスが役割ごとに分離され、再利用性・拡張性が高い
  2. 状態管理:
    • MobStatus を基盤とし、状態遷移(移動、攻撃、死亡)を統一的に管理
    • EnemyStatus, PlayerStatus がそれぞれを継承して固有の実装を拡張
  3. 連携:
    • 敵はプレイヤーの接近を検知して追跡→攻撃
    • プレイヤーは PlayerInput による入力操作で移動や攻撃
    • 同じ攻撃ロジック(MobAttack)を共有することで、一貫性のあるダメージ処理が可能

6.2 設計図・シーケンス図

  • クラス図:
    • MobStatusEnemyStatus / PlayerStatus
    • MobAttackEnemy / Player 両方にアタッチ可能
    • EnemyMove / PlayerController で各自の移動・入力処理
  • 攻撃シーケンス図:
    1. AttackIfPossible 呼び出し
    2. 攻撃状態遷移 → 攻撃アニメーション再生
    3. 攻撃ヒット判定(MobAttackHitCollider)→ ダメージ付与
    4. クールダウン → 通常状態に戻る
    • プレイヤー移動シーケンス図:
      1. 入力(Move, Jump, Attack)を受け取る
      2. 移動方向を算出 → CharacterController.Move
      3. アニメーションへ速度を反映 (MoveSpeed)
      4. 攻撃ボタン押下で MobAttack.AttackIfPossible を実行

      まとめ

      • 本資料では、状態管理(MobStatus, EnemyStatus, PlayerStatus) を中心に、攻撃制御(MobAttack, AttackRangeDetector, MobAttackHitCollider)移動・入力処理(EnemyMove, PlayerController) を連携させる設計について解説しました。
      • 新たに追加された PlayerStatusPlayerController により、プレイヤーも同じフレームワーク(Mobの概念)上で動作・攻撃が可能になります。
      • 今後、プレイヤー特有の状態や演出(例: 無敵時間、被ダメージ演出、UI 連携など)を拡張する際は、PlayerStatusPlayerController に追加実装していくことで対応できます

      Unity

      Posted by hidepon