diff --git a/Assets/ControllerMapper.asset b/Assets/ControllerMapper.asset new file mode 100644 index 0000000..c3741be Binary files /dev/null and b/Assets/ControllerMapper.asset differ diff --git a/Assets/ControllerMapper.asset.meta b/Assets/ControllerMapper.asset.meta new file mode 100644 index 0000000..e2e8f26 --- /dev/null +++ b/Assets/ControllerMapper.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4e69a787b1338846b2293e50d7cc92e +timeCreated: 1440215393 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor.meta b/Assets/Editor.meta new file mode 100644 index 0000000..30f1702 --- /dev/null +++ b/Assets/Editor.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 2ca10ed205191f6469b088b753449e2e +folderAsset: yes +timeCreated: 1436647855 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/InputHandler.meta b/Assets/Editor/InputHandler.meta new file mode 100644 index 0000000..60fef14 --- /dev/null +++ b/Assets/Editor/InputHandler.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 7f51e978f4624ae4794201e436ec39e5 +folderAsset: yes +timeCreated: 1435023323 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/InputHandler/CreateControllerMapperAsset.cs b/Assets/Editor/InputHandler/CreateControllerMapperAsset.cs new file mode 100644 index 0000000..5ded958 --- /dev/null +++ b/Assets/Editor/InputHandler/CreateControllerMapperAsset.cs @@ -0,0 +1,21 @@ +using UnityEngine; +using System.Collections; +using UnityEditor; + +namespace InputHandler +{ + public class CreateControllerMapperAsset + { + [MenuItem("InputHandler/Create/ControllerMapper")] + public static void CreateInputAsset() + { + ControllerMapperAsset asset = ControllerMapperAsset.CreateInstance(); + AssetDatabase.CreateAsset(asset, "Assets/ControllerMapper.asset"); + AssetDatabase.SaveAssets(); + + EditorUtility.FocusProjectWindow(); + + Selection.activeObject = asset; + } + } +} \ No newline at end of file diff --git a/Assets/Editor/InputHandler/CreateControllerMapperAsset.cs.meta b/Assets/Editor/InputHandler/CreateControllerMapperAsset.cs.meta new file mode 100644 index 0000000..b030eaf --- /dev/null +++ b/Assets/Editor/InputHandler/CreateControllerMapperAsset.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 37a276da6a074c149a173094095c1e94 +timeCreated: 1434958498 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Materials/ChildMaterial.mat b/Assets/Materials/ChildMaterial.mat index 874f1fe..ff3fa90 100644 Binary files a/Assets/Materials/ChildMaterial.mat and b/Assets/Materials/ChildMaterial.mat differ diff --git a/Assets/Plugins.meta b/Assets/Plugins.meta new file mode 100644 index 0000000..c8171b5 --- /dev/null +++ b/Assets/Plugins.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b8cbf66babec0bc45aaff94731a97758 +folderAsset: yes +timeCreated: 1440215282 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/x86.meta b/Assets/Plugins/x86.meta new file mode 100644 index 0000000..58e77ae --- /dev/null +++ b/Assets/Plugins/x86.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d5a17b4fbbb9c794fb163e397e963e00 +folderAsset: yes +timeCreated: 1434857820 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/x86/XInputDotNetPure.dll b/Assets/Plugins/x86/XInputDotNetPure.dll new file mode 100644 index 0000000..f44f947 Binary files /dev/null and b/Assets/Plugins/x86/XInputDotNetPure.dll differ diff --git a/Assets/Plugins/x86/XInputDotNetPure.dll.meta b/Assets/Plugins/x86/XInputDotNetPure.dll.meta new file mode 100644 index 0000000..bd05672 --- /dev/null +++ b/Assets/Plugins/x86/XInputDotNetPure.dll.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: c4e96c35cd46f534592ecc07b608e110 +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/x86/XInputInterface.dll b/Assets/Plugins/x86/XInputInterface.dll new file mode 100644 index 0000000..7efa8fa Binary files /dev/null and b/Assets/Plugins/x86/XInputInterface.dll differ diff --git a/Assets/Plugins/x86/XInputInterface.dll.meta b/Assets/Plugins/x86/XInputInterface.dll.meta new file mode 100644 index 0000000..6c437d5 --- /dev/null +++ b/Assets/Plugins/x86/XInputInterface.dll.meta @@ -0,0 +1,6 @@ +fileFormatVersion: 2 +guid: bbceb1b00a2e35849a7020d601589c40 +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/x86_64.meta b/Assets/Plugins/x86_64.meta new file mode 100644 index 0000000..f103658 --- /dev/null +++ b/Assets/Plugins/x86_64.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 19f56f3d79f95da47ae4895f7588c43b +folderAsset: yes +timeCreated: 1434857820 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/x86_64/XInputDotNetPure.dll b/Assets/Plugins/x86_64/XInputDotNetPure.dll new file mode 100644 index 0000000..d345520 Binary files /dev/null and b/Assets/Plugins/x86_64/XInputDotNetPure.dll differ diff --git a/Assets/Plugins/x86_64/XInputDotNetPure.dll.meta b/Assets/Plugins/x86_64/XInputDotNetPure.dll.meta new file mode 100644 index 0000000..b1b839c --- /dev/null +++ b/Assets/Plugins/x86_64/XInputDotNetPure.dll.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: b9f05caccaeb48146ae995df3ed431ab +PluginImporter: + serializedVersion: 1 + iconMap: {} + executionOrder: {} + isPreloaded: 0 + platformData: + Any: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/x86_64/XInputInterface.dll b/Assets/Plugins/x86_64/XInputInterface.dll new file mode 100644 index 0000000..8a2d764 Binary files /dev/null and b/Assets/Plugins/x86_64/XInputInterface.dll differ diff --git a/Assets/Plugins/x86_64/XInputInterface.dll.meta b/Assets/Plugins/x86_64/XInputInterface.dll.meta new file mode 100644 index 0000000..bae1129 --- /dev/null +++ b/Assets/Plugins/x86_64/XInputInterface.dll.meta @@ -0,0 +1,6 @@ +fileFormatVersion: 2 +guid: ea895df4f09804d47ac0a43ce22418cb +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Child.prefab b/Assets/Prefabs/Child.prefab index d2b5146..beacf7f 100644 Binary files a/Assets/Prefabs/Child.prefab and b/Assets/Prefabs/Child.prefab differ diff --git a/Assets/Prefabs/InputManager.prefab b/Assets/Prefabs/InputManager.prefab new file mode 100644 index 0000000..d58fb1d Binary files /dev/null and b/Assets/Prefabs/InputManager.prefab differ diff --git a/Assets/Prefabs/InputManager.prefab.meta b/Assets/Prefabs/InputManager.prefab.meta new file mode 100644 index 0000000..7e77ed1 --- /dev/null +++ b/Assets/Prefabs/InputManager.prefab.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 158e745881137e04ca2086294f44d74c +timeCreated: 1440215386 +licenseType: Free +NativeFormatImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scenes/PatScene.unity b/Assets/Scenes/PatScene.unity index 0cdf9a3..bcf66ca 100644 Binary files a/Assets/Scenes/PatScene.unity and b/Assets/Scenes/PatScene.unity differ diff --git a/Assets/Scripts/Child.cs b/Assets/Scripts/Child.cs new file mode 100644 index 0000000..9ff814d --- /dev/null +++ b/Assets/Scripts/Child.cs @@ -0,0 +1,31 @@ +using UnityEngine; +using System.Collections; + +[RequireComponent(typeof(Rigidbody))] +public class Child : MonoBehaviour +{ + public float Speed = 10f; + + private Rigidbody _rb; + + void Awake() + { + _rb = GetComponent(); + } + + public void Move(float xValue, float zValue) + { + // We move the child depending on the camera orientation + + Vector3 forwardDir = Camera.main.transform.forward; + Vector3 rightDir = Camera.main.transform.right; + + forwardDir.y = 0f; + forwardDir *= zValue * Speed; + + rightDir.y = 0f; + rightDir *= xValue * Speed; + + _rb.velocity = forwardDir + rightDir; + } +} diff --git a/Assets/Scripts/Child.cs.meta b/Assets/Scripts/Child.cs.meta new file mode 100644 index 0000000..b0fffb2 --- /dev/null +++ b/Assets/Scripts/Child.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dd2c12784e85d194ca7216a12233e1fa +timeCreated: 1440215984 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/ChildController.cs b/Assets/Scripts/ChildController.cs index 10198a7..cc9a375 100644 --- a/Assets/Scripts/ChildController.cs +++ b/Assets/Scripts/ChildController.cs @@ -1,15 +1,51 @@ using UnityEngine; using System.Collections; +using InputHandler; -public class CharacterController : MonoBehaviour { +[RequireComponent(typeof(Child))] +public class ChildController : MonoBehaviour +{ + public enum Player { One, Two, Three, Four } + + public Player PlayerNumber; + + private Child _child; + + void Awake() + { + InputManager.Instance.PushActiveContext("Gameplay", (int)PlayerNumber); + InputManager.Instance.AddCallback((int)PlayerNumber, HandlePlayerInput); + + _child = GetComponent(); + } + + private void HandlePlayerInput(MappedInput input) + { + if (this == null) return; + + float xValue = 0f; + + if (input.Ranges.ContainsKey("MoveLeft")) + { + xValue = -input.Ranges["MoveLeft"]; + } + else if (input.Ranges.ContainsKey("MoveRight")) + { + xValue = input.Ranges["MoveRight"]; + } + + float zValue = 0f; + + if (input.Ranges.ContainsKey("MoveForward")) + { + zValue = input.Ranges["MoveForward"]; + } + else if (input.Ranges.ContainsKey("MoveBackward")) + { + zValue = -input.Ranges["MoveBackward"]; + } + + _child.Move(xValue, zValue); + } - // Use this for initialization - void Start () { - - } - - // Update is called once per frame - void Update () { - - } } diff --git a/Assets/Scripts/InputHandler.meta b/Assets/Scripts/InputHandler.meta new file mode 100644 index 0000000..8fe520f --- /dev/null +++ b/Assets/Scripts/InputHandler.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d6e2ccb4aa280a04297ff5048cde5ee1 +folderAsset: yes +timeCreated: 1434183356 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/InputHandler/ControllerManager.cs b/Assets/Scripts/InputHandler/ControllerManager.cs new file mode 100644 index 0000000..f911a9e --- /dev/null +++ b/Assets/Scripts/InputHandler/ControllerManager.cs @@ -0,0 +1,196 @@ +using UnityEngine; +using System.Collections; +using XInputDotNetPure; +using System.Collections.Generic; + +namespace InputHandler +{ + public class ControllerManager : InputManager + { + private bool[] _initialSetupDone; + private PlayerIndex[] _playerIndexes; + private GamePadState[] _gamePadPreviousStates; + private GamePadState[] _gamePadStates; + + protected override void InitialSetup() + { + _initialSetupDone = new bool[MAX_PLAYER_COUNT]; + _playerIndexes = new PlayerIndex[MAX_PLAYER_COUNT]; + _gamePadPreviousStates = new GamePadState[MAX_PLAYER_COUNT]; + _gamePadStates = new GamePadState[MAX_PLAYER_COUNT]; + + for (int i = 0; i < MAX_PLAYER_COUNT; i++) + { + _gamePadStates[i] = GamePad.GetState(_playerIndexes[i]); + } + } + + protected override void MapInputs() + { + for (int i = 0; i < MAX_PLAYER_COUNT; i++) + { + _gamePadPreviousStates[i] = _gamePadStates[i]; + _gamePadStates[i] = GamePad.GetState(_playerIndexes[i]); + + if (!_gamePadPreviousStates[i].IsConnected || !_initialSetupDone[i]) + { + _initialSetupDone[i] = true; + + if (_gamePadStates[i].IsConnected) + { + _playerIndexes[i] = (PlayerIndex)i; + + Debug.Log(string.Format("GamePad {0} is ready", _playerIndexes[i])); + } + } + + MapPlayerInput(_inputMappers[i], _gamePadStates[i], _gamePadPreviousStates[i]); + } + } + + // TODO: Maybe reduce it to only the inputs actually used in the game? + private void MapPlayerInput(InputMapper inputMapper, GamePadState state, GamePadState previousState) + { + foreach (int axisInt in InputMapperAsset.GetMappedXboxAxis()) + { + MapXboxAxis(axisInt, inputMapper, state); + } + + foreach (int buttonInt in InputMapperAsset.GetMappedXboxButtons()) + { + MapXboxButton(buttonInt, inputMapper, state, previousState); + } + + // TODO: Put the following code into another class, so we can have 2 distinct XboxManager and KeyboardManager classes + + // We map only the keyboard keys that are going to be used in the game + + foreach (int key in InputMapperAsset.GetMappedKeyboardKeys()) + { + inputMapper.SetRawButtonState(100 + key, Input.GetKey((KeyCode)key), Input.GetKey((KeyCode)key) && !Input.GetKeyDown((KeyCode)key)); + } + + foreach (int key in InputMapperAsset.GetMappedKeyboardKeysAxis()) + { + float value = Input.GetKey((KeyCode)key) ? 1f : 0f; + + inputMapper.SetRawAxisValue(100 + key, value); + } + } + + private void MapXboxButton(int buttonInt, InputMapper inputMapper, GamePadState state, GamePadState previousState) + { + XboxInputConstants.Buttons button = (XboxInputConstants.Buttons)buttonInt; + + bool pressed = false; + bool previouslyPressed = false; + + switch (button) + { + case XboxInputConstants.Buttons.A: + pressed = state.Buttons.A == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.A == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.B: + pressed = state.Buttons.B == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.B == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.X: + pressed = state.Buttons.X == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.X == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.Y: + pressed = state.Buttons.Y == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.Y == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.LeftShoulder: + pressed = state.Buttons.LeftShoulder == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.LeftShoulder == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.RightShoulder: + pressed = state.Buttons.RightShoulder == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.RightShoulder == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.Back: + pressed = state.Buttons.Back == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.Back == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.Start: + pressed = state.Buttons.Start == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.Start == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.LeftStick: + pressed = state.Buttons.LeftStick == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.LeftStick == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.RightStick: + pressed = state.Buttons.RightStick == ButtonState.Pressed; + previouslyPressed = previousState.Buttons.RightStick == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.DPadLeft: + pressed = state.DPad.Left == ButtonState.Pressed; + previouslyPressed = previousState.DPad.Left == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.DPadRight: + pressed = state.DPad.Right == ButtonState.Pressed; + previouslyPressed = previousState.DPad.Right == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.DPadUp: + pressed = state.DPad.Up == ButtonState.Pressed; + previouslyPressed = previousState.DPad.Up == ButtonState.Pressed; + break; + case XboxInputConstants.Buttons.DPadDown: + pressed = state.DPad.Down == ButtonState.Pressed; + previouslyPressed = previousState.DPad.Down == ButtonState.Pressed; + break; + } + + inputMapper.SetRawButtonState(buttonInt, pressed, previouslyPressed); + } + + private void MapXboxAxis(int axisInt, InputMapper inputMapper, GamePadState state) + { + XboxInputConstants.Axis axis = (XboxInputConstants.Axis)axisInt; + + float value = 0f; + + switch (axis) + { + case XboxInputConstants.Axis.LeftStickLeft: + // If the left stick X value is negative, we keep it and take its absolute value + value = state.ThumbSticks.Left.X < 0f ? -state.ThumbSticks.Left.X : 0f; + break; + case XboxInputConstants.Axis.LeftStickRight: + // If the left stick X value is positive, we keep it + value = state.ThumbSticks.Left.X > 0f ? state.ThumbSticks.Left.X : 0f; + break; + case XboxInputConstants.Axis.LeftStickDown: + value = state.ThumbSticks.Left.Y < 0f ? -state.ThumbSticks.Left.Y : 0f; + break; + case XboxInputConstants.Axis.LeftStickUp: + value = state.ThumbSticks.Left.Y > 0f ? state.ThumbSticks.Left.Y : 0f; + break; + case XboxInputConstants.Axis.RightStickLeft: + value = state.ThumbSticks.Right.X < 0f ? -state.ThumbSticks.Right.X : 0f; + break; + case XboxInputConstants.Axis.RightStickRight: + value = state.ThumbSticks.Right.X > 0f ? state.ThumbSticks.Right.X : 0f; + break; + case XboxInputConstants.Axis.RightStickDown: + value = state.ThumbSticks.Right.Y < 0f ? -state.ThumbSticks.Right.Y : 0f; + break; + case XboxInputConstants.Axis.RightStickUp: + value = state.ThumbSticks.Right.Y > 0f ? state.ThumbSticks.Right.Y : 0f; + break; + case XboxInputConstants.Axis.TriggerLeft: + value = state.Triggers.Left; + break; + case XboxInputConstants.Axis.TriggerRight: + value = state.Triggers.Right; + break; + } + + inputMapper.SetRawAxisValue(axisInt, value); + } + } +} diff --git a/Assets/Scripts/InputHandler/ControllerManager.cs.meta b/Assets/Scripts/InputHandler/ControllerManager.cs.meta new file mode 100644 index 0000000..f25f973 --- /dev/null +++ b/Assets/Scripts/InputHandler/ControllerManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 6e33ba5066fe01747b2722e6f089a2ba +timeCreated: 1436627825 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: -50 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/InputHandler/ControllerMapperAsset.cs b/Assets/Scripts/InputHandler/ControllerMapperAsset.cs new file mode 100644 index 0000000..bf77e1d --- /dev/null +++ b/Assets/Scripts/InputHandler/ControllerMapperAsset.cs @@ -0,0 +1,197 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System; + +namespace InputHandler +{ + // TODO: REFACTOR THE WHOLE CLASS, IT STINKS + + [SerializeField] + public class ControllerMapperAsset : InputMapperAsset + { + [Serializable] + public class XboxContext + { + public string name; + public XboxAction[] ButtonActions; + public XboxRange[] AxisRanges; + public XboxState[] ButtonStates; + } + + [Serializable] + public class XboxAction + { + public string name; + public XboxInputConstants.Buttons[] XboxButtons; + public KeyCode[] KeyboardKeys; + } + + [Serializable] + public class XboxRange + { + public string name; + public XboxInputConstants.Axis[] Axis; + public KeyCode[] KeyboardKeys; + } + + [Serializable] + public class XboxState + { + public string name; + public XboxInputConstants.Buttons[] XboxButtons; + public KeyCode[] KeyboardKeys; + } + + public XboxContext[] Contexts; + + // TODO: Temporary + private List _mappedKeyboardKeysAxis; + private List _mappedKeyboardKeys; + private List _mappedXboxAxis; + private List _mappedXboxButtons; + + // Context -> InputMap + public override Dictionary GetMappedContexts() + { + _mappedKeyboardKeys = new List(); + _mappedKeyboardKeysAxis = new List(); + _mappedXboxButtons = new List(); + _mappedXboxAxis = new List(); + + Dictionary mappedContexts = new Dictionary(); + + foreach (XboxContext xboxContext in Contexts) + { + InputMap inputMap = new InputMap(); + + inputMap.ButtonsToActionsMap = new List[xboxContext.ButtonActions.Length]; + inputMap.ButtonsToStatesMap = new List[xboxContext.ButtonStates.Length]; + inputMap.AxisToRangesMap = new List[xboxContext.AxisRanges.Length]; + + for (int i = 0; i < xboxContext.ButtonActions.Length; i++) + { + XboxAction buttonAction = xboxContext.ButtonActions[i]; + + inputMap.ButtonsToActionsMap[i] = new List(); + + foreach (XboxInputConstants.Buttons xboxButton in buttonAction.XboxButtons) + { + // TODO: We need to manage this in the InputMapper side + inputMap.ButtonsToActionsMap[i].Add(new InputToActionMap { action = buttonAction.name, input = (int)xboxButton }); + + if (!_mappedXboxButtons.Contains((int)xboxButton)) + { + _mappedXboxButtons.Add((int)xboxButton); + } + } + + // Keyboard part + foreach (KeyCode key in buttonAction.KeyboardKeys) + { + // TODO: Find a way to not add 100 to the code (for now, it's necessary since there are overlaps with the xbox enum) + inputMap.ButtonsToActionsMap[i].Add(new InputToActionMap { action = buttonAction.name, input = 100 + (int)key }); + + // TODO: Temporary + if (!_mappedKeyboardKeys.Contains((int)key)) + { + _mappedKeyboardKeys.Add((int)key); + } + } + } + + for (int i = 0; i < xboxContext.ButtonStates.Length; i++) + { + XboxState buttonState = xboxContext.ButtonStates[i]; + + inputMap.ButtonsToStatesMap[i] = new List(); + + foreach (XboxInputConstants.Buttons xboxButton in buttonState.XboxButtons) + { + // TODO: We need to manage this in the InputMapper side + inputMap.ButtonsToStatesMap[i].Add(new InputToActionMap() { action = buttonState.name, input = (int)xboxButton }); + + if (!_mappedXboxButtons.Contains((int)xboxButton)) + { + _mappedXboxButtons.Add((int)xboxButton); + } + } + + // Keyboard part + foreach (KeyCode key in buttonState.KeyboardKeys) + { + // TODO: Find a way to not add 100 to the code (for now, it's necessary since there are overlaps with the xbox enum) + inputMap.ButtonsToStatesMap[i].Add(new InputToActionMap { action = buttonState.name, input = 100 + (int)key }); + + // TODO: Temporary + if (!_mappedKeyboardKeys.Contains((int)key)) + { + _mappedKeyboardKeys.Add((int)key); + } + } + } + + for (int i = 0; i < xboxContext.AxisRanges.Length; i++) + { + XboxRange axisRange = xboxContext.AxisRanges[i]; + + inputMap.AxisToRangesMap[i] = new List(); + + foreach (XboxInputConstants.Axis xboxAxis in axisRange.Axis) + { + // TODO: We need to manage this in the InputMapper side + inputMap.AxisToRangesMap[i].Add(new InputToActionMap() { action = axisRange.name, input = (int)xboxAxis }); + + if (!_mappedXboxAxis.Contains((int)xboxAxis)) + { + _mappedXboxAxis.Add((int)xboxAxis); + } + } + + // Keyboard part + foreach (KeyCode key in axisRange.KeyboardKeys) + { + // TODO: Find a way to not add 100 to the code (for now, it's necessary since there are overlaps with the xbox enum) + inputMap.AxisToRangesMap[i].Add(new InputToActionMap { action = axisRange.name, input = 100 + (int)key }); + + // TODO: Temporary + if (!_mappedKeyboardKeysAxis.Contains((int)key)) + { + _mappedKeyboardKeysAxis.Add((int)key); + } + } + } + + InputContext context = new InputContext(xboxContext.name, inputMap); + + mappedContexts.Add(xboxContext.name, context); + } + + return mappedContexts; + } + + // TODO: Probably temporary, until we find a better way and all the classes are refactored + + // Utility method to be used by the ControllerManager class + public override List GetMappedKeyboardKeysAxis() + { + return _mappedKeyboardKeysAxis; + } + + // Utility method to be used by the ControllerManager class + public override List GetMappedKeyboardKeys() + { + return _mappedKeyboardKeys; + } + + public override List GetMappedXboxAxis() + { + return _mappedXboxAxis; + } + + public override List GetMappedXboxButtons() + { + return _mappedXboxButtons; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/InputHandler/ControllerMapperAsset.cs.meta b/Assets/Scripts/InputHandler/ControllerMapperAsset.cs.meta new file mode 100644 index 0000000..aedca80 --- /dev/null +++ b/Assets/Scripts/InputHandler/ControllerMapperAsset.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 539aad81a9327404e8e67bb53c540d91 +timeCreated: 1436387267 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/InputHandler/InputConstants.cs b/Assets/Scripts/InputHandler/InputConstants.cs new file mode 100644 index 0000000..0b823e8 --- /dev/null +++ b/Assets/Scripts/InputHandler/InputConstants.cs @@ -0,0 +1,19 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace InputHandler +{ + public struct InputMap + { + public List[] ButtonsToActionsMap; + public List[] ButtonsToStatesMap; + public List[] AxisToRangesMap; + } + + public struct InputToActionMap + { + public int input; + public string action; + } +} diff --git a/Assets/Scripts/InputHandler/InputConstants.cs.meta b/Assets/Scripts/InputHandler/InputConstants.cs.meta new file mode 100644 index 0000000..5bc8258 --- /dev/null +++ b/Assets/Scripts/InputHandler/InputConstants.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: baa0e457a4ff21a4a8eb7d57efeef697 +timeCreated: 1434996179 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/InputHandler/InputContext.cs b/Assets/Scripts/InputHandler/InputContext.cs new file mode 100644 index 0000000..1ca6d92 --- /dev/null +++ b/Assets/Scripts/InputHandler/InputContext.cs @@ -0,0 +1,70 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System; + +namespace InputHandler +{ + public class InputContext + { + private Dictionary _mappedButtons; + private Dictionary _mappedStates; + private Dictionary _mappedAxis; + + private string _name; + + public string Name + { + get { return _name; } + } + + + public InputContext(string contextName, InputMap inputMap) + { + _name = contextName; + + _mappedButtons = new Dictionary(); + _mappedStates = new Dictionary(); + _mappedAxis = new Dictionary(); + + foreach (List buttonsToActionsMap in inputMap.ButtonsToActionsMap) + { + foreach (InputToActionMap buttonToActionMap in buttonsToActionsMap) + { + _mappedButtons.Add(buttonToActionMap.input, buttonToActionMap.action); + } + } + + foreach (List buttonsToStatesMap in inputMap.ButtonsToStatesMap) + { + foreach (InputToActionMap buttonToStateMap in buttonsToStatesMap) + { + _mappedStates.Add(buttonToStateMap.input, buttonToStateMap.action); + } + } + + foreach (List axisToRangesMap in inputMap.AxisToRangesMap) + { + foreach (InputToActionMap axisToRangeMap in axisToRangesMap) + { + _mappedAxis.Add(axisToRangeMap.input, axisToRangeMap.action); + } + } + } + + public string GetActionForButton(int button) + { + return _mappedButtons.ContainsKey(button) ? _mappedButtons[button] : null; + } + + public string GetStateForButton(int button) + { + return _mappedStates.ContainsKey(button) ? _mappedStates[button] : null; + } + + public string GetRangeForAxis(int axis) + { + return _mappedAxis.ContainsKey(axis) ? _mappedAxis[axis] : null; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/InputHandler/InputContext.cs.meta b/Assets/Scripts/InputHandler/InputContext.cs.meta new file mode 100644 index 0000000..dc2aa61 --- /dev/null +++ b/Assets/Scripts/InputHandler/InputContext.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d99cd0919594864482148f723dfa8e2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Scripts/InputHandler/InputManager.cs b/Assets/Scripts/InputHandler/InputManager.cs new file mode 100644 index 0000000..2c0e292 --- /dev/null +++ b/Assets/Scripts/InputHandler/InputManager.cs @@ -0,0 +1,98 @@ +using UnityEngine; +using System.Collections; +using XInputDotNetPure; +using System; +using System.Collections.Generic; + +namespace InputHandler +{ + public abstract class InputManager : MonoBehaviour + { + public static InputManager Instance + { + get + { + return _instance; + } + } + + private static InputManager _instance; + + protected InputMapper[] _inputMappers; + + public int MAX_PLAYER_COUNT = 2; + public InputMapperAsset InputMapperAsset; + + protected abstract void InitialSetup(); + protected abstract void MapInputs(); + + void Awake() + { + if (_instance != null) + { + Destroy(gameObject); + } + else + { + _instance = this; + + _inputMappers = new InputMapper[MAX_PLAYER_COUNT]; + + Dictionary mappedContexts = InputMapperAsset.GetMappedContexts(); + + for (int i = 0; i < MAX_PLAYER_COUNT; i++) + { + _inputMappers[i] = new InputMapper(mappedContexts); + } + + // Do the needed initial setup in the derived classes + InitialSetup(); + } + } + + void Update() + { + // Do the input mapping here in the derived classes + MapInputs(); + + for (int i = 0; i < _inputMappers.Length; i++) + { + _inputMappers[i].Dispatch(); + } + } + + public void AddCallback(int playerIndex, Action action) + { + _inputMappers[playerIndex].AddCallback(action); + } + + public void PushActiveContext(string name, int playerIndex) + { + _inputMappers[playerIndex].PushActiveContext(name); + } + + public void PopActiveContext(int playerIndex) + { + // TODO: Give the choice to remove an active context not on top + _inputMappers[playerIndex].PopActiveContext(); + } + + public void ClearContexts() + { + // For now, all input mappers are gonna have the same contexts at the same time + + for (int i = 0; i < _inputMappers.Length; i++) + { + _inputMappers[i].ClearActiveContexts(); + } + } + + void LateUpdate() + { + for (int i = 0; i < _inputMappers.Length; i++) + { + _inputMappers[i].ResetInputs(); + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/InputHandler/InputManager.cs.meta b/Assets/Scripts/InputHandler/InputManager.cs.meta new file mode 100644 index 0000000..7e29a63 --- /dev/null +++ b/Assets/Scripts/InputHandler/InputManager.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 967b7f4e180b49f4fb6f53702c67aa34 +timeCreated: 1436627825 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: -100 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/InputHandler/InputMapper.cs b/Assets/Scripts/InputHandler/InputMapper.cs new file mode 100644 index 0000000..25dc580 --- /dev/null +++ b/Assets/Scripts/InputHandler/InputMapper.cs @@ -0,0 +1,205 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System; + +/* + Strongly inspired from Mike Lewis' excellent post about input handling + http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games/ +*/ + +namespace InputHandler +{ + public class InputMapper + { + // Right now, the only active context is the peek of the stack, but when we will need multiple contexts at once, this is going to be useful + private Dictionary _contexts; + private Stack _activeContexts; + + private List> _callbacks; + + private MappedInput _currentFrameMappedInput; + + public InputMapper(Dictionary contexts) + { + _contexts = contexts; + _activeContexts = new Stack(); + _callbacks = new List>(); + _currentFrameMappedInput = new MappedInput(); + } + + public void Dispatch() + { + foreach (Action callback in _callbacks) + { + callback(_currentFrameMappedInput); + } + } + + public void PushActiveContext(string name) + { + InputContext context = _contexts[name]; + + if (_activeContexts.Count == 0 || _activeContexts.Peek().Name != name) + { + _activeContexts.Push(context); + } + } + + public void PopActiveContext() + { + if (_activeContexts.Count != 0) + { + _activeContexts.Pop(); + } + } + + public void ClearActiveContexts() + { + _activeContexts.Clear(); + } + + public void AddCallback(Action callback) + { + _callbacks.Add(callback); + } + + public void SetRawButtonState(int button, bool pressed, bool previouslyPressed) + { + string action = GetActionForButton(button); + string state = GetStateForButton(button); + + if (pressed) + { + if (!previouslyPressed && action != null) + { + _currentFrameMappedInput.Actions.Add(action); + return; + } + + if (state != null) + { + _currentFrameMappedInput.States.Add(state); + return; + } + } + + // Uncomment if we start to have problems + //RemoveButtonFromLists(button); + } + + public void SetRawAxisValue(int axis, float value) + { + // TODO: Have contexts for every single player? + + // TODO: Use the commented code below instead when we will want multiple contexts to be available at the same time (maybe for when the player holds a weapon?). We'll keep it simple for now. + + /* + foreach (InputContext activeContext in _activeContexts) + { + InputConstants.Ranges range = activeContext.GetRangeForAxis(axis); + + if (range != InputConstants.Ranges.None) + { + // We only want the first active "range behaviour" of the player to handle the ranges values, since we don't want multiple actions to react to it + _mappedInputs[playerIndex].Ranges[range] = value; + break; + } + }*/ + + if (value != 0f) + { + string range = null; + + if (_activeContexts.Count != 0) + { + range = _activeContexts.Peek().GetRangeForAxis(axis); + } + + if (range != null) + { + _currentFrameMappedInput.Ranges[range] = value; + } + } + } + + public void ResetInputs() + { + _currentFrameMappedInput.Clear(); + } + + #region Helper methods + + private string GetActionForButton(int button) + { + // TODO: Have contexts for every single player? + + // TODO: Use the commented code below instead when we will want multiple contexts to be available at the same time (maybe for when the player holds a weapon?). We'll keep it simple for now. + + /* + foreach (InputContext activeContext in _activeContexts) + { + InputConstants.Actions action = activeContext.GetActionForButton(button); + + if (action != InputConstants.Actions.None) + { + return action; + } + }*/ + + string action = null; + + if (_activeContexts.Count != 0) + { + action = _activeContexts.Peek().GetActionForButton(button); + } + + return action; + } + + private string GetStateForButton(int button) + { + // TODO: Have contexts for every single player? + + // TODO: Use the commented code below instead when we will want multiple contexts to be available at the same time (maybe for when the player holds a weapon?). We'll keep it simple for now. + + /* + foreach (InputContext activeContext in _activeContexts) + { + InputConstants.States state = activeContext.GetStateForButton(button); + + if (state != InputConstants.States.None) + { + return state; + } + }*/ + + string state = null; + + if (_activeContexts.Count != 0) + { + state = _activeContexts.Peek().GetStateForButton(button); + } + + return state; + } + + private void RemoveButtonFromLists(int button) + { + string action = GetActionForButton(button); + string state = GetStateForButton(button); + + if (action != null) + { + _currentFrameMappedInput.Actions.Remove(action); + } + + if (state != null) + { + _currentFrameMappedInput.States.Remove(state); + } + } + + #endregion + } +} diff --git a/Assets/Scripts/InputHandler/InputMapper.cs.meta b/Assets/Scripts/InputHandler/InputMapper.cs.meta new file mode 100644 index 0000000..f760acc --- /dev/null +++ b/Assets/Scripts/InputHandler/InputMapper.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 586455317dda0b543a30eff647db722e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Scripts/InputHandler/InputMapperAsset.cs b/Assets/Scripts/InputHandler/InputMapperAsset.cs new file mode 100644 index 0000000..f9bbbaa --- /dev/null +++ b/Assets/Scripts/InputHandler/InputMapperAsset.cs @@ -0,0 +1,20 @@ +using UnityEngine; +using System.Collections; +using System; +using System.Collections.Generic; + +namespace InputHandler +{ + public abstract class InputMapperAsset : ScriptableObject + { + public enum InputTypes { Action, State, Range } + + public abstract Dictionary GetMappedContexts(); + + // TODO: Probably temporary, until we find a better way and all the classes are refactored + public abstract List GetMappedKeyboardKeysAxis(); + public abstract List GetMappedKeyboardKeys(); + public abstract List GetMappedXboxAxis(); + public abstract List GetMappedXboxButtons(); + } +} \ No newline at end of file diff --git a/Assets/Scripts/InputHandler/InputMapperAsset.cs.meta b/Assets/Scripts/InputHandler/InputMapperAsset.cs.meta new file mode 100644 index 0000000..beec650 --- /dev/null +++ b/Assets/Scripts/InputHandler/InputMapperAsset.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3a5ffa04260e8db4a9eab84c1e6b11ae +timeCreated: 1434962375 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/InputHandler/MappedInput.cs b/Assets/Scripts/InputHandler/MappedInput.cs new file mode 100644 index 0000000..b244bce --- /dev/null +++ b/Assets/Scripts/InputHandler/MappedInput.cs @@ -0,0 +1,23 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System; + +namespace InputHandler +{ + // Specific to the game + public class MappedInput + { + // We use hashets for the actions and the states because we just need to check if they are in the collection, and not retrieve them + public HashSet Actions = new HashSet(); + public HashSet States = new HashSet(); + public Dictionary Ranges = new Dictionary(); + + public void Clear() + { + Actions.Clear(); + States.Clear(); + Ranges.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/InputHandler/MappedInput.cs.meta b/Assets/Scripts/InputHandler/MappedInput.cs.meta new file mode 100644 index 0000000..40b9d51 --- /dev/null +++ b/Assets/Scripts/InputHandler/MappedInput.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5fe308a0d85530408827f4357cc1ff5 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Scripts/InputHandler/XboxInputConstants.cs b/Assets/Scripts/InputHandler/XboxInputConstants.cs new file mode 100644 index 0000000..e5ab19d --- /dev/null +++ b/Assets/Scripts/InputHandler/XboxInputConstants.cs @@ -0,0 +1,43 @@ +using UnityEngine; +using System.Collections; + +namespace InputHandler +{ + //TODO: When we will be ready to read raw inputs from a file, we need this to simply be generic "BUTTON_ONE, BUTTON_TWO, etc." + + public class XboxInputConstants + { + // These buttons will eventually map to controls saved in a file + public enum Buttons + { + A, + B, + X, + Y, + LeftShoulder, + RightShoulder, + Back, + Start, + LeftStick, + RightStick, + DPadLeft, + DPadRight, + DPadUp, + DPadDown, + } + + public enum Axis + { + LeftStickLeft, + LeftStickRight, + LeftStickUp, + LeftStickDown, + RightStickLeft, + RightStickRight, + RightStickUp, + RightStickDown, + TriggerLeft, + TriggerRight + } + } +} diff --git a/Assets/Scripts/InputHandler/XboxInputConstants.cs.meta b/Assets/Scripts/InputHandler/XboxInputConstants.cs.meta new file mode 100644 index 0000000..c9ed15d --- /dev/null +++ b/Assets/Scripts/InputHandler/XboxInputConstants.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 4b46fefecf9412e46bdad7c26a00d537 +timeCreated: 1436628179 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index 89df263..52c12ea 100644 Binary files a/ProjectSettings/ProjectSettings.asset and b/ProjectSettings/ProjectSettings.asset differ diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 802c8ce..8c353d8 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 5.0.2f1 +m_EditorVersion: 5.1.2f1 m_StandardAssetsVersion: 0