具体的な操作方法
Device:
- このフレームで Space キーが押されたかどうかを確認するには?
- 接続されているすべてのゲームパッドを検出するには?
- プレイヤーが現在使用しているゲームパッドを特定するには?
- 新しい Device が接続されたことを検出するには?
Action:
- Fire タイプの Action を作成するには?
- ボタンを 0.4 秒間押し続けたら Action がトリガーされるようにするには?
- "正" と "負" のボタンを使用して軸を動かすには?
- 入力を再バインドするための UI をゲーム内に作成するには?
このフレームで Space キーが押されたかどうかを確認するには?
以下のコードを使用します。
Keyboard.current.space.wasPressedThisFrame
このコードは、以下のように変更して、ボタンやその他の入力タイプが搭載されている他の Device に合わせることができます。
Gamepad.current.aButton.wasPressedThisFrame
接続されているすべてのゲームパッドを検出するには?
Gamepad
クラスを使用します。
var allGamepads = Gamepad.all;
// または、より明確なバージョンを指定します。
var allPS4Gamepads = DualShockGamepadPS4.all;
別の方法として、LINQ 式または コントロールパス を使用して、一般的な Device クエリを実行することもできます。
// すべてのデバイスを調べてゲームパッドを選択します。
InputSystem.devices.Select(x => x is Gamepad);
// gamepad レイアウトを使用しているもの、またはそのレイアウトに基づいているものをすべて照会します。
// ノート: 結果は必ず Dispose() で破棄してください。
InputSystem.FindControls("<gamepad>");
プレイヤーが現在使用しているゲームパッドを特定するには?
以下のコードを使用します。
var gamepad = Gamepad.current;
// 他のタイプのデバイスでも同様です。
var keyboard = Keyboard.current;
var mouse = Mouse.current;
新しい Device が接続されたことを検出するには?
以下のコードを使用します。
InputSystem.onDeviceChange +=
(device, change) =>
{
switch (change)
{
case InputDeviceChange.Added:
// 新しい Device。
break;
case InputDeviceChange.Disconnected:
// Device がの接続が切断されました。
break;
case InputDeviceChange.Connected:
// 再び接続されました。
break;
case InputDeviceChange.Removed:
// Input System から完全に削除されました。デフォルトでは、検出された Device はシステムに保持されます。
break;
default:
// その他のイベントタイプについては、InputDeviceChange のリファレンスを参照してください。
break;
}
}
詳細については、"Device の監視" に関するドキュメントを参照してください。
単純な Fire タイプの Action を作成するには?
以下のコードを使用します。
// すべてのデバイスのプライマリアクションコントロールにバインドする Action を作成します。
var action = new InputAction(binding: "*/{primaryAction}");
// Action がトリガーされたときに独自のコードが実行されるようにします。
action.performed += _ => Fire();
// コントロールの変更のリッスンを開始します。
action.Enable();
以下のように、シリアル化された InputAction
型のフィールドを MonoBehaviour
に加えることもできます。
public class MyControllerComponent : MonoBehaviour
{
public InputAction fireAction;
public InputAction walkAction;
}
エディターでは、インスペクターウィンドウで Action の Binding を作成し、編集することができます。
ノート: このほか、コード内で Action を有効にし、応答を登録する必要があります。これらの処理は、コンポーネントの
Awake
メソッドで行うことができます。
void Awake()
{
fireAction.performed += Fire;
walkAction.performed += Walk;
}
void OnEnable()
{
fireAction.Enable();
walkAction.Enable();
}
void OnDisable()
{
fireAction.Disable();
walkAction.Disable();
}
void Fire(CallbackContext ctx)
{
//...
}
void Walk(CallbackContext ctx)
{
//...
}
デリゲートからの割り当てが懸念される場合は、コールバック駆動型のアプローチではなく、ポーリングによるアプローチを使用できます。
void OnEnable()
{
fireAction.Enable();
walkAction.Enable();
}
void OnDisable()
{
fireAction.Disable();
walkAction.Disable();
}
void Update()
{
if (fireAction.triggered)
Fire();
if (walkAction.triggered)
Walk();
}
void Fire()
{
//...
}
void Walk()
{
//...
}
一般に、アプリケーションでは複数の Action を処理する必要があります。その場合、複数の Action を Input Action アセットファイルにまとめることができます。Input Action アセットを作成するには、以下のステップに従います。
- Project ウィンドウで Create をクリックします。
- Input Actions を選択します。
- アセットをダブルクリックし、Input Action を含む 1 つ以上の Input Action Map を作成し、編集します。
その後、作成したアセットのインスペクターで Generate C# Class をクリックすると、Unity によって Action のラッパークラスが生成されます。これを以下のように使用できます。
MyInputActionAssetClass actions;
public void OnEnable()
{
actions = new MyInputActionAssetClass();
controls.myActionsMap.fire.performed += Fire;
controls.myActionsMap.walk.performed += Walk;
}
詳細については、Action に関するドキュメントを参照してください。
ボタンを 0.4 秒間押し続けたら Action がトリガーされるようにするには?
以下のように、Action に hold Interaction を設定します。
var action = new InputAction(binding: "*/{PrimaryAction}",
modifiers: "hold(duration=0.4)");
ボタンが押され始めたときに UI フィードバックを表示するには、started
コールバックを使用します。
action.started += _ => ShowGunChargeUI();
action.performed += _ => FinishGunChargingAndHideChargeUI();
action.cancelled += _ => HideChargeUI();
"正" と "負" のボタンを使用して軸を動かすには?
UI またはコードで 軸合成 バインディングを使用し、その部品をそれぞれのボタンにバインドします。
var accelerateAction = new InputAction("Accelerate");
accelerateAction.AddCompositeBinding("Axis")
.With("Positive", "<Gamepad>/rightTrigger")
.With("Negative", "<Gamepad>/leftTrigger");
入力を再バインドするための UI をゲーム内に作成するには?
再バインディングをトリガーするボタンを備えた UI を作成します。アクションにコントロールをバインドするボタンをユーザーがクリックしたら、InputAction.PerformInteractiveRebinding
を使用して再バインディングを処理します。
void RemapButtonClicked(InputAction actionToRebind)
{
var rebindOperation = actionToRebind.PerformInteractiveRebinding()
// マウスモーションによる意図しない入力を防止
.WithControlsExcluding("Mouse")
.OnMatchWaitForAnother(0.1f)
.Start();
}
Package Manager を使用して Input System パッケージにインストールできる Tanks Demo サンプルには、インタラクティブな再バインディング UI の例が含まれています。
左手用の XR コントローラーをターゲットとする Action を設定するには?
以下のコードを使用します。
var action = new InputAction(binding: "/<XRController>{leftHand}/position");
インスペクターまたは Input Action アセットエディターウィンドウでは、パスを直接指定することなく、任意の Input Binding にこれを設定できます。
任意のデバイスの任意のボタンを待機するには?
以下のコードを使用します。
var myAction = new InputAction(binding: "/*/<button>");
myAction.onPerformed += (action, control) => Debug.Log($"Button {control.name} pressed!");
myAction.Enable();
ノート: これは効率が悪く、リソース消費量の多い方法です。1 つの Action で実行される処理量は、その Action がターゲットとする Control の量と直接的に相関します。各 Device の各ボタンをすべてターゲットにすると、Control の数が多くなり、処理オーバーヘッドが増加します。例えば、キーボードは単独で多数のボタンを備えていますが、そのそれぞれを個別に処理することが必要になります。
左手用の XR コントローラーを右手用にするには?
以下のコードを使用します。
var controller = XRController.leftHand;
InputSystem.SetUsage(controller, CommonUsages.RightHand);
タッチスクリーンから、現在のタッチをすべて取得するには?
推奨される方法は EnhancedTouch.Touch.activeTouches
を使用することです。
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
public void Update()
{
foreach (var touch in Touch.activeTouches)
Debug.Log($"{touch.touchId}: {touch.screenPosition},{touch.phase}");
}
ノート: 最初に
InputSystem.EnhancedTouch.Enable()
を呼び出して、拡張タッチサポートを有効にする必要があります。
低レベルの Touchscreen.current.touches
API を使用することもできます。
Device を作成するには?
以下のコードを使用します。
InputSystem.AddDevice<Gamepad>();
または、Device が使用可能であることを Input System に通知し、一致するレイアウトから Device を作成させる方法もあります。レイアウトが存在しない場合は、手動でレイアウトを加えるまで、Input System による Device の作成は行われません。
InputSystem.ReportAvailableDevice(
new InputDeviceDescription
{
product = "AwesomeGadget",
manufacturer = "Awesome Products Inc."
}
);
独自のカスタム Device を作成するには?
これを行うには、2 つの方法が考えられます。
コード内で既存の C# InputDevice
クラスのいずれかを使用して Device とのインターフェースを確立する場合は、JSON を使用して、既存のレイアウトに基づいて作成することができます。
{
"name" : "MyDevice",
"extend" : "Gamepad", // または他の Device
"controls" : [
{
"name" : "firstButton",
"layout" : "Button",
"offset" : 0,
"bit": 0,
"format" : "BIT",
},
{
"name" : "secondButton",
"layout" : "Button",
"offset" : 0,
"bit": 1,
"format" : "BIT",
},
{
"name" : "axis",
"layout" : "Axis",
"offset" : 4,
"format" : "FLT",
"parameters" : "clamp=true,clampMin=0,clampMax=1"
}
]
}
次に、レイアウトをシステムに登録してインスタンス化します。
InputSystem.RegisterControlLayout(myDeviceJson);
var device = InputSystem.AddDevice("MyDevice");
または、C# で独自の InputDevice
クラスと状態レイアウトを作成することもできます。
public struct MyDeviceState : IInputStateTypeInfo
{
// 状態ブロックのメモリレイアウトを識別するために FourCC 型のコードを使用します。
public FourCC format => new FourCC('M', 'D', 'E', 'V');
[InputControl(name = "firstButton", layout = "Button", bit = 0)]
[InputControl(name = "secondButton", layout = "Button", bit = 1)]
public int buttons;
[InputControl(layout = "Analog", parameters="clamp=true,clampMin=0,clampMax=1")]
public float axis;
}
[InputState(typeof(MyDeviceState)]
public class MyDevice : InputDevice
{
public ButtonControl firstButton { get; private set; }
public ButtonControl secondButton { get; private set; }
public AxisControl axis { get; private set; }
protected override void FinishSetup(InputControlSetup setup)
{
firstButton = setup.GetControl<ButtonControl>(this, "firstButton");
secondButton = setup.GetControl<ButtonControl>(this, "secondButton");
axis = setup.GetControl<AxisControl>(this, "axis");
base.FinishSetup(setup);
}
}
Device のインスタンスを作成するには、Device をレイアウトとして登録してからインスタンス化します。
InputSystem.RegisterControlLayout("MyDevice", typeof(MyDevice));
InputSystem.AddDevice("MyDevice");
詳細については、HID に関するドキュメントを参照してください。
GamepadState
とは異なる形式で送信されるゲームパッドデータを扱うには?
"Gamepad" レイアウトを拡張し、その Control をカスタマイズします。
この実例の 1 つは、HID を通じてサポートされる macOS 上の Xbox コントローラーです。そのレイアウトは、以下のようなものです。
{
"name" : "XboxGamepadOSX",
"extend" : "Gamepad",
"format" : "HID",
"device" : { "interface" : "HID", "product" : "Xbox.*Controller" },
"controls" : [
{ "name" : "leftShoulder", "offset" : 2, "bit" : 8 },
{ "name" : "rightShoulder", "offset" : 2, "bit" : 9 },
{ "name" : "leftStickPress", "offset" : 2, "bit" : 14 },
{ "name" : "rightStickPress", "offset" : 2, "bit" : 15 },
{ "name" : "buttonSouth", "offset" : 2, "bit" : 12 },
{ "name" : "buttonEast", "offset" : 2, "bit" : 13 },
{ "name" : "buttonWest", "offset" : 2, "bit" : 14 },
{ "name" : "buttonNorth", "offset" : 2, "bit" : 15 },
{ "name" : "dpad", "offset" : 2 },
{ "name" : "dpad/up", "offset" : 0, "bit" : 8 },
{ "name" : "dpad/down", "offset" : 0, "bit" : 9 },
{ "name" : "dpad/left", "offset" : 0, "bit" : 10 },
{ "name" : "dpad/right", "offset" : 0, "bit" : 11 },
{ "name" : "start", "offset" : 2, "bit" : 4 },
{ "name" : "select", "offset" : 2, "bit" : 5 },
{ "name" : "xbox", "offset" : 2, "bit" : 2, "layout" : "Button" },
{ "name" : "leftTrigger", "offset" : 4, "format" : "BYTE" },
{ "name" : "rightTrigger", "offset" : 5, "format" : "BYTE" },
{ "name" : "leftStick", "offset" : 6, "format" : "VC2S" },
{ "name" : "leftStick/x", "offset" : 0, "format" : "SHRT", "parameters" : "normalize,normalizeMin=-0.5,normalizeMax=0.5" },
{ "name" : "leftStick/y", "offset" : 2, "format" : "SHRT", "parameters" : "invert,normalize,normalizeMin=-0.5,normalizeMax=0.5" },
{ "name" : "rightStick", "offset" : 10, "format" : "VC2S" },
{ "name" : "rightStick/x", "offset" : 0, "format" : "SHRT", "parameters" : "normalize,normalizeMin=-0.5,normalizeMax=0.5" },
{ "name" : "rightStick/y", "offset" : 2, "format" : "SHRT", "parameters" : "invert,normalize,normalizeMin=-0.5,normalizeMax=0.5" }
]
}
例えば、独自の Device で一部のボタンが入れ替わっている場合も、同じ原則が適用されます。この場合は、ボタンのオフセットを再マップできます。
ネイティブバックエンドで特定の Device が検出されたときに、Input System で強制的に独自のレイアウトを使用するには?
以下のように、レイアウトで Device を記述します。
{
"name" : "MyGamepad",
"extend" : "Gamepad",
"device" : {
// ここでの文字列はすべて正規表現であり、大文字と小文字は区別されません。
"product" : "MyController",
"manufacturer" : "MyCompany"
}
}
レイアウトの変更をネイティブの Device に反映させるために Unity を再起動する必要はありません。Input System では、ドメインの再ロード時に毎回自動的に変更が適用されるため、レイアウトを調整するだけで、スクリプトが再コンパイルされるたびに最新バージョンで Device が再作成されます。
ゲームパッドのスティックにデッドゾーンを設定するには?
以下のように、スティックに Stick Deadzone Processor を設定します。
{
"name" : "MyGamepad",
"extend" : "Gamepad",
"controls" : [
{
"name" : "leftStick",
"processors" : "stickDeadzone(min=0.125,max=0.925)"
},
{
"name" : "rightStick",
"processors" : "stickDeadzone(min=0.125,max=0.925)"
}
]
}
C# 状態構造体でも、同じことができます。
public struct MyDeviceState
{
[InputControl(processors = "stickDeadzone(min=0.125,max=0.925)"]
public StickControl leftStick;
[InputControl(processors = "stickDeadzone(min=0.125,max=0.925)"]
public StickControl rightStick;
}
ゲームパッドレイアウトには既に Stick Deadzone Processor が設定されており、その最小値と最大値は、InputSettings.defaultDeadzoneMin
と InputSettings.defaultDeadzoneMax
から取得されます。
レンダー前にヘッドトラッキングを追加で更新するには?
最初に、Device でレンダー前の更新を有効にします。
{
"name" : "MyHMD",
"extend" : "HMD",
"beforeRender" : "Update"
}
次に、レンダリングが実行される直前に合わせて、HMD に対する追加の StateEvent
をキューに入れます。HMD が、非トラッキングコントロールとトラッキングコントロールの組み合わせから成っている場合は、完全な状態イベントの代わりに差分イベントを送信してトラッキングだけを更新することもできます。
システムを通じて流れるイベントを記録するには?
以下のコードを使用します。
var trace = new InputEventTrace(); // デバイス ID を指定して、特定のデバイスに対する
// イベントだけを追跡することもできます。
trace.Enable();
//... 処理を実行
var current = new InputEventPtr();
while (trace.GetNextEvent(ref current))
{
Debug.Log("Got some event: " + current);
}
// IEnumerable もサポートされます。
foreach (var eventPtr in trace)
Debug.Log("Got some event: " + eventPtr);
// トレースではアンマネージリソースが使用されます。必ず破棄してください。
trace.Dispose();
処理されるイベントを確認するには?
以下のコードを使用します。
InputSystem.onEvent +=
(eventPtr, device) =>
{
// 例えば、イベントを手動で処理した後、処理済みとして
// マークすると、それ以上の処理を停止できます。
eventPtr.handled = true;
};
現在使用されている Device と、それらの状態を確認するには?
Windows > Analysis > Input Debugger (Debugging.md) に移動します。Device をダブルクリックすると、その Control が表示されます。Remote Devices ボタンをクリックして、接続されている任意のコンピューターまたはデバイスに展開された Unity Player からリモートで Device を確認することもできます。