Unity3d_Rewired官方文档翻译:概念(一):InputManager、Players、Actions
仅翻译了官方文档中的Essentials(要点)、Concepts(概念)两部分,这是文档中最重要的部分,理解了这两部分的内容应该足以让你将Rewired运用到你的项目中,之后再去阅读文档的其他部分也能更容易理解。
斜体加下划线部分为添加的注解,非官方文档内容。若你发现有翻译、注解不正确的,请留言告知,以免再继续误导他人,感谢。
概念
Input Manager
Input Manger的职责是存储所有输入配置数据,并使其可以在运行时被获取。你必须保证场景中存在一个Input Manager,否则Rewired输入将不可用。
重要
- 场景中必须有且只能有一个Input Manager存在【可以存在多个,但只能有一个处于激活状态】
- 不要在运行时激活或者禁用Input Manager
创建一个Input Manager
通过菜单界面创建Input Manager: Window -> Rewired -> Create -> Input Manager
- Input Manger(Prefab) - 将Input Manager作为预制体资源创建到Project视图下。建议使用此选项。(不要将这个预制体存储到Rewired文件夹下的任何位置。如果你需要删除并重装Rewired,这将导致数据丢失。)
- Input Manger(in scene) - 将在当前场景中创建一个Input Manager。(不建议)
强烈建议你创建Input Manager预制体,然后使用Rewired Initializer去实例化。
编辑输入
你可以通过Rewired Editor创建并编辑输入。在Hierarchy窗口选中Input Manger,然后在Inspector窗口中点击“Laun Rewired Editor”打开编辑器。你可以通过编辑器修改存储在选中的Input Manager中的输入配置数据。
数据如何存储
不同于其他大多数输入系统,Rewired不将整个工程的输入配置数据(maps,Actions等等)保存在一个单独的位置。相反,这些数据都被存储在Input Manager这个游戏对象上。这意味着只要你想,你可以为每一个不同的场景创建完全不同的输入设置,因为每一个Input Manager 对象是完全独立的。这也意味着输入设置不是全局可用的,尤其是编辑器脚本中,或者当Rewired还未初始化时。
运行时,当前的输入配置数据是从当前场景中已激活的Input Manager中加载而来。你可以在编辑器中禁用一个Input Manager,然后激活另一个,以此来切换不同的输入配置(确保只有一个Input Manager处于激活状态,或者其他所有Input Manager都被禁用)。可以将Input Manager制作成预制体,然后在每一个场景中都实例化它,以此来共享输入配置。
OnDestroy
当激活的Input Manager被销毁时,它将完全重置 Rewired,从而使Player、Controller等对象引用失效,控制器分配丢失等。脚本中对这些对象的所有引用都将失效。如果要销毁Input Manager,你必须注意这一点,尤其是“Don't Destroy on Load”未勾选,并进行场景加载时。
注意:这也会影响编辑器中脚本的运行时重新编译。当运行时脚本进行重新编译,Rewired会重置。此时,Rewired 对象的缓存引用将失效,因此如果不考虑这一点,脚本可能会开始抛出空引用异常。如果运行时脚本重新编译是你工作流程的一部分,请参阅此链接了解更多信息
Input Manager检视窗口
Don't Destroy On Load | 勾选后,加载场景是将不会销毁Input Manager |
---|---|
Data Files | 对ControllerDataFiles对象的引用。该对象包含所有受支持操纵杆(joysticks)和模板的列表,是 Rewired 正常运行所必需的。如果你想要自定义自己的受支持的控制器,您可以将其链接到您已修改的 ControllerDataFiles 的单独副本。 |
Run in Editor Mode | 使Rewired可以在编辑器模式下运行 |
Debug Information | 在运行时显示Player、Controller、Controller Map等大量有用信息。可将系统中的大多数运行时对象可视化。 |
在游戏中使用Input Manager
当游戏最终打包时,初始场景中应该存在一个Input Manager(或者Rewired Initializer),并确保Don't Destroy On Load已勾选,使Rewired可以贯穿整个游戏周期。
测试单个场景
Rewired Initializer
建议你在每一个场景中都创建一个Rewired Initializer。Rewired Initializer会在Awake时根据需要生成Input Manager,但是当加载新场景是它不会生成多个Input Manager,以避免产生错误。这样,您就可以在每个场景中使用相同的 Rewired 输入管理器,并能在编辑器中单独测试这些场景或在游戏过程中加载它们。
通过菜单创建Rewired Initializer:Window -> Rewired -> Create -> Initializer
创建Rewired Initializer后,你需要为其赋予一个Input Manager预制体。
替代方法
你可以创建一个Input Manager的预制体,然后在每一个场景中放置一个它的实例,并不勾选Don't Destroy On Load。当加载新场景时,已加载场景里的Input Manager将自动销毁自己,原有的Input Manager不变并继续处理输入,而不会导致错误。
不建议使用该方法,因为它容易导致错误。每一个场景中的Input Manager都可以直接编辑,这可能导致不同场景中不同预制件实例的配置存在差异。这是寻求帮助中经常遇到的情况。建议使用Rewired Initializer以避免任何潜在错误。
注意:如果你创建了一个Input Manager的预制体,请总是通过预制体打开Rewired Editor编辑器,而不是场景中的实例,否则这些修改将只会应用到实例。如果您不小心对场景中的实例进行了更改,您可以将更改应用到预制件中,这样一切都会保持同步。
编辑器下运行
使 Rewired 在 Play 模式之外的编辑器中运行。当不在播放模式下时,它可用于在 Unity 编辑器中处理输入,以实现各种目的。
按下 "Input Manager"Inspector中的 "Run in Edit Mode"按钮可在编辑模式下启动Rewired。请注意,该按钮的作用是切换,因此如果将其启用,则每次打开场景或退出播放模式时,Rewired都会立即开始在编辑模式下运行。
重要信息
- 在Play和Editor模式间切换时,Rewired将会重置,在不同模式间,对象的状态不会保持。例如,您对任何 Rewired 对象所做的操纵杆(Joystick)分配或其他运行时更改都不会持久存在。
- 你能不在Rewired运行时编辑Input Manager的配置数据
- 并非所有编辑器平台和输入源都完全支持在 "编辑 "模式下运行。某些类型的输入设备在某些编辑器平台使用某些输入源进行输入时可能无法工作。
- 如果需要在Scene视图有焦点时进行输入,请启用 "Allow Input in Editor Scene Views"选项。
- 在编辑模式下,Rewired 不会在标准的 Unity Update、FixedUpdate 和 OnGUI 循环中更新,因为在Play模式之外,Unity 不会每帧都执行这些循环。因此,在“编辑”模式下,Rewired 只会在特殊的编辑器更新循环中运行。这有一些重要的副作用:
- 在处理输入时,无法使用 Unity 的 Time 类。例如,如果您需要将一个值乘以 Time.deltaTime,它将始终返回 0。相反,您必须使用 ReInput.time.unscaledDeltaTime。
- 在编写脚本时,建议使用输入事件方法获取输入,而不是在 Update 中进行轮询,因为 Unity 不会每帧都执行 Update 循环。
- 在 "编辑 "模式下,Rewired 永远不会在 "FixedUpdate"模式下运行。如果使用输入事件,只能订阅“Update”循环中的事件。
- 如果要轮询输入,请通过 EditorApplication.update 回调进行轮询。
- Mouse.screenPosition 和相关属性在编辑模式下不起作用。
- 要从编辑器脚本开始以编辑模式运行,请将 InputManager.runInEditMode 属性设置为 true。
Players
Rewired是采用以Player为中心的输入系统。这意味着,通常情况下所有输入都由Player处理而不是控制器。您只需调用 player.GetAxis、player.GetButton 等,或使用 player.AddInputEventDelegate 注册接收输入事件,即可访问所有输入,而无需考虑输入源。
例如,您可能需要响应来自键盘、鼠标、任意数量的操纵杆和任意数量的自定义控制器的输入。只需将控制器和相应的映射分配给Player,然后直接从Player获取输入即可。从Player接收到的输入是所有分配控制器接收到的输入的组合。此外,游戏手柄(joysticks)可以(可选)在连接和断开时智能地自动分配给玩家,因此您不必担心每个玩家拥有哪些控制器。相反,您只需为你需要的特定Action获取输入,Rewired 就会处理剩下的工作。
将Player视为 "控制器容器 "可能会有所帮助。换句话说,Player可以包含任意数量的控制器和控制器映射。当你从Player获取输入时,实际上是从Player拥有的、启用了 "Action"->"元素 "映射的任何控制器获取输入。【本文出现的所有“元素”通常是指控制器上的实体按键或摇杆】
创建/编辑Players
Player是由场景中的Input Manager在运行时创建的。您必须在Rewired Editor中定义 "Player",才能在运行时创建它们。
访问Players
ReInput.players 属性中的方法可通过 id 或名称访问Player,或获取所有Player的列表。建议您在 Awake 中存储Player的引用,并在游戏过程中保持该引用。
System Player
System player是用于处理保存、载入等系统操作的可选项。你可以为System player分配控制器和控制器映射,就像为其他Player分配控制器和控制器映射一样。操纵杆不会自动分配给System player,但可以通过脚本手动分配。
获取输入
在Rewired中,你通常从Player而非控制器本身获得输入。
Player与控制器映射
控制器映射是控制器元素到Actions的关联。由于 Rewired 是一个以Player为中心的输入系统,因此控制器映射并不存储在控制器中,而是存储在Player中。这样做的好处是,您可以根据需要在多个 "Player "之间共享控制器,同时每个 "Player "都能保持自己独立的 "Action "映射集。
Player 类包含许多用于获取、添加和删除所有类型控制器映射的方法(通过 Player.controllers.maps 对象访问这些方法)。此外,赋值冲突检查和保存/加载映射也是通过Player类处理的。
即使为Player分配了控制器,如果没有分配映射,也无法进行输入。您应在Rewired Editor中为每个Player定义操纵杆、键盘和鼠标的起始映射。您也可以通过Player类,在运行时加载和分配映射。
Player与控制器
Player本质上是控制器和控制器映射的容器。Player中包含的控制器映射提供了一种将Actions与控制器元素(按钮、键、轴等)关联的方法。Player处理不同类型控制器的方式略有不同。
Rewired 目前有 4 种控制器类:
- Joystick(非键盘或鼠标)
- Keyboard
- Mouse
- Custom Controller
Joysticks
在Player返回操纵杆的输入之前,必须先将该操纵杆分配给Player。该操纵杆必须添加到Player的操纵杆列表中,然后才能接收来自该设备的输入。如果需要,一个操纵杆可以分配给多个Player并共享(这种情况很少见)。
默认情况下,Rewired 的操纵杆自动分配系统已在Input Manager中启用。这将确保每个Player在连接到系统时都能根据“Rewired Editor - Setting ”页面中的规则分配到一个操纵杆。如果您有自动分配系统选项无法满足的特殊需求,可以禁用该系统。
要在Player中返回操纵杆的输入,以下条件必须全部满足:
- 操纵杆必须分配给Player。
- Player必须至少有一个启用的操纵杆映射(Joystick Map)适用于该操纵杆。
- 操纵杆映射必须将至少一个操纵杆元素绑定到一个Action上。
请勿混淆:Player在Input Manager中“拥有操纵杆映射”这一事实与分配给该Player的操纵杆并不相同。“操纵杆映射”完全独立于“操纵杆分配”,不会影响操纵杆自动分配系统为Player分配的操纵杆(如果有的话)。操纵杆分配包括向Player添加操纵杆类对象(Joystick)。一旦分配了操纵杆,Rewired 将在Player中加载该特定操纵杆的操纵杆映射(如果在 Rewired Editor中创建了一个或多个适用的操纵杆映射并将其分配给了Player的话),然后操纵杆映射将执行Action到该操纵杆上的元素的映射。如果已将操纵杆分配给Player,但未找到匹配的操纵杆映射,则该操纵杆不会在该Player中提供任何输入。
Keyboard
在Rewired中,键盘是一个共享控制器。与操纵杆类似,键盘也必须分配给Player,然后才能返回任何输入。这可以在 "Input Manager - Player "页面进行设置,也可以通过脚本使用 player.controllers.hasKeyboard 属性进行设置。默认情况下,除非在Input Manager中禁用,否则键盘会在启动时分配给所有Player。
与操纵杆一样,只有当Player拥有至少一个将某些Actions与按键关联起来的键盘映射(Keyboard Map)时,键盘才会在Player中返回输入。
Mouse
与操纵杆类似,鼠标也必须分配给Player后才能返回任何输入。这可以在 "Input Manager - Player "页面中进行设置,也可以通过脚本使用 player.controllers.hasMouse 属性进行设置。如果需要,鼠标可由多个Player共享。
与操纵杆和键盘一样,只有当一个Player中至少有一个鼠标映射(Mouse Map)将某些Actions与鼠标按钮和轴相关联时,鼠标才会在该Player中返回输入。
Custom Controller
自定义控制器在处理方式上与操纵杆非常相似,但它们与系统的连接永远不会断开,并且始终可用。同样的规则也适用:自定义控制器必须分配给一个Player,并且有一个或多个有效的自定义控制器映射,才能返回任何输入值。
Actions
一个Action可以代表任何类型的事件,这些事件都是输入的结果。一般来说,Action是根据其在游戏中代表的动作来命名的,例如水平移动、跳跃、射击、装弹、更换武器、出拳等。Action也能代表系统操作,例如:菜单、保存、加载、取消、后退、前进等。你如何命名和使用Action完全取决于你的游戏需要。
获取输入
在Rewired中,Action通常是获取输入的方式。与从特定控制器上的特定按钮获取输入(如果用户切换控制器,按钮可能会发生变化)不同,你可以通过Player类从Action获取输入。例如
private Rewired.Player player;
void Awake() {
player = Rewired.ReInput.players.GetPlayer(0); // get the player by id
}
void Update() {
player.GetButtonDown("Fire");
}
这样,你就不必担心玩家使用的控制器类型或数量,只需根据 "Action "获取输入即可。
您也可以根据操作 ID 获取输入。Action ID 显示在Rewired Editor的 "Action"下。你可以导出Action ID 常量列表,这样就可以在编码时使用IDE的自动补全功能查找Action ID,非常方便。按 id 查找Action比按名称查找要快得多,因此推荐使用这种方法。
此外,您还可以选择使用输入事件,而不是如上例所示轮询输入。
按键与轴
Action 既不是按钮,也不是轴。Action是一个虚拟元素,可以作为按钮(布尔值)和轴(浮点值)进行查询。所有Player的按钮(Button)和坐标轴(Axis)方法都能正常工作,无论该Action的值由哪种类型或多少个底层元素构成。
查询Action的按钮值时,如果绑定到该Action的底层元素是物理轴或虚拟轴,则该Action的Input Behavior Button Dead Zone将用于确定按钮状态变化发生在哪个轴值上。此外,底层轴只有在轴值为正数时才会触发 Button 状态改变。如果轴值为负数,则按钮状态将忽略该值,而形成负按钮状态。
查询Action的轴值时,如果绑定到Action的底层元素是物理或虚拟按钮,则会使用Action的Input Behavior Digital Axis Settings来确定如何计算轴值。
创建、编辑Action
您必须在Rewired Editor中创建和编辑Action。
Action类别
通过使用 "Action Categories",可以将操作归类到不同的列表中。
Action Categories仅用于在Rewired Editor中或在用户界面(例如控件重映射界面)中显示的动作列表中进行分类组织。它们对Player中的控件映射没有任何影响,也不会以任何方式影响输入。
Rewired的目的和职责
通常,Rewired的Action系统会被以一种非预期的方式用作单独的游戏状态管理系统的组成部分或替代物。这不是Rewired的设计初衷,也不是它的使用目的。
- Rewired 的唯一目的是读取用户输入。
- Rewired 中的所有 "Action "实际上都是 "输入操作",除了用于获取有关用户意图的信息外,不得用于任何其他目的。它们不应与游戏状态或操作相混淆或用作游戏状态或操作。
- Action "跳跃 "并不表示 "玩家正在跳跃",而是表示 "用户想要跳跃"。
- 游戏应实现权限和状态管理系统,对用户输入进行评估,然后改变状态。在这之后,发生的事情就不属于输入系统的职责范围了。