Unity3d_Rewired官方文档翻译:概念(四):LayoutManager、MapEnabler、CustomController

发布时间 2024-01-12 17:32:52作者: 尽头之外

仅翻译了官方文档中的Essentials(要点)、Concepts(概念)两部分,这是文档中最重要的部分,理解了这两部分的内容应该足以让你将Rewired运用到你的项目中,之后再去阅读文档的其他部分也能更容易理解。

斜体加下划线部分为添加的注解,非官方文档内容。若你发现有翻译、注解不正确的,请留言告知,以免再继续误导他人,感谢。

概念

Layout Manager

Layout Manager可用于管理Player中控制器映射的加载和卸载,以强制使用指定的布局。例如,在为 "左撇子 "输入方案更改控制器映射时,这可用于在Player中以特定布局加载特定控制器映射。这些设置将持续存在,并由根据您的规则分配给Player的新控制器继承。这将强制在Player中加载每个受管映射表类别的单一布局。Layout Manager无法管理Player中同时加载的同一映射表类别中的多个布局。

它不管理控制器映射的启用状态。它只管理控制器映射的加载和卸载。请参阅 Map Enabler 管理控制器地图的启用状态。通常,您会同时使用这两个系统。

如何运行

  1. 每个Player都有自己的Layout Manager,可用于管理该Player的控制器映射。
  2. Layout Manager包含一个规则集(Rule Set)列表。
  3. 每个规则集(Rule Set)都包含一个规则(Rule)列表,这些规则决定加载和/或卸载哪些控制器映射。
  4. 在Layout Manager上调用 "应用(Apply)"时(手动或发生某些情况时,如将控制器分配给Player),所有启用的规则集中的所有规则都会按顺序逐一处理。匹配控制器的控制器映射会根据需要卸载或加载,以符合每条规则的要求。

Tips

  • 可以禁用规则集(Rule Set),这样在调用 Apply 时就会忽略其中包含的规则(Rule)。
  • 每次在Layout Manager中调用 Apply 时,Player都会自动调用 MapEnabler.Apply,以确保根据需要启用或禁用新加载的控制器映射。
  • 只有被启用的规则集(Rule Set)中的一条或多条规则(Rule)匹配的控制器映射才会被管理。Player中的其他控制器映射将不受管理。
  • 使用规则集(Rule Set)的一种方法是将规则(Rule)拆分成许多单一用途的规则集(Rule Set),将所有规则集分配给Player,将其禁用,并有选择地启用规则集组的组合,以实现不同的模式。
  • 使用规则集的另一种方法是将许多规则堆叠成一个规则集,在一个规则集中定义整个模式,然后启用或调换规则集即可。
  • 如果某条规则指定某个控制器的映射应以特定的映射表类别和布局加载,但没有找到与这些设置相匹配的控制器映射,则将创建一个具有该映射表类别和布局的空白控制器映射,导致无法通过该控制器映射进行输入。例如,如果您在 "默认 "映射类别中为操纵杆创建了 "左手 "布局,那么您就应该为每一个要支持的操纵杆创建一个 "默认"、"左手 "控制器映射(控制器模板映射可用于覆盖其适用的所有控制器)。
  • 如果Layout Manager要管理相同映射表类别但不同布局的多个控制器映射,请勿将其分配给Player。如果控制器映射被管理,Layout Manager将只为每个控制器、每个映射表类别加载一个控制器映射。
  • Layout Manager与映射启用(Map Enabler)程序协同工作。建议您同时使用这两个系统来管理布局和控制器映射启用状态。
  • Layout Manager必须启用,否则将无法管理布局。Layout Manager可在运行时通过脚本启用或禁用,也可在 Rewired Editor - Players 页面启动时启用或禁用。
  • Layout Manager中的 "从用户数据存储"(Load From User Data Store)设置(在Rewired Editor中设置或通过脚本设置)决定加载的控制器映射是否应先搜索用户数据存储,然后再从Input Manager默认值中加载。这允许Layout Manager在加载控制器映射时加载由 Control Mapper 或其他自定义控制映射系统创建的已保存用户映射。请注意,UserDataStore 实现必须实现 Rewired.Interfaces.IControllerMapStore 接口,这样才能发挥作用。
  • 在Layout Manager中更改规则集或规则后,应调用 LayoutManager.Apply 将这些更改提交到Player的控制器映射中。
  • 每次在Layout Manager中调用 Apply 时,Player都会自动调用 MapEnabler.Apply,以确保新加载的控制器映射按要求启用或禁用。(反之则不会)。

