// Copyright (c) 2018 Augie R. Maddox, Guavaman Enterprises. All rights reserved. #pragma warning disable 0649 // disable warnings about unused variables /* This example shows how determine which Controller Template * elements correspond to mapped Actions in a Player, both those * that are currently active and those that are mapped. * These concepts be used to display a Controller Template based mapping * UI, display Controller Template element names / glyphs instead * of Controller-specific element names / glyphs, etc. * The same concepts can be used to display help UI using * Controller Template elements instead of Controller-specific * elements. * * This example is NOT meant to be modified and used in your game. * It is only intended to teach the API. */ namespace Rewired.Demos.GamepadTemplateUI { using UnityEngine; using UnityEngine.UI; using System; using System.Collections.Generic; public class GamepadTemplateUI : MonoBehaviour { private const float stickRadius = 20f; public int playerId = 0; [SerializeField] private RectTransform leftStick; [SerializeField] private RectTransform rightStick; [SerializeField] private ControllerUIElement leftStickX; [SerializeField] private ControllerUIElement leftStickY; [SerializeField] private ControllerUIElement leftStickButton; [SerializeField] private ControllerUIElement rightStickX; [SerializeField] private ControllerUIElement rightStickY; [SerializeField] private ControllerUIElement rightStickButton; [SerializeField] private ControllerUIElement actionBottomRow1; [SerializeField] private ControllerUIElement actionBottomRow2; [SerializeField] private ControllerUIElement actionBottomRow3; [SerializeField] private ControllerUIElement actionTopRow1; [SerializeField] private ControllerUIElement actionTopRow2; [SerializeField] private ControllerUIElement actionTopRow3; [SerializeField] private ControllerUIElement leftShoulder; [SerializeField] private ControllerUIElement leftTrigger; [SerializeField] private ControllerUIElement rightShoulder; [SerializeField] private ControllerUIElement rightTrigger; [SerializeField] private ControllerUIElement center1; [SerializeField] private ControllerUIElement center2; [SerializeField] private ControllerUIElement center3; [SerializeField] private ControllerUIElement dPadUp; [SerializeField] private ControllerUIElement dPadRight; [SerializeField] private ControllerUIElement dPadDown; [SerializeField] private ControllerUIElement dPadLeft; #if !REWIRED_USE_USER_DEFINED_CONTROLLER_TEMPLATES private UIElement[] _uiElementsArray; private Dictionary _uiElements = new Dictionary(); private IList _tempTargetList = new List(2); private Stick[] _sticks; private Player player { get { return ReInput.players.GetPlayer(playerId); } } private void Awake() { // Create an array of all UI elements so we can iterate this later _uiElementsArray = new UIElement[] { new UIElement(GamepadTemplate.elementId_leftStickX, leftStickX), new UIElement(GamepadTemplate.elementId_leftStickY, leftStickY), new UIElement(GamepadTemplate.elementId_leftStickButton, leftStickButton), new UIElement(GamepadTemplate.elementId_rightStickX, rightStickX), new UIElement(GamepadTemplate.elementId_rightStickY, rightStickY), new UIElement(GamepadTemplate.elementId_rightStickButton, rightStickButton), new UIElement(GamepadTemplate.elementId_actionBottomRow1, actionBottomRow1), new UIElement(GamepadTemplate.elementId_actionBottomRow2, actionBottomRow2), new UIElement(GamepadTemplate.elementId_actionBottomRow3, actionBottomRow3), new UIElement(GamepadTemplate.elementId_actionTopRow1, actionTopRow1), new UIElement(GamepadTemplate.elementId_actionTopRow2, actionTopRow2), new UIElement(GamepadTemplate.elementId_actionTopRow3, actionTopRow3), new UIElement(GamepadTemplate.elementId_center1, center1), new UIElement(GamepadTemplate.elementId_center2, center2), new UIElement(GamepadTemplate.elementId_center3, center3), new UIElement(GamepadTemplate.elementId_dPadUp, dPadUp), new UIElement(GamepadTemplate.elementId_dPadRight, dPadRight), new UIElement(GamepadTemplate.elementId_dPadDown, dPadDown), new UIElement(GamepadTemplate.elementId_dPadLeft, dPadLeft), new UIElement(GamepadTemplate.elementId_leftShoulder1, leftShoulder), new UIElement(GamepadTemplate.elementId_leftShoulder2, leftTrigger), new UIElement(GamepadTemplate.elementId_rightShoulder1, rightShoulder), new UIElement(GamepadTemplate.elementId_rightShoulder2, rightTrigger) }; // Add UI elements to the dictionary so we can look them up by Element Identifier Id for(int i = 0; i < _uiElementsArray.Length; i++) { _uiElements.Add(_uiElementsArray[i].id, _uiElementsArray[i].element); } // Create Sticks which will be used to move the sticks on the UI _sticks = new Stick[] { new Stick(leftStick, GamepadTemplate.elementId_leftStickX, GamepadTemplate.elementId_leftStickY), new Stick(rightStick, GamepadTemplate.elementId_rightStickX, GamepadTemplate.elementId_rightStickY) }; // Subscribe to controller connection events ReInput.ControllerConnectedEvent += OnControllerConnected; ReInput.ControllerDisconnectedEvent += OnControllerDisconnected; } private void Start() { if(!ReInput.isReady) return; DrawLabels(); } private void OnDestroy() { // Unsubscribe from events ReInput.ControllerConnectedEvent -= OnControllerConnected; ReInput.ControllerDisconnectedEvent -= OnControllerDisconnected; } private void Update() { if(!ReInput.isReady) return; DrawActiveElements(); } private void DrawActiveElements() { // Deactivate all elements first for(int i = 0; i < _uiElementsArray.Length; i++) { _uiElementsArray[i].element.Deactivate(); } // Reset stick positions for(int i = 0; i < _sticks.Length; i++) { _sticks[i].Reset(); } // Activate elements currently active based on the Action IList actions = ReInput.mapping.Actions; for(int i = 0; i < actions.Count; i++) { ActivateElements(player, actions[i].id); } } private void ActivateElements(Player player, int actionId) { // Get the Axis value of the Action from the Player float axisValue = player.GetAxis(actionId); if(axisValue == 0f) return; // not active // Get all the sources contributing to the Action IList sources = player.GetCurrentInputSources(actionId); // Check each source and activate the elements they map to for(int i = 0; i < sources.Count; i++) { InputActionSourceData source = sources[i]; // Try to get the GamepadTemplate from the Controller IGamepadTemplate gamepad = source.controller.GetTemplate(); if(gamepad == null) continue; // does not implement the Dual Analog Gamepad Template // Get all element targets on the template by passing in the Action Element Map // This gives you the Template element targets that are mapped to the Controller element target. gamepad.GetElementTargets(source.actionElementMap, _tempTargetList); // Activate Template element targets for(int j = 0; j < _tempTargetList.Count; j++) { ControllerTemplateElementTarget target = _tempTargetList[j]; int templateElementId = target.element.id; ControllerUIElement uiElement = _uiElements[templateElementId]; if(target.elementType == ControllerTemplateElementType.Axis) { uiElement.Activate(axisValue); } else if(target.elementType == ControllerTemplateElementType.Button) { // If the target element is a Button, make sure the Button value of the Action is true before activating if(player.GetButton(actionId) || player.GetNegativeButton(actionId)) uiElement.Activate(1f); } // Move the stick for stick axes Stick stick = GetStick(templateElementId); if(stick != null) stick.SetAxisPosition(templateElementId, axisValue * stickRadius); } } } private void DrawLabels() { // Clear UI labels first for(int i = 0; i < _uiElementsArray.Length; i++) { _uiElementsArray[i].element.ClearLabels(); } // Draw the label for each Action IList actions = ReInput.mapping.Actions; for(int i = 0; i < actions.Count; i++) { DrawLabels(player, actions[i]); } } private void DrawLabels(Player player, InputAction action) { // Lists first Action bound to each Dual Analog Gamepad Template element // Get the first Controller that implements the Dual Analog Gamepad Template from the Player Controller controller = player.controllers.GetFirstControllerWithTemplate(); if(controller == null) return; // Get the first gamepad assigned to the Player IGamepadTemplate gamepad = controller.GetTemplate(); // Get the Controller Map in the Default category and layout for this Controller from the Player ControllerMap controllerMap = player.controllers.maps.GetMap(controller, "Default", "Default"); if(controllerMap == null) return; // Go through each Controller Template element displayed in the UI for(int i = 0; i < _uiElementsArray.Length; i++) { ControllerUIElement uiElement = _uiElementsArray[i].element; int elementId = _uiElementsArray[i].id; // Get the Controller Template Element from the Controller Template IControllerTemplateElement element = gamepad.GetElement(elementId); // Draw the label DrawLabel(uiElement, action, controllerMap, gamepad, element); } } private void DrawLabel(ControllerUIElement uiElement, InputAction action, ControllerMap controllerMap, IControllerTemplate template, IControllerTemplateElement element) { if(element.source == null) return; // this element cannot map to a source ActionElementMap aem; // A Controller Template Element Source contains Targets that each point to // a Controller.Element or part of a Controller.Element (such as one pole of an Axis). // Handle Axis-type Template Element if(element.source.type == ControllerTemplateElementSourceType.Axis) { // Cast the source to an Axis source so we can access the 3 possible Targets IControllerTemplateAxisSource source = (element.source as IControllerTemplateAxisSource); // A Template axis source can be either a full-axis binding or a split-axis binding // Handle split-axis source if(source.splitAxis) { // A split-axis source has a Positive Target and a Negative Target, one for each side of the axis. // Positive Target aem = controllerMap.GetFirstElementMapWithElementTarget(source.positiveTarget, action.id, true); if(aem != null) { uiElement.SetLabel(aem.actionDescriptiveName, AxisRange.Positive); } // Negative Target aem = controllerMap.GetFirstElementMapWithElementTarget(source.negativeTarget, action.id, true); if(aem != null) uiElement.SetLabel(aem.actionDescriptiveName, AxisRange.Negative); // Handle full-axis source } else { // A full-axis sources has just a single full target. // Full Target aem = controllerMap.GetFirstElementMapWithElementTarget(source.fullTarget, action.id, true); if(aem != null) { // a full target was mapped uiElement.SetLabel(aem.actionDescriptiveName, AxisRange.Full); } else { // no full mapping was found, look for separate positive/negative mappings // Positive side aem = controllerMap.GetFirstElementMapWithElementTarget( new ControllerElementTarget(source.fullTarget) { axisRange = AxisRange.Positive }, action.id, true ); if(aem != null) uiElement.SetLabel(aem.actionDescriptiveName, AxisRange.Positive); // Negative side aem = controllerMap.GetFirstElementMapWithElementTarget( new ControllerElementTarget(source.fullTarget) { axisRange = AxisRange.Negative }, action.id, true ); if(aem != null) uiElement.SetLabel(aem.actionDescriptiveName, AxisRange.Negative); } } // Handle Button-type Template Element } else if(element.source.type == ControllerTemplateElementSourceType.Button) { // Cast the source to an button source IControllerTemplateButtonSource source = (element.source as IControllerTemplateButtonSource); // Target aem = controllerMap.GetFirstElementMapWithElementTarget(source.target, action.id, true); if(aem != null) uiElement.SetLabel(aem.actionDescriptiveName, AxisRange.Full); } } private Stick GetStick(int elementId) { for(int i = 0; i < _sticks.Length; i++) { if(_sticks[i].ContainsElement(elementId)) return _sticks[i]; } return null; } private void OnControllerConnected(ControllerStatusChangedEventArgs args) { DrawLabels(); } private void OnControllerDisconnected(ControllerStatusChangedEventArgs args) { DrawLabels(); } private class Stick { private RectTransform _transform; private Vector2 _origPosition; private int _xAxisElementId = -1; private int _yAxisElementId = -1; public Vector2 position { get { return _transform != null ? _transform.anchoredPosition - _origPosition : Vector2.zero; } set { if(_transform == null) return; _transform.anchoredPosition = _origPosition + value; } } public Stick(RectTransform transform, int xAxisElementId, int yAxisElementId) { if(transform == null) return; _transform = transform; _origPosition = _transform.anchoredPosition; _xAxisElementId = xAxisElementId; _yAxisElementId = yAxisElementId; } public void Reset() { if(_transform == null) return; _transform.anchoredPosition = _origPosition; } public bool ContainsElement(int elementId) { if(_transform == null) return false; return elementId == _xAxisElementId || elementId == _yAxisElementId; } public void SetAxisPosition(int elementId, float value) { if(_transform == null) return; Vector2 position = this.position; if(elementId == _xAxisElementId) position.x = value; else if(elementId == _yAxisElementId) position.y = value; this.position = position; } } private class UIElement { public int id; public ControllerUIElement element; public UIElement(int id, ControllerUIElement element) { this.id = id; this.element = element; } } #endif } }