Unity3d_Rewired官方文档翻译:概念(三):ControllerTemplate、MapCategories、Layouts

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

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

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

概念

Controller Templates

Controller Template代表一种通用的控制器布局,适用于所有兼容的控制器,为这些控制器提供了一个通用的工作界面。为控制器模板创建映射后,任何实现该模板的控制器都将自动继承该映射,而无需专门为该控制器创建映射。例如,Rewired 附带一个游戏手柄模板。当你为该游戏手柄模板创建映射时,你无需再为本页所列的任何游戏手柄创建单独的映射,因为游戏手柄模板已涵盖了所有这些手柄。这样就能更快地为各种控制器创建预定义控制器映射。此外,如果将来模板中添加了更多控制器,您已创建的映射也将适用于这些新控制器。

如果您已为Controller Template创建了映射,但仍想为Controller Template所涵盖的特定控制器创建映射,只需为特定控制器创建映射,它就会覆盖模板中定义的映射。

Controller Template还可以在运行时通过脚本访问,以实现各种目的。

有关哪些控制器与哪些控制器模板兼容的信息,请参阅Supported Controllers

游戏手柄模板

通过游戏手柄模板,您可以制作一张涵盖all of the gamepads列出的所有游戏手柄的映射。

注意:请不要误认为游戏手柄模板适用于现有的所有游戏手柄。该模板仅适用于具有控制器定义的可识别游戏手柄。要创建一个能自动识别和映射所有游戏手柄、方向盘、飞行控制器或任何其他类型设备的系统是不可能的,因为设备提供的 USB 或 HID 数据中根本不存在这样做所需的信息。只有具有控制器定义的设备才能使用模板系统。

游戏手柄模板的元素名称是通用的,因为并非所有游戏手柄的所有元素都使用相同的名称。请注意,尽管模板元素名称是通用的,但在游戏过程中,Rewired 会使用控制器元素的实际名称,而不是通用名称。例如,XBox 360 控制器的绿色按钮将返回 "A",而不是 "Action Bottom Row 1"。

为避免在映射游戏手柄模板时出现混淆,请参考以下元素命名指南:

脚本参考:

方向盘模板:

赛车方向盘模板可让您制作一张涵盖all of the wheels listed的所有方向盘的映射。由于没有像游戏手柄那样被普遍接受的通用赛车方向盘布局,因此不存在直观显示元素的图表。元素名称应足够简单明了,以便理解它们在设备上的映射关系。

脚本参考:

飞行器模板:

飞行操纵杆模板允许您制作一张涵盖all of the flight yokes listed的所有飞行操纵杆的映射。由于没有像游戏手柄那样公认的通用飞行操纵杆布局,因此不存在直观显示元素的图表。元素名称应足够简单明了,以便理解它们在设备上的映射关系。

脚本参考:

飞行踏板模板:

飞行踏板模板允许您绘制一张涵盖all of the flight pedals listed的所有飞行踏板的映射。由于没有像游戏手柄那样公认的通用飞行踏板布局,因此不存在直观显示元素的图表。元素名称应足够简单明了,以便理解它们在设备上的映射关系。

脚本参考:

6 DoF 控制器模板

6 DoF 控制器【6自由度控制器,常见于VR设备中】模板允许您制作一张涵盖all of the 6 DoF controllers listed的所有 6 DoF 控制器的映射。

6 DoF 控制器模板的主要元素是可用于检索 3D 方向和旋转输入的 6 个轴:

  • 水平(Position X)
  • 垂直(Position Y)
  • 前进/后退(Position Z)
  • 旋转 X
  • 旋转 Y
  • 旋转 Z

由于没有像游戏手柄那样公认的通用 6 DoF 控制器布局,因此不存在直观显示元素的图表。元素名称应足够简单明了,以便理解它们在设备上的映射关系。

脚本参考:

脚本

一般来说,你只需在Rewired Editor中为控制器模板定义控制器映射,当用户连接到兼容的控制器时,它就能正常工作了。你不需要编写任何额外的代码来使控制器模板工作,甚至不需要知道它们的存在,而只需在Rewired Editor中创建控制器映射。不过,在某些特殊情况下,通过脚本在运行时访问控制器模板可能会很有用。如果预计不需要在代码中直接使用控制器模板,可以跳过本节内容。

控制器模板可在运行时通过脚本访问,以实现各种目的,例如显示控制器的通用控制器模板用户界面,或直接从控制器模板元素获取输入。

访问控制器模板

每个控制器都有其实现的控制器模板列表。下面显示了访问这些模板的各种方法:

// Get the first Controller assigned to the Player that implements Gamepad Template
var controller = player.controllers.GetFirstControllerWithTemplate<IGamepadTemplate>();

// Get the Gamepad Template from the Controller
var gamepad = controller.GetTemplate<IGamepadTemplate>();

// Get a list of all Controller Templates of a particular type in all Controllers found on the system
var gamepads = ReInput.controllers.GetControllerTemplates<IGamepadTemplate>();

