using UnityEngine; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using CarbonInput; /// /// Interface to the carbon controller input system. /// // ReSharper disable once CheckNamespace // ReSharper disable InconsistentNaming public static class GamePad { public delegate void OnReloadEvent(); /// /// This event is fired when a reload has happened. /// public static event OnReloadEvent OnReload; /// /// Used for lazy initialization. /// private static bool IsInitialized; /// /// Array of all mappings supporting this platform. /// private static CarbonController[] AllMappings; /// /// One mapping for each player, including (index 0). /// private static ControllerInstance[] PlayerMappings; /// /// s of all players. /// private static readonly GamePadState[] States = new GamePadState[CarbonController.PlayerIndices]; /// /// Number of connected and supported hardware gamepads, without TouchInput/Keyboard. /// private static int gamepadCount; /// /// Number of connected and supported hardware gamepads, without TouchInput/Keyboard. /// public static int GamePadCount { get { if(!IsInitialized) Initialize(); return gamepadCount; } } /// /// Used to store settings like and inverted axes. /// private static CarbonSettings settings; /// /// Used to store settings like and inverted axes. /// public static CarbonSettings Settings { get { if(!IsInitialized) Initialize(); return settings; } set { if(!IsInitialized) Initialize(); settings = value; } } private static readonly CarbonController disabledInput = CarbonController.CreateDisabledInput(); /// /// Returns an array of all mappings supported by this platform. /// /// public static CarbonController[] GetAllMappings() { if(!IsInitialized) Initialize(); return AllMappings; } /// /// Returns an array of all player mappings. Index 0 is the mapping for and indices 1 to 8 meant to /// reference to . /// /// public static ControllerInstance[] GetPlayerMappings() { if(!IsInitialized) Initialize(); return PlayerMappings; } /// /// Reinitializes all GamePads. /// public static void ReInit() { var touchMappings = GetPlayerMappings().Skip(1).Where(x => x.Controller is TouchMapping).ToList(); Initialize(); var mappings = GetPlayerMappings(); int idx = 0; for(int i = 1; i < CarbonController.PlayerIndices && idx < touchMappings.Count; i++) { if(mappings[i] != null && mappings[i].Controller.Replacable) { mappings[i] = touchMappings[idx++]; if(i == 1) mappings[0] = mappings[1]; // required for PlayerIndex.Any if used with AnyBehaviour.UseMappingOne } } if(OnReload != null) OnReload(); } /// /// Initializes this library by loading all mappings from file and matching the given gamepads. /// private static void Initialize() { if(!IsInitialized) { // first init new GameObject("GamePad ReInit").AddComponent(); } List mappings = new List(Resources.LoadAll("Mappings")); // load all mappings mappings.RemoveAll(mapping => !mapping.SupportedOnThisPlatform()); // keep only mappings for this platform mappings.Sort((a, b) => a.Priority - b.Priority); // sort by priority, lower is better AllMappings = mappings.ToArray(); // now try to match with the names of the connected joysticks int nameIndex = 0; gamepadCount = 0; List matches = new List(); foreach(string name in Input.GetJoystickNames()) { CarbonController toRemove = null; foreach(CarbonController cc in mappings) { if(!string.IsNullOrEmpty(cc.RegEx) && Regex.IsMatch(name, cc.RegEx, RegexOptions.IgnoreCase)) { matches.Add(new ControllerInstance(cc, nameIndex)); gamepadCount++; if(cc.UseOnce) toRemove = cc; break; } } if(toRemove != null) mappings.Remove(toRemove); nameIndex++; } // add fallbacks (keyboard) var fallbacks = AllMappings.Where(x => x.IsFallback()).ToList(); fallbacks.Add(disabledInput); PlayerMappings = new ControllerInstance[CarbonController.PlayerIndices]; for(int i = 1; i < CarbonController.PlayerIndices; i++) { int idx = i - 1; if(idx < matches.Count) PlayerMappings[i] = matches[idx]; // real GamePad else { // Keyboard Fallback var fallback = fallbacks.First(); PlayerMappings[i] = new ControllerInstance(fallback, idx); if(fallback.UseOnce) fallbacks.RemoveAt(0); } } PlayerMappings[0] = PlayerMappings[1]; // always use first found mapping as the "global" mapping for Anyone for(int i = 0; i < CarbonController.PlayerIndices; i++) States[i] = new GamePadState((PlayerIndex)i); settings = CarbonSettings.Default(); IsInitialized = true; } /// /// Returns the mapping used by player . /// /// /// public static ControllerInstance GetMapping(PlayerIndex id) { if(!IsInitialized) Initialize(); return PlayerMappings[(int)id]; } /// /// Returns true if there is any real gamepad connected. /// /// public static bool AnyConnected() { if(!IsInitialized) Initialize(); return gamepadCount > 0; } /// /// Returns the state of button of player . /// /// /// /// public static bool GetButton(CButton btn, PlayerIndex id = PlayerIndex.Any) { if(!IsInitialized) Initialize(); if(id == PlayerIndex.Any) { switch(settings.Behaviour) { case AnyBehaviour.UseControllerOne: return PlayerMappings[1].GetButton(btn); case AnyBehaviour.CheckAll: for(int i = 1; i < CarbonController.PlayerIndices; i++) { if(PlayerMappings[i].GetButton(btn)) return true; } return false; } } return PlayerMappings[(int)id].GetButton(btn); } /// /// Returns the state of button of player using a playstation controller layout. /// /// /// /// public static bool GetButton(PSButton btn, PlayerIndex id = PlayerIndex.Any) { return GetButton((CButton)btn, id); } /// /// Returns the of player . The result is in range [-1, 1], except for the two triggers. /// They are in range [0, 1]. /// /// /// /// public static float GetAxis(CAxis axis, PlayerIndex id = PlayerIndex.Any) { if(!IsInitialized) Initialize(); if(Settings[axis]) return -GetAxisRaw(axis, id); return GetAxisRaw(axis, id); } private static float GetAxisRaw(CAxis axis, PlayerIndex id) { if(id == PlayerIndex.Any) { switch(settings.Behaviour) { case AnyBehaviour.UseControllerOne: return PlayerMappings[1].GetAxis(axis); case AnyBehaviour.CheckAll: for(int i = 1; i < CarbonController.PlayerIndices; i++) { float value = PlayerMappings[i].GetAxis(axis); if(Mathf.Abs(value) > 0.02f) return value; } return 0f; } } return PlayerMappings[(int)id].GetAxis(axis); } /// /// Returns a for the specified stick of player . /// /// /// /// public static Vector2 GetStick(CStick stick, PlayerIndex id = PlayerIndex.Any) { switch(stick) { case CStick.Left: return GetLeftStick(id); case CStick.Right: return GetRightStick(id); default: return GetDPad(id); } } /// /// Returns a vector for the left thumbstick of player . /// /// /// public static Vector2 GetLeftStick(PlayerIndex id = PlayerIndex.Any) { return new Vector2(GetAxis(CAxis.LX, id), GetAxis(CAxis.LY, id)); } /// /// Returns a vector for the right thumbstick of player . /// /// /// public static Vector2 GetRightStick(PlayerIndex id = PlayerIndex.Any) { return new Vector2(GetAxis(CAxis.RX, id), GetAxis(CAxis.RY, id)); } /// /// Returns the left trigger of player . Result is in range [0, 1]. /// /// /// public static float GetLeftTrigger(PlayerIndex id = PlayerIndex.Any) { return GetAxis(CAxis.LT, id); } /// /// Returns the right trigger of player . Result is in range [0, 1]. /// /// /// public static float GetRightTrigger(PlayerIndex id = PlayerIndex.Any) { return GetAxis(CAxis.RT, id); } /// /// Returns a vector for the dpad of player . /// /// /// public static Vector2 GetDPad(PlayerIndex id = PlayerIndex.Any) { return new Vector2(GetAxis(CAxis.DX, id), GetAxis(CAxis.DY, id)); } /// /// Returns the state of player . /// A contains all pressed buttons and axes values. /// It also stores information from the last frame in order to distinguish between a single press and a continuous pressing. /// /// /// public static GamePadState GetState(PlayerIndex id = PlayerIndex.Any) { if(!IsInitialized) Initialize(); GamePadState state = States[(int)id]; state.Update(); return state; } }