通过脚本访问

player.controllers.maps.layoutManager

规则集(Rule Set)

规则集是规则的集合。

创建规则集

规则集可以在 Rewired Editor中创建,也可以在运行时通过脚本创建。

在 Rewired Editor中创建规则集

规则集可以在Rewired Editor - Layout Manager Rules页面中创建。创建规则集后,必须将其分配给Player,否则将无法使用。

另外,也可以通过脚本加载在Rewired Editor中创建的规则集,并将其添加到Player的 "Layout Manager "中,方法如下:

// Load an instance of the Rule Set
var ruleSet = ReInput.mapping.GetControllerMapLayoutManagerRuleSetInstance(ruleSetId);

// Add the Rule Set to the Player's Layout Manager
player.controllers.maps.layoutManager.ruleSets.Add(ruleSet);

// Apply the changes to the Player's Controller Maps
player.controllers.maps.layoutManager.Apply(); 

在 Rewired Editor中创建的规则集在初始化时按Player实例化。它们不会在Player之间共享。可以在运行时修改一个Player的规则集,但该修改不会反映在其他Player拥有的规则集中。

通过脚本创建规则集

规则集可在运行时创建和分配。

本示例显示创建了两个Layout Manager规则集,可用于在 "GameplayShared"、"Airplane "和 "Infantry "映射表类别中的操纵杆 "默认 "布局和 "Leftie "布局之间切换。在本示例中,其他控制器的所有其他控制器映射均未受管理,也不会受到Layout Manager的影响。

private ControllerMapLayoutManager.RuleSet layoutManager_joysticks_default = new ControllerMapLayoutManager.RuleSet() {

    // Enable the Rule Set. This is unnecessary since Rule Sets start enabled by default.
    enabled = true,

    // Create a tag if you want to find this Rule Set via scripting in the list
    tag = "default",

    // Create the list of Rules for this Rule Set
    rules = {

        // Load Default Layout for GameplayShared, Airplane, and Infantry categories in all Joysticks
        new ControllerMapLayoutManager.Rule() {

            // Create the Controller Set Selector to determine which Controller(s) this applies to
            controllerSetSelector = ControllerSetSelector.SelectControllerType(ControllerType.Joystick),

            // Set which Map Catetories of the Controller Maps to be loaded
            categoryNames = new[] { "GameplayShared", "Airplane", "Infantry" },

            // Set the Layout of the Controller Maps to be loaded
            layoutName = "Default"
        }
    }
};

private ControllerMapLayoutManager.RuleSet layoutManager_joysticks_leftie = new ControllerMapLayoutManager.RuleSet() {

    tag = "leftie",
    rules = {

        // Load Leftie Layout for GameplayShared, Airplane, and Infantry categories in all Joysticks
        new ControllerMapLayoutManager.Rule() {
            controllerSetSelector = ControllerSetSelector.SelectControllerType(ControllerType.Joystick),
            categoryNames = new[] { "GameplayShared", "Airplane", "Infantry" },
            layoutName = "Leftie"
        }
    }
};

启用和禁用规则集

可以启用和禁用规则集,以控制在调用 ControllerMapLayoutManager.Apply 或评估规则时是否评估规则集。

ControllerMapLayoutManager.ruleSets 包含一个 List<ControllerMapLayoutManager.RuleSet>,可以像其他通用列表一样进行搜索和修改。找到要更改启用状态的规则集,更改状态,然后调用 ControllerMapLayoutManager.Apply 评估规则并将更改应用到Player的控制器映射。

// Disable all Rule Sets
foreach(var ruleSet in player.controllers.maps.layoutManager.ruleSets) {
    ruleSet.enabled = false;
}

// Enable the Rule Set with the tag "leftie"
player.controllers.maps.layoutManager.ruleSets.Find(item => item.tag == "leftie").enabled = true;

// Apply the changes to the Player's Controller Maps
player.controllers.maps.layoutManager.Apply();

规则(Rule)

