internal static IActuator[] CreateActuatorsFromMap(InputActionMap inputActionMap, BehaviorParameters behaviorParameters, InputDevice inputDevice, InputActuatorEventContext context) { var actuators = new IActuator[inputActionMap.actions.Count]; for (var i = 0; i < inputActionMap.actions.Count; i++) { var action = inputActionMap.actions[i]; var actionLayout = InputSystem.LoadLayout(action.expectedControlType); var adaptor = (IRLActionInputAdaptor)Activator.CreateInstance(controlTypeToAdaptorType[actionLayout.type]); actuators[i] = new InputActionActuator(inputDevice, behaviorParameters, action, adaptor, context); // Reasonably, the input system starts adding numbers after the first none numbered name // is added. So for device ID of 0, we use the empty string in the path. var path = $"{inputDevice?.path}{InputControlPath.Separator}{action.name}"; action.AddBinding(path, action.interactions, action.processors, mlAgentsControlSchemeName); action.bindingMask = InputBinding.MaskByGroup(mlAgentsControlSchemeName); } return(actuators); }
/// <summary> /// Construct an <see cref="InputActionActuator"/> with the <see cref="BehaviorParameters"/> of the /// <see cref="Agent"/> component, the relevant <see cref="InputAction"/>, and the relevant /// <see cref="IRLActionInputAdaptor"/> to convert between ml-agents <--> <see cref="InputSystem"/>. /// </summary> /// <param name="inputDevice">The input device this action is bound to.</param> /// <param name="behaviorParameters">Used to determine if the <see cref="Agent"/> is running in /// heuristic mode.</param> /// <param name="action">The <see cref="InputAction"/> this <see cref="IActuator"/> we read/write data to/from /// via the <see cref="IRLActionInputAdaptor"/>.</param> /// <param name="adaptor">The <see cref="IRLActionInputAdaptor"/> that will convert data between ML-Agents /// and the <see cref="InputSystem"/>.</param> /// <param name="inputActuatorEventContext">The object that will provide the event ptr to write to.</param> public InputActionActuator(InputDevice inputDevice, BehaviorParameters behaviorParameters, InputAction action, IRLActionInputAdaptor adaptor, InputActuatorEventContext inputActuatorEventContext) { m_BehaviorParameters = behaviorParameters; Name = $"InputActionActuator-{action.name}"; m_Action = action; m_InputAdaptor = adaptor; m_InputActuatorEventContext = inputActuatorEventContext; ActionSpec = adaptor.GetActionSpecForInputAction(m_Action); m_Device = inputDevice; m_Control = m_Device?.GetChildControl(m_Action.name); }
/// <summary> /// This method is where the <see cref="InputActionAsset"/> gets parsed and translated into /// <see cref="InputActionActuator"/>s that communicate with the <see cref="InputSystem"/> via a /// virtual <see cref="InputDevice"/>. /// <remarks> /// The flow of this method is as follows: /// <list type="number"> /// <item> /// <description>Ensure that our custom <see cref="InputBindingComposite{TValue}"/>s are registered with /// the InputSystem.</description> /// </item> /// <item> /// <description>Look for the components that are needed by this class in order to retrieve the /// <see cref="InputActionAsset"/>. It first looks for <see cref="IInputActionAssetProvider"/>, if that /// is not found, it will get the asset from the <see cref="PlayerInput"/> component.</description> /// </item> /// <item> /// <description>Create the list <see cref="InputActionActuator"/>s, one for each action in the default /// <see cref="InputActionMap"/> as set by the <see cref="PlayerInput"/> component. Within the method /// where the actuators are being created, an <see cref="InputControlLayout"/> is also being built based /// on the number and types of <see cref="InputAction"/>s. This will be used to create a virtual /// <see cref="InputDevice"/> with a <see cref="InputControlLayout"/> that is specific to the /// <see cref="InputActionMap"/> specified by <see cref="PlayerInput"/></description> /// </item> /// <item> /// <description>Create our device based on the layout that was generated and registered during /// actuator creation.</description> /// </item> /// <item> /// <description>Create an ml-agents control scheme and add it to the <see cref="InputActionAsset"/> so /// our virtual devices can be used.</description> /// </item> /// <item> /// <description>Add our virtual <see cref="InputDevice"/> to the input system.</description> /// </item> /// </list> /// </remarks> /// </summary> /// <returns>A list of </returns> public override IActuator[] CreateActuators() { FindNeededComponents(); var collection = m_AssetCollection ?? m_InputAsset; collection.Disable(); var inputActionMap = m_InputAsset.FindActionMap(m_PlayerInput.defaultActionMap); RegisterLayoutBuilder(inputActionMap, m_LayoutName); m_Device = InputSystem.AddDevice(m_LayoutName); var context = new InputActuatorEventContext(inputActionMap.actions.Count, m_Device); m_Actuators = CreateActuatorsFromMap(inputActionMap, m_BehaviorParameters, m_Device, context); UpdateDeviceBinding(m_BehaviorParameters.IsInHeuristicMode()); inputActionMap.Enable(); m_ActionSpec = CombineActuatorActionSpecs(m_Actuators); collection.Enable(); return(m_Actuators); }