参考元:
新しくデバイスを追加する
PS4のコントローラーを追加する
NewInputSystemの入力元として、アセットとかで買ったサードパーティの入力APIを追加したいときについてです。
LeanTouchをNewInputSystemのタッチ入力として使うつもりで実装していきます。
Touchだけなら既に実装されていますが。
とりあえずコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
using System.Collections; using System.Collections.Generic; using Lean.Touch; using UnityEditor; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.InputSystem.Layouts; using UnityEngine.InputSystem.LowLevel; using UnityEngine.InputSystem.Utilities; #if UNITY_EDITOR [InitializeOnLoad] #endif [InputControlLayout(displayName = "LeanTouch",stateType = typeof(LeanTouchState))] [UnityEngine.Scripting.Preserve] public class InputFromLeanTouch : InputDevice,IInputUpdateCallbackReceiver { public static InputFromLeanTouch current { get; private set; } public static IReadOnlyList<InputFromLeanTouch> all => s_AllMyDevices; private static List<InputFromLeanTouch> s_AllMyDevices = new List<InputFromLeanTouch>(); public ButtonControl button { get; private set; } public Vector2Control axis { get; private set; } protected override void FinishSetup() { base.FinishSetup(); //引数のpath==構造体でInputControl属性のnameに一致するものが返り値になる button = GetChildControl<ButtonControl>("button");//buttonにアクセスしやすいように axis = GetChildControl<Vector2Control>("axis1");//axis1にアクセスしやすいように } /// <summary> /// IInputUpdateCallbackReceiverの実装するべきメソッド /// 今回のように、入力用のAPI(LeanTouch)が既にある場合 /// このメソッド内で値の更新をする /// </summary> public void OnUpdate() { var state = new LeanTouchState(); state.axis = LeanGesture.GetScreenDelta(); if (LeanTouch.Fingers.Count > 0) { state.buttons |= 1 << 0; } InputSystem.QueueStateEvent(this,state); } public override void MakeCurrent() { base.MakeCurrent(); current = this; } protected override void OnAdded() { base.OnAdded(); s_AllMyDevices.Add(this); } protected override void OnRemoved() { base.OnRemoved(); s_AllMyDevices.Remove(this); } static InputFromLeanTouch() { InitializeInPlayer(); } [RuntimeInitializeOnLoadMethod] static void InitializeInPlayer() { //このメソッドでInputActionアセットのBindingPathに反映される InputSystem.RegisterLayout<InputFromLeanTouch>("LeanTouch"); //デバイスを追加するには下のメソッドを呼び出す //InputSystem.AddDevice<InputFromLeanTouch>(); //今回の場合はLeanTouchがシーン内に置いてある必要があるので実行時にAwakeから呼び出す //そのためのコンポーネントを別に作る必要があるので //LeanTouchSupport.csを別に作る } } //デバイスから取得する情報を構造体として定義する //InputActionアセットで使うところのControlTypeとかバインドに使う名前 //値の型とか public struct LeanTouchState : IInputStateTypeInfo { //何でもよいみたいです //FourCCという識別する仕組みがあるみたい? public FourCC format => new FourCC('L', 'T', 'T', 'O'); //InputControl属性 //nameはInputActionアセットのBinding➡Pathに表示される文字列 //bitは対応しているbitの列 ビットフラグでボタン状態の管理をしている //layoutはInputActionのControlTypeに対応しているもの、だと思います // layoutを省略した場合、フィールドの型から自動でそれなりに判別してくれるそう [InputControl(name = "button",layout = "Button",bit = 0)] public ushort buttons;//ushortは16bitなのでボタン16個分管理できる [InputControl(name = "axis1",layout = "Vector2")] //下のように書くと、axis1のXとYのそれぞれの軸について細かく設定できる模様 //何も書かなくてもaxis1.xとyは自動で追加されています //細かい設定の引数については公式のドキュメントを [InputControl(name = "axis1/x", defaultState = 0.0f, format = "FLT", parameters = "normalize,normalizeMin=-1,normalizeMax=1,normalizeZero=0.0,clamp=2,clampMin=-1,clampMax=1")] [InputControl(name = "axis1/y", defaultState = 0.0f, format = "FLT", parameters = "normalize,normalizeMin=-1,normalizeMax=1,normalizeZero=0.0,clamp=2,clampMin=-1,clampMax=1")] public Vector2 axis; } |
次のファイルはLeanTouchを持ったオブジェクトと一緒につけます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Layouts; /// <summary> /// Leantouchを持っているオブジェクトにつける /// </summary> public class LeanTouchSupport : MonoBehaviour { private void Awake() { //このWithInterfaceというのがイマイチ理解できませんでした //デバイスで使っているAPI(LeanTouch)と、自分が作ったデバイスを追加するスクリプト(InputFromLeanTouch)を //対応させるために付けているのかも //デバイスが削除されたとき(LeanTouchのオブジェクトが消されたときとか)に対応しているデバイスをまとめて削除するために //付けているのかも InputSystem.RegisterLayout<InputFromLeanTouch>( matches:new InputDeviceMatcher().WithInterface("LeanTouch")); } private void OnEnable() { //これでInputActionアセットを使って入力を取得することができる InputSystem.AddDevice( new InputDeviceDescription() { interfaceName = "LeanTouch", product = name }); } private void OnDisable() { var device = InputSystem.devices.FirstOrDefault( x => x.description == new InputDeviceDescription() { interfaceName = "LeanTouch", product = name }); if (device != null) { InputSystem.RemoveDevice(device); } } } |
これで何とか最低限の実装は出来ました。値の設定については適当です。OnUpdate内を必要なように実装する必要があります。
ステップとしては
- 入力を受け取るデータを「構造体」として定義する
- InputActionアセットで表示する情報をInputSystem.RegisterLayout()を使って実装する
- InputSystem.AddDevice()を使って使うデバイスをInputSystemに登録する
のような感じになりました。
今回は新しくデバイスを追加しましたが、レイアウトを追加するだけなら別にやり方があるかもしれません。Touchのデバイス自体は標準で用意されているので、それに追加する感じで実装できたらもっと楽にできるのかも。
NewInputSystem自体の使い方はすでにいくつか情報がありますので省略しました。
別にそのままLeanTouchを使っても良いんですが、AndroidだけじゃなくSteamでも公開したいなと思っていたので、コントローラの差を吸収してくれるNewInputSystemを使ってみようと思いました。
InputActionを介して入力処理を実装すればとりあえず入力自体はInputActionアセットを変更するだけでよくなります。
理解できればそこまで大変ではないかもしれません。でも面倒は面倒です。使いまわせるように出来たら良いんですが。