规则是对Player中所有匹配的控制器映射进行评估和应用的单独命令,用于确定应加载或删除哪些控制器映射。规则集中的每条规则都按顺序进行评估。

规则包含 3 条信息:

  • 控制器选择器(Controller Selector) - 确定该规则适用于哪些控制器。该规则只管理特定控制器的控制器映射。
  • 类别(Categories) - 确定该规则管理哪些映射表类别。
  • 布局(Layout) - 确定要加载/维持的控制器映射的布局。

当Layout Manager评估规则时,对于指定的控制器,它将卸载与规则中指定的类别相匹配但与规则中指定的布局不匹配的映射表类别中的任何控制器映射。然后,它将在指定布局中加载指定映射表类别中的控制器映射。

规则可以在Rewired Editor - Layout Manager Rules页面中创建,也可以在运行时通过脚本创建。

常见问题

问:能否在运行时使用 ID 而不是标签选择规则集或规则?

答:Id 不能用于在运行时选择Player中的规则集或规则。规则集可以完全在代码中定义,也可以在运行时复制,在这种情况下,它们不会有一个与Input Manager中存在的其他规则集定义相对应的 id。

规则集可导出的 Id 常量仅用于将规则集实例化(从Input Manager中加载)到Player中。这样做并不常见,因为大多数情况下,你会在Rewired Editor中将这些规则集分配给Player,然后在应用程序启动时加载这些规则集。应用程序启动后,每个Player的规则集都会被实例化,此后它们与父规则集定义不再有任何联系。

API 参考:

Map Enabler

Map Enabler 可对Player中的控制器映射强制执行持久启用状态。这可用于在Player中启用或禁用特定控制器映射,例如在更改需要不同输入方案的游戏模式时。这些设置将持续存在,并由根据您的规则分配给玩家的新控制器继承。在添加新控制器、加载控制器映射等情况下,启用状态将被同步。

如何运行

  1. 每个Player都有自己的 Map Enabler,可用于管理该Player的控制器映射。
  2. Map Enabler包含一个规则集列表。
  3. 每个规则集包含一个规则列表,这些规则决定启用或禁用哪些控制器映射。
  4. 在Map Enabler上调用 "Apply"时(手动或发生某些情况时,如将控制器分配给Player或加载控制器映射时),所有启用的规则集中的所有规则都会按顺序逐一处理。匹配控制器的控制器映射会根据每条规则被启用或禁用。

Tips

  • 可以禁用规则集,以便在调用 "Apply"时忽略其中包含的规则。
  • 只有被启用的规则集中的一条或多条规则匹配的控制器映射才会被管理。Player中的其他控制器映射将不受管理。
  • 由Map Enabler管理的控制器映射必须已经加载到Player中。Map Enabler不会加载或卸载任何控制器映射。它只会更改已加载控制器映射或在Player中加载控制器映射时的启用状态。
  • 使用规则集的一种方法是将规则拆分成许多单一用途的规则集,将所有规则集分配给Player,启动时禁用它们,然后有选择地启用规则集组的组合,以实现不同的模式。
  • 使用规则集的另一种方法是将许多规则堆叠成一个规则集,在一个规则集中定义整个模式,然后启用或更换规则集即可。
  • 您不应手动设置由Map Enabler管理的控制器映射的启用状态,而应通过更改规则集或规则来更改启用状态设置,并将这些更改应用到Map Enabler。
  • Map Enabler与Layout Manager配合使用。建议同时使用这两个系统来管理布局和控制器映射启用状态。
  • Map Enabler必须启用,否则无法管理控制器映射。Map Enabler可以在运行时通过脚本启用或禁用,也可以在 "Rewired Editor - Playes"页面设置启动时启用或禁用。
  • 在Map Enabler中更改规则集或规则后,应调用 MapEnabler.Apply(应用)将这些更改提交到Player的控制器映射中。
  • 每次在Layout Manager中调用 Apply 时,Player都会自动调用 MapEnabler.Apply,以确保根据需要启用或禁用新加载的控制器映射。

通过脚本访问

player.controllers.maps.mapEnabler

规则集(Rule Set)

规则集是规则的集合。

创建规则集

规则集可以在 Rewired Editor中创建,也可以在运行时通过脚本创建。

