1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UnityのInputSystemでさらに入力情報を取得するクラスを作ってみた

Posted at

概要

UnityのInputSystemはキーボード、マウス、ゲームパッドなどの入力を一括管理できる代物です。詳しくはマニュアルをご覧ください。

InputSystemは基本的に入力開始時と入力終了時、トリガーやスティックだったらfloatvector2で押し具合を受け取れるものです。
ただアクションゲーム前提だともっと詳しく入力情報ほしいので、さらに入力回数、入力時間や入力開始、入力中、入力終了フレームを計算するクラスを作りました。

環境

Unity 6000.0.23f1

実装

まずは、InputActionAssetを作成してラッパークラスを生成します。
このクラスはActionで関数を登録することで入力時、入力終了時にコールバックを受け取れ、引数で入力値のクラスを受け取ることができます。

InputData

このクラスでは先ほどのコールバック時にInputを呼び、引数のboolに入力時にはtrue、終了時にはfalseを渡します。

このコールバック時とは別にUpdateで毎フレーム、計算用のPostInputを呼んで入力回数や入力時間などを計算します。

/// <summary>
/// インプット状態の列挙
/// </summary>
public enum InputState
{
    None = 0, // 入力なし
    Start = 1, // 入力開始時
    Middle = 2, // 入力中
    End = 3 // 入力終了時
}

/// <summary>
/// インプット情報を格納する構造体
/// </summary>
public struct InputInfo
{
    public bool isInput; // 入力判定
    public int inputCount; // 入力回数
    public float inputTime; // 入力時間
    public InputState inputState; //入力の状態
}

/// <summary>
/// インプット情報計算の抽象クラス
/// </summary>
public abstract class InputData
{
    protected bool _isInput; 
    protected bool _isInputed;
    protected InputInfo _inputInfo;
    protected bool _isPool;
    protected bool _poolInput;
    
    /// <summary>
    /// 入力計算のためUpdateで毎フレーム呼ぶ
    /// </summary>
    public void PostInput()
    {
        if (!(_isPool & _inputInfo.inputState == InputState.Start))
        {
            if (_isInput)
            {
                _inputInfo.inputTime += Time.deltaTime;
                _inputInfo.inputState = InputState.Middle;
            }
            else
            {
                _inputInfo.inputTime = 0;
                _inputInfo.inputState = InputState.None;
            }
        }
        _isInputed = _isInput;
        _inputInfo.isInput = _isInput | _isInputed;
    }

    /// <summary>
    /// 先行入力用
    /// </summary>
    /// <param name="isPool"></param>
    public void InputPool(bool isPool)
    {
        _isPool = isPool;
        if (!isPool)
            _poolInput = false;
    }

    public InputInfo inputInfo {get => _inputInfo;}
}


/// <summary>
/// スティック、トリガーなど入力値がある場合
/// </summary>
/// <typeparam name="T"><see cref="UnityEngine.InputSystem.InputAction.CallbackContext.ReadValue{TValue}()"/>の型に合わせる</typeparam>
public class InputValueData<T> : InputData where T : struct
{
    private T _value; // 入力値

    public void Input(bool isInput, T value)
    {
        if (isInput)
            _value = value;
        if (!_isInputed & isInput)
        {
            ++ _inputInfo.inputCount;
            _inputInfo.inputState = InputState.Start;
        }
        if (_isInputed & !isInput)
            _inputInfo.inputState = InputState.End;

        _isInput = isInput;
        _inputInfo.isInput = _isInput | _isInputed;
    }

    public T value {get => _inputInfo.isInput ? _value : default;}
}

/// <summary>
/// ボタン用
/// </summary>
public class InputButtonData : InputData
{
    public void Input(bool isInput)
    {
        if (!_isInputed & isInput)
        {
            ++ _inputInfo.inputCount;
            _inputInfo.inputState = InputState.Start;
        }
        if (_isInputed & !isInput)
            _inputInfo.inputState = InputState.End;
            
        _isInput = isInput;
        _inputInfo.isInput = _isInput | _isInputed;
    }
}

使い方は以下のようになります。

public class PlayableCharacterInputManager : SingletonMonoBehaviour<PlayableCharacterInputManager>
{
    private PlayableCharacterInput _inputs;
    private List<InputData> _inputDataList;

    private InputValueData<Vector2> _move;
    private InputValueData<Vector2> _moveCamera;
    private InputButtonData _jump;
    private InputButtonData _guard;
    private InputButtonData _step;
    private InputButtonData _attack;
    private InputValueData<float> _shoot;

