1
2

More than 3 years have passed since last update.

【Unity】ECSでの入力の最適な検出方法【DOTS】

Posted at

はじめに

「ECSを使ってゲームを作りたい!」ということで、とりあえずECSでプレイヤーキャラクターを移動させるシステムを作ることにした。

とりあえず、以下のコードを見てほしい。

public struct Player : IComponentData { }

public struct Mover : IComponentData {
    public float Speed;
}

// プレイヤーを移動させるためのシステム
public class PlayerMovementSystem : SystemBase {

    // 移動の入力情報
    InputAction m_MoveInput;

    protected override void OnUpdate () {
        // 移動の入力を取得する
        Vector2 input = m_MoveInput.ReadValue<Vector2>();
        float3 movement = new float3(input.x,0f,input.y);

        // 移動させる
        float deltaTime = UnityEngine.Time.deltaTime;
        Entities
            .WithAll<Player>()
            .ForEach((Mover mover,ref Translation translation) => {
                translation.Value += movement * mover.Speed * deltaTime;
            })
            .WithBurst()
            .ScheduleParallel();
    }
}

ただ、一見動きそうなこのコードには問題があって、移動の入力情報(m_MoveInput)には何も割り当てられていないのです。

しかし、単純にnewすればいいというものでもなく、InputActionのコンストラクタは文字列ベースのハードコーディングになるので普段使いには適さない。

Keyboard.currentなどのAPIを使う方法もあるが、これもしたくない。
とにかくハードコーディングはしたくない。

では、m_MoveInputはどうやって設定すればいいのだろうか?

結論: Generate C# Classオプションを使う

InputSystemには、InputActionAssetからC#コードを生成する機能があります。
そして、生成されたクラスを使用することで、InputActionAssetで定義されたInputActionに対してコードから簡単にアプローチすることができるようになります。

この方法の利点として、

  • UnityエディターでInputActionを編集可能
    • ハードコーディングせずに済む
  • 外部からInputActionの参照を割り当てる必要が無い
    • そのための余計なコンポーネントなどを実装せずに済む

というところが挙げられます。

以下からは実際の手順の解説です。

1. InputActionAssetを作成する

  1. Assets > Create > Input Actionsメニューから、InputActionAssetを作成する。
  2. 作成したInputActionAssetに、必要なInputActionを定義する。

今回はMoveというInputActionを定義しました。

スクリーンショット 2021-08-04 005219.jpg

2. Generate C# Classオプションを有効にする

作成したInputActionAssetGenerate C# Classを有効にする。

スクリーンショット 2021-08-04 005250.jpg

すると、以下のようなコードが自動で生成されます。

スクリーンショット 2021-08-04 190154.jpg

3. コードを書く

InputActionAssetから生成したクラスを使用し、最初のコードに少し手を加える。

public class PlayerMovementSystem : SystemBase {

    PlayerInputActions m_Input;
    InputAction m_MoveInput;

    protected override void OnCreate () {
        // PlayerInputActionsをインスタンス化し、有効にする
        m_Input = new PlayerInputActions();
        m_Input.Enable();

        // PlayerInputActionsに定義されているMoveをm_MoveInputに割り当てる
        m_MoveInput = m_Input.Player.Move;
    }

    protected override void OnUpdate () {
        // 移動の入力を取得する
        Vector2 input = m_MoveInput.ReadValue<Vector2>();
        float3 movement = new float3(input.x,0f,input.y);

        // 移動させる
        float deltaTime = UnityEngine.Time.deltaTime;
        Entities
            .WithAll<Player>()
            .ForEach((Mover mover,ref Translation translation) => {
                translation.Value += movement * mover.Speed * deltaTime;
            })
            .WithBurst()
            .ScheduleParallel();
    }

    protected override void OnDestroy () {
        m_Input.Disable();
        m_Input.Dispose();
    }

}

おわりに

ECSでの入力について調べましたが、これがECSでの最適な入力の検出方法なんじゃないかなと思います。

もし「もっと良い方法があるよ」という人がいれば、教えていただけると幸いです。

参考

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