在 Rewired Editor中创建规则集

规则集可以在Rewired Editor - Map Enabler Rules页面中创建。创建规则集后,必须将其分配给Player,否则将无法使用。

另外,也可以通过脚本加载在Rewired Editor中创建的规则集,并将其添加到Player的Map Enabler中,方法如下:

// Create an instance of a Rule Set defined in the Rewired Editor
var ruleSet = ReInput.mapping.GetControllerMapEnablerRuleSetInstance(ruleSetId);

// Add the Rule Set to the Player's Map Enabler
player.controllers.maps.mapEnabler.ruleSets.Add(ruleSet);

// Apply the changes to the Player's Controller Maps
player.controllers.maps.mapEnabler.Apply(); 

在 Rewired Editor中创建的规则集在初始化时按Player实例化。它们不会在Player之间共享。可以在运行时修改一个Player的规则集,但该修改不会反映在其他Player拥有的规则集中。

通过脚本创建规则集

规则集可在运行时创建和分配。

本例显示了创建两个规则集。

// Exclusively enables Controller Maps in the "GameplayShared" and "Infantry" categories for all Controllers
private ControllerMapEnabler.RuleSet mapEnabler_default = new ControllerMapEnabler.RuleSet() {

    // Enable the Rule Set. This is unnecessary since Rule Sets start enabled by default.
    enabled = true,

    // Create a tag if you want to find this Rule Set via scripting in the list
    tag = "default",

    // Create the list of Rules for this Rule Set
    rules = {

        // First disable all Controller Maps for all Controllers
        new ControllerMapEnabler.Rule() {
            enable = false,
            controllerSetSelector = ControllerSetSelector.SelectAll()
        },

        // Enable Controller Maps in the "GameplayShared" and "Infantry" categories in all Layouts for all Controllers
        new ControllerMapEnabler.Rule() {
            enable = true,
            controllerSetSelector = ControllerSetSelector.SelectAll(),
            categoryNames = new[] { "GameplayShared", "Infantry" }
        }
    }
};

// Exclusively enables Controller Maps in the "GameplayShared" category in the "Leftie" Layout for Joysticks only
private ControllerMapEnabler.RuleSet mapEnabler_default_leftieJoystick = new ControllerMapEnabler.RuleSet() {

    tag = "leftie_joystick",
    rules = {

        // First disable all Controller Maps for all Joysticks
        new ControllerMapEnabler.Rule() {
            enable = false,
            controllerSetSelector = ControllerSetSelector.SelectControllerType(ControllerType.Joystick)
        },

        // Enable Controller Maps in the "GameplayShared" category in the "Leftie" Layout for all Joysticks
        new ControllerMapEnabler.Rule() {
            enable = true,
            controllerSetSelector = ControllerSetSelector.SelectControllerType(ControllerType.Joystick),
            categoryName = "GameplayShared",
            layoutName = "Leftie"
        }
    }
};

启用和禁用规则集

可以启用和禁用规则集,以控制在调用 ControllerMapEnabler.Apply 或评估规则时是否评估规则集。

ControllerMapEnabler.ruleSets 包含一个 List<ControllerMapEnabler.RuleSet>,可以像其他通用列表一样进行搜索和修改。找到要更改启用状态的规则集,更改状态,然后调用 ControllerMapEnabler.Apply 评估规则并将更改应用到播放器的控制器映射。

// Disable all Rule Sets
foreach(var ruleSet in player.controllers.maps.mapEnabler.ruleSets) {
    ruleSet.enabled = false;
}

// Enable the Rule Set with the tag "UI"
player.controllers.maps.mapEnabler.ruleSets.Find(item => item.tag == "UI").enabled = true;

// Apply the changes to the Player's Controller Maps
player.controllers.maps.mapEnabler.Apply();  

规则(Rule)

规则是对Player中所有匹配的控制器映射进行评估和应用的单独命令,用于确定应加载或删除哪些控制器映射。规则集中的每条规则都按顺序进行评估。

规则包含 3 条信息:

  • 控制器选择器(Controller Selector) - 确定该规则适用于哪些控制器。该规则只管理特定控制器的控制器映射。
  • 类别(Categories) - 确定该规则管理哪些映射表类别。
  • 布局(Layout) - 确定要加载/维持的控制器映射的布局。

