转载请注明出处:🔗https://blog.csdn.net/weixin_44013533/article/details/135630016
作者:CSDN@|Ringleader|
主要参考:
- Unity官方Input System手册与API
- 【Unity学习笔记】Unity TestRunner使用
- 【Unity学习笔记】第十二 · New Input System 及其系统结构 和 源码浅析
注:本文使用的unity版本是2021.3.25f,InputSystem版本为1.5.1
deafault Interaction测试用例
-
ButtonAndValue
[Test] public void Actions_ButtonActions_RespectButtonPressPoints() { InputSystem.settings.defaultButtonPressPoint = 0.5f; InputSystem.settings.buttonReleaseThreshold = 0.9f; // Release at 90% of press point puts release at 0.45. // Customize gamepad with specific button press point on right trigger (but not on left). InputSystem.RegisterLayoutOverride(@" { ""name"" : ""GamepadRightTriggerWithPressPoint"", ""extend"" : ""Gamepad"", ""controls"" : [ { ""name"" : ""rightTrigger"", ""parameters"" : ""pressPoint=0.75"" } ] } "); var gamepad = InputSystem.AddDevice<Gamepad>(); var rightTriggerButton = new InputAction(type: InputActionType.Button, binding: "<Gamepad>/rightTrigger"); var rightTriggerValue = new InputAction(type: InputActionType.Value, binding: "<Gamepad>/rightTrigger"); var leftTriggerButton = new InputAction(type: InputActionType.Button, binding: "<Gamepad>/leftTrigger"); var leftTriggerValue = new InputAction(type: InputActionType.Value, binding: "<Gamepad>/leftTrigger"); rightTriggerButton.Enable(); rightTriggerValue.Enable(); leftTriggerButton.Enable(); leftTriggerValue.Enable(); using (var rightTriggerButtonTrace = new InputActionTrace(rightTriggerButton)) using (var rightTriggerValueTrace = new InputActionTrace(rightTriggerValue)) using (var leftTriggerButtonTrace = new InputActionTrace(leftTriggerButton)) using (var leftTriggerValueTrace = new InputActionTrace(leftTriggerValue)) { Set(gamepad.leftTrigger, 0.25f); Set(gamepad.rightTrigger, 0.25f); // Have crossed neither button threshold. Actions start but don't perform. Assert.That(leftTriggerButtonTrace, Started(leftTriggerButton, gamepad.leftTrigger, value: 0.25f)); Assert.That(rightTriggerButtonTrace, Started(rightTriggerButton, gamepad.rightTrigger, value: 0.25f)); Assert.That(leftTriggerValueTrace, Started(leftTriggerValue, gamepad.leftTrigger, value: 0.25f) .AndThen(Performed(leftTriggerValue, gamepad.leftTrigger, value: 0.25f))); Assert.That(rightTriggerValueTrace, Started(rightTriggerValue, gamepad.rightTrigger, value: 0.25f) .AndThen(Performed(rightTriggerValue, gamepad.rightTrigger, value: 0.25f))); rightTriggerButtonTrace.Clear(); rightTriggerValueTrace.Clear(); leftTriggerButtonTrace.Clear(); leftTriggerValueTrace.Clear(); Set(gamepad.leftTrigger, 0.6f); Set(gamepad.rightTrigger, 0.6f); // Have grossed global but not right trigger threshold. Assert.That(leftTriggerButtonTrace, Performed(leftTriggerButton, gamepad.leftTrigger, value: 0.6f)); Assert.That(rightTriggerButtonTrace, Is.Empty); Assert.That(leftTriggerValueTrace, Performed(leftTriggerValue, gamepad.leftTrigger, value: 0.6f)); Assert.That(rightTriggerValueTrace, Performed(rightTriggerValue, gamepad.rightTrigger, value: 0.6f)); rightTriggerButtonTrace.Clear(); rightTriggerValueTrace.Clear(); leftTriggerButtonTrace.Clear(); leftTriggerValueTrace.Clear(); Set(gamepad.leftTrigger, 0.9f); Set(gamepad.rightTrigger, 0.9f); // No change on left trigger action, right trigger crossed threshold. Assert.That(leftTriggerButtonTrace, Is.Empty); Assert.That(rightTriggerButtonTrace, Performed(rightTriggerButton, gamepad.rightTrigger, value: 0.9f)); Assert.That(leftTriggerValueTrace, Performed(leftTriggerValue, gamepad.leftTrigger, value: 0.9f)); Assert.That(rightTriggerValueTrace, Performed(rightTriggerValue, gamepad.rightTrigger, value: 0.9f)); rightTriggerButtonTrace.Clear(); rightTriggerValueTrace.Clear(); leftTriggerButtonTrace.Clear(); leftTriggerValueTrace.Clear(); Set(gamepad.leftTrigger, 0.6f); Set(gamepad.rightTrigger, 0.6f); // No change on left trigger action, right trigger action cancels. Assert.That(leftTriggerButtonTrace, Is.Empty); Assert.That(rightTriggerButtonTrace, Started(rightTriggerButton, gamepad.rightTrigger, value: 0.6f)); Assert.That(leftTriggerValueTrace, Performed(leftTriggerValue, gamepad.leftTrigger, value: 0.6f)); Assert.That(rightTriggerValueTrace, Performed(rightTriggerValue, gamepad.rightTrigger, value: 0.6f)); rightTriggerButtonTrace.Clear(); rightTriggerValueTrace.Clear(); leftTriggerButtonTrace.Clear(); leftTriggerValueTrace.Clear(); Set(gamepad.leftTrigger, 0.4f); Set(gamepad.rightTrigger, 0.4f); // Left trigger cancels, right trigger *starts* again (but doesn't perform). Assert.That(leftTriggerButtonTrace, Started(leftTriggerButton, gamepad.leftTrigger, value: 0.4f)); Assert.That(rightTriggerButtonTrace, Is.Empty); Assert.That(leftTriggerValueTrace, Performed(leftTriggerValue, gamepad.leftTrigger, value: 0.4f)); Assert.That(rightTriggerValueTrace, Performed(rightTriggerValue, gamepad.rightTrigger, value: 0.4f)); rightTriggerButtonTrace.Clear(); rightTriggerValueTrace.Clear(); leftTriggerButtonTrace.Clear(); leftTriggerValueTrace.Clear(); Set(gamepad.leftTrigger, 0f); Set(gamepad.rightTrigger, 0f); // No change on left and right trigger actions. Assert.That(leftTriggerButtonTrace, Canceled(leftTriggerButton, gamepad.leftTrigger, 0f)); Assert.That(rightTriggerButtonTrace, Canceled(rightTriggerButton, gamepad.rightTrigger, 0f)); Assert.That(leftTriggerValueTrace, Canceled(leftTriggerValue, gamepad.leftTrigger, value: 0f)); Assert.That(rightTriggerValueTrace, Canceled(rightTriggerValue, gamepad.rightTrigger, value: 0f)); rightTriggerButtonTrace.Clear(); leftTriggerButtonTrace.Clear(); // Make sure that we start and cancel if we press the buttons just a little and then release. Set(gamepad.leftTrigger, 0.25f); Set(gamepad.rightTrigger, 0.25f); Assert.That(leftTriggerButtonTrace, Started(leftTriggerButton, gamepad.leftTrigger, value: 0.25f)); Assert.That(rightTriggerButtonTrace, Started(rightTriggerButton, gamepad.rightTrigger, value: 0.25f)); rightTriggerButtonTrace.Clear(); leftTriggerButtonTrace.Clear(); Set(gamepad.leftTrigger, 0f); Set(gamepad.rightTrigger, 0f); Assert.That(leftTriggerButtonTrace, Canceled(leftTriggerButton, gamepad.leftTrigger, value: 0f)); Assert.That(rightTriggerButtonTrace, Canceled(rightTriggerButton, gamepad.rightTrigger, value: 0f)); } }
-
passthrough
[Test] public void Actions_passthroughActions() { var gamepad = InputSystem.AddDevice<Gamepad>(); var rightTriggerValue = new InputAction(type: InputActionType.PassThrough, binding: "<Gamepad>/rightTrigger"); rightTriggerValue.Enable(); using (var rightTriggerValueTrace = new InputActionTrace(rightTriggerValue)) { Set(gamepad.rightTrigger, 0.25f); Assert.That(rightTriggerValueTrace, Performed(rightTriggerValue, gamepad.rightTrigger, value: 0.25f)); rightTriggerValueTrace.Clear(); Set(gamepad.rightTrigger, 0.6f); Assert.That(rightTriggerValueTrace, Performed(rightTriggerValue, gamepad.rightTrigger, value: 0.6f)); rightTriggerValueTrace.Clear(); Set(gamepad.rightTrigger, 0.9f); Assert.That(rightTriggerValueTrace, Performed(rightTriggerValue, gamepad.rightTrigger, value: 0.9f)); rightTriggerValueTrace.Clear(); Set(gamepad.rightTrigger, 0f); Assert.That(rightTriggerValueTrace, Performed(rightTriggerValue, gamepad.rightTrigger, value: 0f)); rightTriggerValueTrace.Clear(); } }
Press Interaction测试用例
using System.Diagnostics.CodeAnalysis;
using NUnit.Framework;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Utilities;
namespace Scenes.TestAction
{
[SuppressMessage("ReSharper", "AccessToStaticMemberViaDerivedType")]
public class TestAction : InputTestFixture
{
[Test]
[TestCase(InputActionType.Value)]
[TestCase(InputActionType.Button)]
[TestCase(InputActionType.PassThrough)]
public void Actions_PressOnly(InputActionType type)
{
var gamepad = InputSystem.AddDevice<Gamepad>();
InputSystem.settings.defaultButtonPressPoint = 0.5f;
InputSystem.settings.buttonReleaseThreshold = 0.75f; // Puts release point at 0.375.
var action = new InputAction(type:type, binding: "<Gamepad>/leftTrigger", interactions: "press(behavior=0)");
action.Enable();
using (var trace = new InputActionTrace(action))
{
Set(gamepad.leftTrigger, 0.35f);
Assert.That(trace, Started(action, control: gamepad.leftTrigger, value: 0.35f));
trace.Clear();
Set(gamepad.leftTrigger, 0.5f);
Assert.That(trace, Performed(action, control: gamepad.leftTrigger, value: 0.5f));
trace.Clear();
Set(gamepad.leftTrigger, 0.6f);
Assert.That(trace, Is.Empty);
Set(gamepad.leftTrigger, 0.4f);
Assert.That(trace, Is.Empty);
Set(gamepad.leftTrigger, 0.3f);
Assert.That(trace, Started(action, control: gamepad.leftTrigger, value: 0.3f));
trace.Clear();
Set(gamepad.leftTrigger, 0);
Assert.That(trace, Canceled(action, control: gamepad.leftTrigger, value: 0));
}
}
[Test]
[TestCase(InputActionType.Value)]
[TestCase(InputActionType.Button)]
[TestCase(InputActionType.PassThrough)]
public void Actions_RealeasOnly(InputActionType type)
{
var gamepad = InputSystem.AddDevice<Gamepad>();
InputSystem.settings.defaultButtonPressPoint = 0.5f;
InputSystem.settings.buttonReleaseThreshold = 0.75f; // Puts release point at 0.375.
var action = new InputAction(type:type, binding: "<Gamepad>/leftTrigger", interactions: "press(behavior=1)");
action.Enable();
using (var trace = new InputActionTrace(action))
{
Set(gamepad.leftTrigger, 0.35f);
Assert.That(trace, Started(action, control: gamepad.leftTrigger, value: 0.35f));
trace.Clear();
Set(gamepad.leftTrigger, 0.5f);
Assert.That(trace, Is.Empty);
trace.Clear();
Set(gamepad.leftTrigger, 0.6f);
Assert.That(trace, Is.Empty);
trace.Clear();
Set(gamepad.leftTrigger, 0.4f);
Assert.That(trace, Is.Empty);
trace.Clear();
Set(gamepad.leftTrigger, 0.3f);
Assert.That(trace,
Performed(action, control: gamepad.leftTrigger, value: 0.3f)
.AndThen(Canceled(action, control: gamepad.leftTrigger, value: 0)));
trace.Clear();
Set(gamepad.leftTrigger, 0.1f);
Assert.That(trace, Started(action, control: gamepad.leftTrigger, value: 0.1f));
trace.Clear();
Set(gamepad.leftTrigger, 0);
Assert.That(trace, Canceled(action, control: gamepad.leftTrigger, value: 0));
trace.Clear();
Set(gamepad.leftTrigger, 0.4f);
Set(gamepad.leftTrigger, 0.3f);//onlyRelease 不超过press-threshold只回落release是不会触发的
Assert.That(trace, Started(action, control: gamepad.leftTrigger, value: 0.4f));
trace.Clear();
}
}
[Test]
[TestCase(InputActionType.Value)]
[TestCase(InputActionType.Button)]
[TestCase(InputActionType.PassThrough)]
public void Actions_PressAndRelease(InputActionType type)
{
var gamepad = InputSystem.AddDevice<Gamepad>();
InputSystem.settings.defaultButtonPressPoint = 0.5f;
InputSystem.settings.buttonReleaseThreshold = 0.75f; // Puts release point at 0.375.
var action = new InputAction(type:type, binding: "<Gamepad>/leftTrigger", interactions: "press(behavior=2)");
action.Enable();
using (var trace = new InputActionTrace(action))
{
Set(gamepad.leftTrigger, 0.35f);
Assert.That(trace, Started(action, control: gamepad.leftTrigger, value: 0.35f));
trace.Clear();
Set(gamepad.leftTrigger, 0.5f);
Assert.That(trace, Performed(action, control: gamepad.leftTrigger, value: 0.5f));
trace.Clear();
Set(gamepad.leftTrigger, 0.6f);
Assert.That(trace, Is.Empty);
trace.Clear();
Set(gamepad.leftTrigger, 0.4f);
Assert.That(trace, Is.Empty);
trace.Clear();
Set(gamepad.leftTrigger, 0.3f);
Assert.That(trace,
Performed(action, control: gamepad.leftTrigger, value: 0.3f));
trace.Clear();
Set(gamepad.leftTrigger, 0);
Assert.That(trace, Is.Empty);
trace.Clear();
Set(gamepad.leftTrigger, 0.9f);
Assert.That(trace,
Started(action, control: gamepad.leftTrigger, value: 0.9f)
.AndThen(Performed(action, control: gamepad.leftTrigger, value: 0.9f)));
trace.Clear();
Set(gamepad.leftTrigger, 0);
Assert.That(trace,
Performed(action, control: gamepad.leftTrigger, value: 0f)
.AndThen(Canceled(action, control: gamepad.leftTrigger, value: 0f)));
trace.Clear();
Set(gamepad.leftTrigger, 0.4f);
Set(gamepad.leftTrigger, 0.3f);//press&release 不超过press-threshold只回落release是不会触发的
Assert.That(trace, Started(action, control: gamepad.leftTrigger, value: 0.4f));
trace.Clear();
}
}
}
}
UnityEvent方式注册回调关键逻辑
PlayerInput.InitializeActions()
UnityEvent方式注册回调的核心在于PlayerInput组件enable时进行InitializeActions
初始化操作
PlayerInputEditor
但对于上面ActionEvent的eventId怎么匹配上actionId,则要看PlayerInputEditor.OnInspectorGUI()
和OnActionAssetChange()
UnityEvent<T0>
上面action触发后,对应actionEvent调用Invoke,但此时真正的回调方法并没有注册,是在下面的InvokableCall中注册的,最后在InvokableCall.Invoke中执行最终的方法回调,处理输入处理。
InvokableCall<T1>
注册回调
从上面看,UnityAction方式远比原生C#事件复杂得多。(而且我也并没完全弄懂)