// Iterate through all Controller Templates implemented by a Controller
for(int i = 0; i < controller.templateCount; i++) {
    Debug.Log(controller.name + " implements the " + controller.Templates[i].name + " Template.");
}    

确定控制器是否实现了特定的控制器模板

有时,了解一个控制器是否实现了某个特定的控制器模板会很有用。具体方法如下:

// Check whether the Controller implements the Controller Template type
if(controller.ImplementsTemplate<IGamepadTemplate>()) {
    // Controller implements IGamepadTemplate
}

// You can also just try to get the Template directly and check if the result is null
var gamepad = controller.GetTemplate<IGamepadTemplate>();
if(gamepad != null) {
    // Controller implements IGamepadTemplate
}

直接从控制器模板获取输入

通常情况下,您会使用 "Player-Action "系统来获取输入值,但如果您愿意,也可以直接从控制器模板中的元素获取输入值。每个控制器模板界面都有一个可通过脚本访问的元素列表。下列脚本说明了这一过程:

// Get the Gamepad Template from the Controller
IGamepadTemplate gamepad = controller.GetTemplate<IGamepadTemplate>();

// If the result is null, the Controller does not implement the Gamepad Template
if (gamepad == null) continue;

// Read values directly from the elements
// Note that most elements on the Gamepad Template have aliases
// available such as a, b, x, y, back, start for elements which correspond to
// Xbox controller naming standards for your convenience.
// The standard names of actionBottomRow1, leftShoulder2, etc., are also available.
Vector2 moveVector = gamepad.leftStick.value;
Vector2 lookVector = gamepad.rightStick.value;
float fire = gamepad.rightTrigger.value;
// Any Axis can also be queried as a Button using the AsButton convenience property
bool fireJustPressed = gamepad.rightTrigger.AsButton.justPressed;
bool punch = gamepad.b.justPressed;
bool reload = gamepad.y.justPressed;
bool aim = gamepad.leftStick.press.value;
bool jump = gamepad.x.justPressed;
bool start = gamepad.start.justPressed;
bool up = gamepad.dPad.up.value;
bool down = gamepad.dPad.down.value;
Vector2 dPadVector = gamepad.dPad.value;

接口与具体类

控制器模板既可以是具体类,也可以是接口。在与应用程序接口交互时,应始终使用接口。具体类只公开其静态成员(元素标识符 id 常量、类型 guid 等)。

// Each Controller Template concrete class lists public
// constants for accessing the various elements should you need them
int id = GamepadTemplate.elementId_leftStickX;
id = GamepadTemplate.elementId_leftStickY;
id = GamepadTemplate.elementId_rightShoulder;

// The GUID is also available
Guid guid = GamepadTemplate.typeGuid;

从控制器Action映射中获取控制器模板元素

如果要确定控制器映射中与Player-Action映射相对应的控制器模板元素,可以使用 IControllerTemplate.GetElementTargets 方法将其转换为控制器模板元素目标。

int count = template.GetElementTargets(actionElementMap, results);

这将获取Action->元素映射指向的控制器模板元素。请注意,在极少数情况下,当Action->元素映射绑定到模板上的多个元素时,可能会返回两个目标,如赛车方向盘模板有 Shifer 1-10 和倒档,其中两个可能绑定到同一个控制器元素。如果两个模板按钮被映射到一个控制器轴的两极,也会返回两个元素。

更完整的示例请参见Gamepad Template UI example

控制器模板元素来源

每个控制器模板元素都指向一个控制器元素,而输入值正是从该元素中提取的。这些信息可在 IControllerTemplateElement.source 属性中找到。可以使用 IControllerTemplateElementSource.type 属性确定源类型,然后将其转换为相应的 IControllerTemplateAxisSource 或 IControllerTemplateButtonSource。

保存和加载控制器模板映射

通常,控制器映射是按控制器类型保存的。不过,也可以保存和加载控制器模板的映射。例如,如果您希望所有游戏手柄共享已保存的控制器映射,而不是每个手柄都有自己的保存数据,就可以这样做。这样您就可以在 Xbox 360 控制器上映射并保存映射,然后在插入索尼 Dual Shock 4 时,它将继承为 Xbox 360 控制器创建的映射。

控制器映射始终存在于每台设备上,但你可以在保存前将控制器映射转换为控制器模板映射。加载后,再将其转换回控制器映射并加载到Player中:

// Quick Example

// Convert Controller Map to a Controller Template Map and then export to XML
string xml = controllerMap.ToControllerTemplateMap<IGamepadTemplate>().ToXmlString();

// Convert exported Controller Template XML to a Controller Map again
ControllerMap controllerMap = ControllerTemplateMap.FromXml(xml).ToControllerMap(joystick);

// Load it in the Player
player.controllers.maps.AddMap(joystick, controllerMap);
// More detailed example below showing using the first implemented Controller Template
// instead of the using Gamepad Template specifically.

// Saving
if(controller.templateCount > 0) {

    // Get the first Controller Template implemented by this Controller
    IControllerTemplate template = controller.Templates[0];

    // Convert the Controller Map to a Controller Template Map
    ControllerTemplateMap templateMap = controllerMap.ToControllerTemplateMap(template.typeGuid);

    // Export the Controller Template Map to XML
    string xml = templateMap.ToXmlString();

    // Save the XML
}