当Layout Manager评估规则时,对于指定的控制器,它将卸载与规则中指定的类别相匹配但与规则中指定的布局不匹配的映射表类别中的任何控制器映射。然后,它将在指定布局中加载指定映射表类别中的控制器映射。

规则可以在Rewired Editor - Map Enabler Rules页面中创建,也可以在运行时通过脚本创建。

常见问题

问:能否在运行时使用 ID 而不是标签选择规则集或规则?

答:Id 不能用于在运行时选择Player中的规则集或规则。规则集可以完全在代码中定义,也可以在运行时复制,在这种情况下,它们不会有一个与Input Manager中存在的其他规则集定义相对应的 id。

规则集可导出的 Id 常量仅用于将规则集实例化(从Input Manager中加载)到Player中。这样做并不常见,因为大多数情况下,你会在Rewired Editor中将这些规则集分配给Player,然后在应用程序启动时加载这些规则集。应用程序启动后,每个Player的规则集都会被实例化,此后它们与父规则集定义不再有任何联系。

API 参考:

Custom Controller

Custom Controller是一种可以自定义的虚拟控制器,可以根据需要添加任意数量的轴和按钮。Custom Controller允许你设置自己的轴和按钮输入源。这可以是任何类型的物理或虚拟控制器。任何可以返回浮点或布尔值的东西都可以用作元素源。自定义控制器可用于屏幕触摸控制器等。(请参阅 Rewired/Examples 文件夹中的示例)。

重要提示:Custom Controller不是用来为 Rewired 无法自动识别和映射的控制器创建新的 HID 操纵杆定义。它们是虚拟控制器,只知道由脚本输入的轴和按钮数据。它们完全独立于操纵杆系统,不会自动分配,也不会生成连接或断开事件等。如果您打算使用Custom Controller来为 Rewired 可以检测但无法识别并自动映射的控制器添加支持,请不要这样做,因为这是一个错误的工具。相反,你需要为此创建一个新的控制器定义,或者为未知控制器定义一个操纵杆映射。不过,Custom Controller可用于支持不显示为手柄的设备,例如需要使用 SDK 的特殊控制器(大多数 VR 控制器)。

创建/编辑自定义控制器

您可以在 Rewired Editor中创建和编辑Custom Controller。

为玩家分配自定义控制器

您可以在Rewired Editor中分配开始使用的Custom Controller。

Custom Controller与操纵杆不同,是为每个Player实例化的。添加Custom Controller时,控制器将在游戏开始时创建并分配给Player。如果为多个Player添加同一个控制器,Custom Controller将为每个Player实例化,因此为每个Player设置一个标签有助于区分控制器。

您还可以在运行时通过脚本分配和取消分配Custom Controller。如果要检测是否存在某种类型的非标准控制器(例如某些 VR 控制器),并将其自动分配给Player,这将非常有用。Custom Controller的分配类似于为Player分配操纵杆。

通过脚本实例化Custom Controller

通常,Rewired 会在初始化时实例化分配给每个Player的控制器。如果需要在运行时实例化新的Custom Controller对象,可以使用 ReInput.controllers 中的 CreateCustomController 方法,通过脚本从Input Manager中的预定义定义中实例化这些对象。

更新元素值

元素(坐标轴和按钮)值必须在每一帧的Custom Controller上更新。有两种不同的方法可以做到这一点:

  1. 注册 ReInput.InputSourceUpdateEvent 事件,然后当该事件触发时,通过 CustomController.SetAxisValue 和 CustomController.SetButtonValue 直接将新值推送到元素中。

  2. 使用 CustomController.SetAxisUpdateCallback 和 SetButtonUpdateCallback 在 CustomController 中设置回调函数。这些回调函数将在输入更新步骤中调用,您可以在此时将最新值推送到元素中。

这两种方法的示例可在 Rewired/Examples 文件夹中的触摸控制器示例中查看。

注意:InputSourceUpdateEvent 和回调在每一帧中都可能被调用多次。每次更新输入时都会调用它们,这取决于输入管理器中的更新循环设置。如果您在多个循环中更新输入,例如Update和FixedUpdate,则每个更新循环都将调用一次事件和回调。

案例