はじめに
「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
を作成する
-
Assets > Create > Input Actions
メニューから、InputActionAsset
を作成する。 - 作成した
InputActionAsset
に、必要なInputAction
を定義する。
今回はMove
というInputAction
を定義しました。
2. Generate C# Class
オプションを有効にする
作成したInputActionAsset
のGenerate C# Class
を有効にする。
すると、以下のようなコードが自動で生成されます。
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での最適な入力の検出方法なんじゃないかなと思います。
もし「もっと良い方法があるよ」という人がいれば、教えていただけると幸いです。