// ...

// Loading
foreach(Joystick joystick in player.controllers.Joysticks) {

    if (joystick.templateCount == 0) continue; // this Joystick does not implement any Controller Templates
    
    // Get the first Controller Template implemented by this Controller
    IControllerTemplate template = controller.Templates[0];

    // Call some method to get the Xml for the template
    string xml = GetXml(player, joystick.Templates[0]);

    // Create the Controller Template Map from XML
    ControllerTemplateMap templateMap = ControllerTemplateMap.FromXml(xml);
    if (templateMap == null) continue; // failed to load from xml, skip

    // Convert to a Controller Map and add it to the Player
    player.controllers.maps.AddMap(joystick, templateMap.ToControllerMap(joystick));
}

未连接操纵杆时查看默认控制器模板映射

如果您需要查看控制器模板的元素映射到了什么,而没有连接实现该模板的操纵杆,您可以获取一个默认控制器模板映射的实例,该实例定义在Input Manager中,如下所示:

ReInput.mapping.GetControllerTemplateMapInstance(GamepadTemplate.typeGuid, categoryId, layoutId);

这将返回一个控制器模板映射,显示特定映射类别和布局中的默认绑定。请注意,此功能不会从已保存的用户 XML/JSON 中加载任何数据,因此如果用户重新映射了他们的控件,而您又保存了这些信息,那么返回的映射中将不会反映出这些信息。您必须从数据存储中加载已保存的映射,才能看到用户修改的绑定。

限制

  • 目前无法允许用户在运行期间将控制器模板映射并应用到未知控制器(或任何其他不兼容的控制器)。

Map Categories

映射表类别是控制器映射的第一级分类。每个控制器映射属于一个 "映射表类别(Map Categorie)"和一个 "布局(Layout)"。当在Rewired Editor中或通过API中选择 "控制器映射 "时,两者的组合可用于识别控制器映射。

与 "布局(Layout)"不同,所有类型的控制器映射都共享同一组 "映射表类别"。

根据您的游戏设计,您可以选择将地图类别用于多种用途。例如,一款游戏有多种不同的游戏模式。在这样的游戏中,映射表类别可以帮助您更轻松地组织不同游戏模式的控制。例如,如果您有以下类别,每个类别对应一种不同的游戏模式:系统、菜单、游戏共享、步兵、车辆、飞机。这样,您就可以为每种游戏模式设置不同的控制映射。当您改变游戏模式(例如进入菜单界面或上下车辆)时,您可以使用类别来决定启用/禁用哪些映射。

在创建用户控制分配界面时,可以使用 "用户可分配(User Assignable)"标志来帮助确定向用户显示的类别。例如,如果 "系统 "类别包含为系统保留的控件(保存、加载、退出等),则可能不希望用户重新分配这些控件。如果是这种情况,请取消选中 "用户可分配(User Assignable)",然后在映射界面代码中检查该标志。(一些映射界面代码示例包含在 Rewired/Examples 目录中)。在进行分配冲突检查时,也可以锁定非用户可分配类别中的控件,使其无法更改。

类别选择性冲突检查:选择对某些类别与其他类别进行冲突检查,但不一定是双向的。(适用于复杂的堆叠地图设置)。要选择当前类别应与哪些类别进行冲突检查,请取消选中 "与所有类别检查冲突(Check Conflicts With All)",并在 "与特定类别检查冲突(Check Conflicts With Specific Categories)"中添加类别。

Layouts

布局是控制器映射的第二级分类。每个控制器映射属于一个 "映射表类别 "和一个 "布局"。当在 Rewired Editor中或通过API中选择 "控制器映射 "时,二者的组合可用于识别控制器映射。

布局是每种控制器类型所特有的,不像 "映射表类别 "那样为所有控制器类型所共享。

布局只是提供了一种在特定映射表类别中检索特定控制器映射的方法。所有修改、启用/禁用和其他过程都是在控制器映射上完成的,而不是在布局上。你可以把 "布局 "看作是一种标签--它可以帮助你在正确的 "映射表类别 "中获取想要使用的控制器映射。

布局的一个可能用途是为控制器提供备用映射布局。例如,您可能有几个预定义的备用控制器布局,如默认"、"倒置"、"左撇子"、"经典 "等。您可以根据玩家的选择来加载特定的布局。

布局也可以作为另一个简单的分类级别。例如,对于键盘等共享控制器,为每个Player设置特定布局可能会很有用。您的 "映射表类别 "可以是 "默认"、"系统"、"菜单"、"步兵"、"车辆 "等,以便按游戏模式组织地图,而您的 "布局 "可以是 "系统"、"Player0"、"Player1"、"Player2 "等,以便进一步按玩家组织映射。

对于任何控制器类型,在特定的映射表类别和布局中只能存在一个控制器映射。

在运行时更改不同布局中的控制器映射

Player中的控制器映射可手动管理,或使用布局管理器(Layout Manager)进行管理,该系统可协助按布局管理控制器映射。