    protected override void OnAwakeProcess()
    {
        //InputActionAssetのラッパークラスをインスタンス化
        _inputs = new PlayableCharacterInput();

        //それぞれの入力用のInputDataを作成
        _move = new InputValueData<Vector2>();
        _moveCamera = new InputValueData<Vector2>();
        _jump = new InputButtonData();
        _guard = new InputButtonData();
        _step = new InputButtonData();
        _attack = new InputButtonData();
        _shoot = new InputValueData<float>();
        _inputDataList = new List<InputData>()
        {
            _move,
            _moveCamera,
            _jump,
            _guard,
            _step,
            _attack,
            _shoot
        };

        //CallBackを登録

        _inputs.Enable();
        _inputs.Player.Move.performed += Move;
        _inputs.Player.Move.canceled += Move;


        _inputs.Player.MoveCamera.performed += MoveCamera;
        _inputs.Player.MoveCamera.canceled += MoveCamera;

        _inputs.Player.Jump.performed += Jump;
        _inputs.Player.Jump.canceled += Jump;

        _inputs.Player.Guard.performed += Guard;
        _inputs.Player.Guard.canceled += Guard;

        _inputs.Player.Step.performed += Step;
        _inputs.Player.Step.canceled += Step;

        _inputs.Player.Attack.performed += Attack;
        _inputs.Player.Attack.canceled += Attack;
        
        _inputs.Player.Shoot.performed += Shoot;
        _inputs.Player.Shoot.canceled += Shoot;
    }

    protected override void OnDestroyProcess()
    {
        if (_inputs == null) return;
        _inputs.Disable();
        _inputs.Dispose();

        _inputs.Player.Move.performed -= Move;
        _inputs.Player.Move.canceled -= Move;

        _inputs.Player.MoveCamera.performed -= MoveCamera;
        _inputs.Player.MoveCamera.canceled -= MoveCamera;

        _inputs.Player.Jump.performed -= Jump;
        _inputs.Player.Jump.canceled -= Jump;

        _inputs.Player.Guard.performed -= Guard;
        _inputs.Player.Guard.canceled -= Guard;

        _inputs.Player.Step.performed -= Step;
        _inputs.Player.Step.canceled -= Step;
        
        _inputs.Player.Attack.performed -= Attack;
        _inputs.Player.Attack.canceled -= Attack;

        _inputs.Player.Shoot.performed -= Shoot;
        _inputs.Player.Shoot.canceled -= Shoot;
    }

    //それぞれのコールバックでInputを呼ぶ

    private void Move(InputAction.CallbackContext context)
    {
        if (context.performed)
            _move.Input(true, context.ReadValue<Vector2>());
        if (context.canceled)
            _move.Input(false, context.ReadValue<Vector2>());
    }

    private void MoveCamera(InputAction.CallbackContext context)
    {
        if (context.performed)
            _moveCamera.Input(true, context.ReadValue<Vector2>());
        if (context.canceled)
            _moveCamera.Input(false, context.ReadValue<Vector2>());
    }

    private void Jump(InputAction.CallbackContext context)
    {
        if (context.performed)
            _jump.Input(true);
        if (context.canceled)
            _jump.Input(false);
    }

    private void Guard(InputAction.CallbackContext context)
    {
        if (context.performed)
            _guard.Input(true);
        if (context.canceled)
            _guard.Input(false);
    }
    
    private void Step(InputAction.CallbackContext context)
    {
        if (context.performed)
            _step.Input(true);
        if (context.canceled)
            _step.Input(false);
    }
    
    private void Attack(InputAction.CallbackContext context)
    {
        if (context.performed)
            _attack.Input(true);
        if (context.canceled)
            _attack.Input(false);
    }

    private void Shoot(InputAction.CallbackContext context)
    {
        if (context.performed)
            _shoot.Input(true, context.ReadValue<float>());
        if (context.canceled)
            _shoot.Input(false, context.ReadValue<float>());
    }
            
    // Updateで毎フレーム呼ばれるとこでPostInputを呼ぶ
    public void PlayableCharacterInputPostTick()
    {
        foreach (var inputData in _inputDataList)
        {
            inputData.PostInput();
        }
    }

    public void PlayableCharacterInputPools(bool isInputPool)
    {
        foreach (var inputData in _inputDataList)
        {
            inputData.InputPool(isInputPool);
        }
    }

    public InputValueData<Vector2> move {get => _move;}
    public InputValueData<Vector2> moveCamera {get => _moveCamera;}
    public InputButtonData jump {get => _jump;}
    public InputButtonData guard {get => _guard;}
    public InputButtonData step {get => _step;}
    public InputButtonData attack {get => _attack;}
    public InputValueData<float> shoot {get => _shoot;}
}
1
0
0

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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?