mirror of
https://github.com/Ratstail91/Keep-It-Alive.git
synced 2025-11-29 10:34:27 +11:00
Working on it
This commit is contained in:
268
Assets/CarbonInput/Scripts/CarbonController.cs
Normal file
268
Assets/CarbonInput/Scripts/CarbonController.cs
Normal file
@@ -0,0 +1,268 @@
|
||||
using UnityEngine;
|
||||
|
||||
// Users don't have to use this directly, so there is no need to have this in global namespace
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// Describes a mapping for a specific controller. This mapping is independend of the PlayerIndex.
|
||||
/// Each CarbonController defines how buttons and axes are mapped correctly to the Unity Input.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "NewCarbonMapping", menuName = "Carbon Input/GamePad Mapping")]
|
||||
public class CarbonController : ScriptableObject {
|
||||
/// <summary>
|
||||
/// Number of buttons defined in the <see cref="CButton"/> enumeration.
|
||||
/// </summary>
|
||||
public const int ButtonCount = 10; // Must match the CButton enum!
|
||||
/// <summary>
|
||||
/// Number of axes defined in the <see cref="AxisCount"/> enumeration.
|
||||
/// </summary>
|
||||
public const int AxisCount = 8; // Must match the CAxis enum!
|
||||
/// <summary>
|
||||
/// Number of generated axes,
|
||||
/// </summary>
|
||||
public const int InputAxisCount = 16; // Must match the number of generated Input axes!
|
||||
/// <summary>
|
||||
/// Number of joystick buttons supported by unity.
|
||||
/// </summary>
|
||||
public const int JoystickButtonCount = 20; // Number of joystick buttons supported by Unity
|
||||
/// <summary>
|
||||
/// Number of entries in <see cref="PlayerIndex"/> enumeration.
|
||||
/// </summary>
|
||||
public const int PlayerIndices = 9; // Any, One, ..., Eight
|
||||
/// <summary>
|
||||
/// Prefix of all generated axes.
|
||||
/// </summary>
|
||||
public const string Tag = "cin_Axis";
|
||||
|
||||
/// <summary>
|
||||
/// Mapping of [<see cref="PlayerIndex"/>, JoystickAxis] to its name.
|
||||
/// </summary>
|
||||
private static readonly string[,] AxisNames;
|
||||
static CarbonController() {
|
||||
// construct all strings beforehand
|
||||
AxisNames = new string[PlayerIndices, InputAxisCount];
|
||||
for(int id = 0; id < PlayerIndices; id++) {
|
||||
for(int axis = 0; axis < InputAxisCount; axis++) {
|
||||
AxisNames[id, axis] = CreateName(id, axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Create the input axis name for <see cref="PlayerIndex"/> and axis.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="axis"></param>
|
||||
/// <returns></returns>
|
||||
public static string CreateName(int id, int axis) {
|
||||
return Tag + id + "_" + axis.ToString("D2");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Regular expression used to check if this mapping can be used for a controller.
|
||||
/// </summary>
|
||||
public string RegEx;
|
||||
/// <summary>
|
||||
/// Platforms supported by this mapping.
|
||||
/// </summary>
|
||||
public CPlatform Platform;
|
||||
/// <summary>
|
||||
/// Priority of this mapping. On startup the system will try to find a correct mapping for all controller. Lower priority mappings will be tester earlier.
|
||||
/// </summary>
|
||||
public int Priority = 1000;
|
||||
/// <summary>
|
||||
/// If true, this mapping will only be used once, even if it could be used multiple times.
|
||||
/// </summary>
|
||||
public bool UseOnce;
|
||||
/// <summary>
|
||||
/// If true, this mapping can be replaced by touch mappings.
|
||||
/// </summary>
|
||||
public bool Replacable;
|
||||
/// <summary>
|
||||
/// All mappings for all possible <see cref="CAxis"/>. This array must have exactly <see cref="AxisCount"/> many entries.
|
||||
/// </summary>
|
||||
public AxisMapping[] Axes = new AxisMapping[AxisCount];
|
||||
/// <summary>
|
||||
/// All mappings for all possible <see cref="CButton"/>s. This array must have exactly <see cref="ButtonCount"/> many entries.
|
||||
/// </summary>
|
||||
public ButtonMapping[] Buttons = new ButtonMapping[ButtonCount];
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this mapping is a fallback mapping.
|
||||
/// A mapping is considered a fallback, if it doesn't have a proper <see cref="RegEx"/>.
|
||||
/// By default, the keyboard is considered a fallback mapping.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsFallback() {
|
||||
return string.IsNullOrEmpty(RegEx);
|
||||
}
|
||||
|
||||
public CarbonController() {
|
||||
for(int i = 0; i < Buttons.Length; i++) Buttons[i] = new ButtonMapping();
|
||||
for(int i = 0; i < Axes.Length; i++) Axes[i] = new AxisMapping();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if controller button btn of player id is pressed.
|
||||
/// </summary>
|
||||
/// <param name="btn">GamePad button</param>
|
||||
/// <param name="id">Index of player</param>
|
||||
/// <returns></returns>
|
||||
public virtual bool GetButton(CButton btn, int id) {
|
||||
ButtonMapping key = Buttons[(int)btn];
|
||||
if(key.Type == ButtonMapping.ButtonType.Wrapper) {
|
||||
if(key.Key != KeyCode.None) return Input.GetKey(key.Key);
|
||||
} else {
|
||||
//JoystickButton0 = 330 ... JoystickButton19 = 349
|
||||
//Joystick1Button0 = 350 ... Joystick1Button19 = 369
|
||||
// ...
|
||||
//Joystick8Button0 = 490 ... Joystick8Button19 = 509
|
||||
return Input.GetKey(KeyCode.JoystickButton0 + id * JoystickButtonCount + key.Button);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the virtual axis of player <paramref name="id"/> identified by the <paramref name="axis"/> parameter;
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public virtual float GetAxis(CAxis axis, int id) {
|
||||
AxisMapping mapping = Axes[(int)axis];
|
||||
float result = 0;
|
||||
switch(mapping.Type) {
|
||||
case AxisMapping.AxisType.Default:
|
||||
result = Input.GetAxis(AxisNames[id, mapping.Axis]);
|
||||
break;
|
||||
case AxisMapping.AxisType.ButtonWrapper:
|
||||
result = Input.GetKey(KeyCode.JoystickButton0 + id * JoystickButtonCount + mapping.Axis) ? mapping.Max : mapping.Min;
|
||||
break;
|
||||
case AxisMapping.AxisType.KeyWrapper:
|
||||
bool key1 = Input.GetKey(mapping.Key1);
|
||||
bool key2 = Input.GetKey(mapping.Key2);
|
||||
if(key1 && !key2) result = -1;
|
||||
else if(!key1 && key2) result = 1;
|
||||
else result = 0;
|
||||
break;
|
||||
case AxisMapping.AxisType.Clamped:
|
||||
result = Mathf.Clamp(Input.GetAxis(AxisNames[id, mapping.Axis]), mapping.Min, mapping.Max);
|
||||
break;
|
||||
case AxisMapping.AxisType.ButtonWrapper2:
|
||||
key1 = Input.GetKey(KeyCode.JoystickButton0 + id * JoystickButtonCount + mapping.Axis);
|
||||
key2 = Input.GetKey(KeyCode.JoystickButton0 + id * JoystickButtonCount + mapping.Alternative);
|
||||
if(key1 && !key2) result = -1;
|
||||
else if(!key1 && key2) result = 1;
|
||||
else result = 0;
|
||||
break;
|
||||
case AxisMapping.AxisType.TriggerLimiter:
|
||||
result = (Input.GetAxis(AxisNames[id, mapping.Axis]) + 1f) / 2f;
|
||||
break;
|
||||
}
|
||||
if(mapping.Invert) return -result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this mapping is supported on the execution platform.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool SupportedOnThisPlatform() {
|
||||
switch(Application.platform) {
|
||||
case RuntimePlatform.WebGLPlayer: return Has(CPlatform.WebGL);
|
||||
case RuntimePlatform.Android: return Has(CPlatform.Android);
|
||||
case RuntimePlatform.IPhonePlayer: return Has(CPlatform.IOS);
|
||||
case RuntimePlatform.LinuxEditor:
|
||||
case RuntimePlatform.LinuxPlayer: return Has(CPlatform.Linux);
|
||||
case RuntimePlatform.OSXEditor:
|
||||
case RuntimePlatform.OSXPlayer:
|
||||
return Has(CPlatform.OSX);
|
||||
case RuntimePlatform.PS4: return Has(CPlatform.PS4);
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
case RuntimePlatform.PSP2: return Has(CPlatform.PSP2);
|
||||
#endif
|
||||
#if !UNITY_2018_1_OR_NEWER
|
||||
case RuntimePlatform.WiiU: return Has(CPlatform.Wii);
|
||||
#endif
|
||||
case RuntimePlatform.WindowsEditor:
|
||||
case RuntimePlatform.WindowsPlayer: return Has(CPlatform.Windows);
|
||||
case RuntimePlatform.WSAPlayerARM:
|
||||
case RuntimePlatform.WSAPlayerX64:
|
||||
case RuntimePlatform.WSAPlayerX86: return Has(CPlatform.WSA);
|
||||
case RuntimePlatform.XboxOne: return Has(CPlatform.XBoxOne);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the given <see cref="CPlatform"/> is set in <see cref="Platform"/>.
|
||||
/// </summary>
|
||||
/// <param name="flag"></param>
|
||||
/// <returns></returns>
|
||||
private bool Has(CPlatform flag) {
|
||||
return (Platform & flag) == flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will return a fallback instance, using the keyboard.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static CarbonController CreateFallback() {
|
||||
CarbonController cc = CreateInstance<CarbonController>();
|
||||
cc.Platform = (CPlatform)(-1);
|
||||
MakeKeyWrapper(cc.Buttons[0], KeyCode.RightShift);
|
||||
MakeKeyWrapper(cc.Buttons[1], KeyCode.RightControl);
|
||||
MakeKeyWrapper(cc.Buttons[2], KeyCode.LeftShift);
|
||||
MakeKeyWrapper(cc.Buttons[3], KeyCode.Space);
|
||||
MakeKeyWrapper(cc.Buttons[4], KeyCode.Escape);
|
||||
MakeKeyWrapper(cc.Buttons[5], KeyCode.Return);
|
||||
MakeKeyWrapper(cc.Buttons[6], KeyCode.Q);
|
||||
MakeKeyWrapper(cc.Buttons[7], KeyCode.E);
|
||||
MakeKeyWrapper(cc.Buttons[8]);
|
||||
MakeKeyWrapper(cc.Buttons[9]);
|
||||
MakeKeyWrapper(cc.Axes[0], KeyCode.A, KeyCode.D);
|
||||
MakeKeyWrapper(cc.Axes[1], KeyCode.W, KeyCode.S);
|
||||
for(int i = 2; i < AxisCount; i++) MakeKeyWrapper(cc.Axes[i]);
|
||||
return cc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will return a fallback instance, which doesn't respond to any key.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static CarbonController CreateDisabledInput() {
|
||||
var cc = CreateInstance<CarbonController>();
|
||||
cc.name = "DisabledInput";
|
||||
cc.Platform = (CPlatform)(-1);
|
||||
cc.Replacable = true;
|
||||
for(int i = 0; i < ButtonCount; i++)
|
||||
MakeKeyWrapper(cc.Buttons[i]);
|
||||
for(int i = 0; i < AxisCount; i++)
|
||||
MakeKeyWrapper(cc.Axes[i]);
|
||||
return cc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the given <see cref="AxisMapping"/> to be a <see cref="AxisMapping.AxisType.KeyWrapper"/>
|
||||
/// </summary>
|
||||
/// <param name="mapping"></param>
|
||||
/// <param name="key1"></param>
|
||||
/// <param name="key2"></param>
|
||||
private static void MakeKeyWrapper(AxisMapping mapping, KeyCode key1 = KeyCode.None, KeyCode key2 = KeyCode.None) {
|
||||
mapping.Type = AxisMapping.AxisType.KeyWrapper;
|
||||
mapping.Key1 = key1;
|
||||
mapping.Min = key1 != KeyCode.None ? -1 : 0;
|
||||
mapping.Key2 = key2;
|
||||
mapping.Max = key2 != KeyCode.None ? 1 : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the given <see cref="ButtonMapping"/> to be a <see cref="ButtonMapping.ButtonType.Wrapper"/>.
|
||||
/// </summary>
|
||||
/// <param name="mapping"></param>
|
||||
/// <param name="key"></param>
|
||||
private static void MakeKeyWrapper(ButtonMapping mapping, KeyCode key = KeyCode.None) {
|
||||
mapping.Type = ButtonMapping.ButtonType.Wrapper;
|
||||
mapping.Key = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Assets/CarbonInput/Scripts/CarbonController.cs.meta
Normal file
16
Assets/CarbonInput/Scripts/CarbonController.cs.meta
Normal file
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c038c960b0ce7624993fdb8e9953dba8
|
||||
labels:
|
||||
- Gamepad
|
||||
- Input
|
||||
- Joystick
|
||||
timeCreated: 1455638784
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
469
Assets/CarbonInput/Scripts/CarbonInputModule.cs
Normal file
469
Assets/CarbonInput/Scripts/CarbonInputModule.cs
Normal file
@@ -0,0 +1,469 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace CarbonInput {
|
||||
[AddComponentMenu("Event/Carbon Input Module")]
|
||||
public class CarbonInputModule : PointerInputModule {
|
||||
private const float Threshold = 0.3f;
|
||||
public PlayerIndex Player = PlayerIndex.Any;
|
||||
public CAxis HorizontalAxis = CAxis.LX;
|
||||
public bool InvertHorizontal;
|
||||
public CAxis VerticalAxis = CAxis.LY;
|
||||
public bool InvertVertical = true;
|
||||
public CButton SubmitButton = CButton.A;
|
||||
public CButton CancelButton = CButton.B;
|
||||
|
||||
private float m_PrevActionTime;
|
||||
private Vector2 m_LastMoveVector;
|
||||
private int m_ConsecutiveMoveCount;
|
||||
|
||||
private Vector2 m_LastMousePosition;
|
||||
private Vector2 m_MousePosition;
|
||||
private Vector2 _lastRawMove;
|
||||
|
||||
private bool HorizontalPressed { get { return Math.Abs(_lastRawMove.x) < Threshold && Math.Abs(GamePad.GetAxis(HorizontalAxis, Player)) > Threshold; } }
|
||||
private bool VerticalPressed { get { return Math.Abs(_lastRawMove.y) < Threshold && Math.Abs(GamePad.GetAxis(VerticalAxis, Player)) > Threshold; } }
|
||||
|
||||
protected CarbonInputModule() {
|
||||
}
|
||||
|
||||
[Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
|
||||
public enum InputMode {
|
||||
Mouse,
|
||||
Buttons
|
||||
}
|
||||
|
||||
[Obsolete("Mode is no longer needed on input module as it handles both mouse and keyboard simultaneously.", false)]
|
||||
public InputMode inputMode {
|
||||
get { return InputMode.Mouse; }
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float m_InputActionsPerSecond = 10;
|
||||
|
||||
[SerializeField]
|
||||
private float m_RepeatDelay = 0.5f;
|
||||
|
||||
[SerializeField]
|
||||
[FormerlySerializedAs("m_AllowActivationOnMobileDevice")]
|
||||
private bool m_ForceModuleActive;
|
||||
|
||||
[Obsolete("allowActivationOnMobileDevice has been deprecated. Use forceModuleActive instead (UnityUpgradable) -> forceModuleActive")]
|
||||
public bool allowActivationOnMobileDevice {
|
||||
get { return m_ForceModuleActive; }
|
||||
set { m_ForceModuleActive = value; }
|
||||
}
|
||||
|
||||
public bool forceModuleActive {
|
||||
get { return m_ForceModuleActive; }
|
||||
set { m_ForceModuleActive = value; }
|
||||
}
|
||||
|
||||
public float inputActionsPerSecond {
|
||||
get { return m_InputActionsPerSecond; }
|
||||
set { m_InputActionsPerSecond = value; }
|
||||
}
|
||||
|
||||
public float repeatDelay {
|
||||
get { return m_RepeatDelay; }
|
||||
set { m_RepeatDelay = value; }
|
||||
}
|
||||
|
||||
public override void UpdateModule() {
|
||||
m_LastMousePosition = m_MousePosition;
|
||||
m_MousePosition = Input.mousePosition;
|
||||
}
|
||||
|
||||
public override bool IsModuleSupported() {
|
||||
return m_ForceModuleActive || Input.mousePresent || Input.touchSupported;
|
||||
}
|
||||
|
||||
public override bool ShouldActivateModule() {
|
||||
if(!base.ShouldActivateModule())
|
||||
return false;
|
||||
|
||||
var state = GamePad.GetState(Player);
|
||||
var shouldActivate = m_ForceModuleActive;
|
||||
shouldActivate |= state.Pressed(SubmitButton);
|
||||
shouldActivate |= state.Pressed(CancelButton);
|
||||
shouldActivate |= GetRawMoveVector().sqrMagnitude > 0.0f;
|
||||
shouldActivate |= (m_MousePosition - m_LastMousePosition).sqrMagnitude > 0.0f;
|
||||
shouldActivate |= Input.GetMouseButtonDown(0);
|
||||
|
||||
if(Input.touchCount > 0)
|
||||
shouldActivate = true;
|
||||
|
||||
return shouldActivate;
|
||||
}
|
||||
|
||||
public override void ActivateModule() {
|
||||
base.ActivateModule();
|
||||
m_MousePosition = Input.mousePosition;
|
||||
m_LastMousePosition = Input.mousePosition;
|
||||
|
||||
var toSelect = eventSystem.currentSelectedGameObject;
|
||||
if(toSelect == null)
|
||||
toSelect = eventSystem.firstSelectedGameObject;
|
||||
|
||||
eventSystem.SetSelectedGameObject(toSelect, GetBaseEventData());
|
||||
}
|
||||
|
||||
public override void DeactivateModule() {
|
||||
base.DeactivateModule();
|
||||
ClearSelection();
|
||||
}
|
||||
|
||||
public override void Process() {
|
||||
bool usedEvent = SendUpdateEventToSelectedObject();
|
||||
|
||||
if(eventSystem.sendNavigationEvents) {
|
||||
if(!usedEvent)
|
||||
usedEvent |= SendMoveEventToSelectedObject();
|
||||
|
||||
if(!usedEvent)
|
||||
SendSubmitEventToSelectedObject();
|
||||
}
|
||||
|
||||
// touch needs to take precedence because of the mouse emulation layer
|
||||
if(!ProcessTouchEvents())
|
||||
ProcessMouseEvent();
|
||||
_lastRawMove = GetRawMoveVector();
|
||||
}
|
||||
|
||||
private bool ProcessTouchEvents() {
|
||||
for(int i = 0; i < Input.touchCount; ++i) {
|
||||
Touch input = Input.GetTouch(i);
|
||||
|
||||
if(input.type == TouchType.Indirect)
|
||||
continue;
|
||||
|
||||
bool released;
|
||||
bool pressed;
|
||||
var pointer = GetTouchPointerEventData(input, out pressed, out released);
|
||||
|
||||
ProcessTouchPress(pointer, pressed, released);
|
||||
|
||||
if(!released) {
|
||||
ProcessMove(pointer);
|
||||
ProcessDrag(pointer);
|
||||
} else
|
||||
RemovePointerData(pointer);
|
||||
}
|
||||
return Input.touchCount > 0;
|
||||
}
|
||||
|
||||
private void ProcessTouchPress(PointerEventData pointerEvent, bool pressed, bool released) {
|
||||
var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
|
||||
|
||||
// PointerDown notification
|
||||
if(pressed) {
|
||||
pointerEvent.eligibleForClick = true;
|
||||
pointerEvent.delta = Vector2.zero;
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.useDragThreshold = true;
|
||||
pointerEvent.pressPosition = pointerEvent.position;
|
||||
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
|
||||
|
||||
DeselectIfSelectionChanged(currentOverGo, pointerEvent);
|
||||
|
||||
if(pointerEvent.pointerEnter != currentOverGo) {
|
||||
// send a pointer enter to the touched element if it isn't the one to select...
|
||||
HandlePointerExitAndEnter(pointerEvent, currentOverGo);
|
||||
pointerEvent.pointerEnter = currentOverGo;
|
||||
}
|
||||
|
||||
// search for the control that will receive the press
|
||||
// if we can't find a press handler set the press
|
||||
// handler to be what would receive a click.
|
||||
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
|
||||
|
||||
// didnt find a press handler... search for a click handler
|
||||
if(newPressed == null)
|
||||
newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// Debug.Log("Pressed: " + newPressed);
|
||||
|
||||
float time = Time.unscaledTime;
|
||||
|
||||
if(newPressed == pointerEvent.lastPress) {
|
||||
var diffTime = time - pointerEvent.clickTime;
|
||||
if(diffTime < 0.3f)
|
||||
++pointerEvent.clickCount;
|
||||
else
|
||||
pointerEvent.clickCount = 1;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
} else {
|
||||
pointerEvent.clickCount = 1;
|
||||
}
|
||||
|
||||
pointerEvent.pointerPress = newPressed;
|
||||
pointerEvent.rawPointerPress = currentOverGo;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
|
||||
// Save the drag handler as well
|
||||
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);
|
||||
|
||||
if(pointerEvent.pointerDrag != null)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
|
||||
}
|
||||
|
||||
// PointerUp notification
|
||||
if(released) {
|
||||
// Debug.Log("Executing pressup on: " + pointer.pointerPress);
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
|
||||
|
||||
// Debug.Log("KeyCode: " + pointer.eventData.keyCode);
|
||||
|
||||
// see if we mouse up on the same element that we clicked on...
|
||||
var pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// PointerClick and Drop events
|
||||
if(pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick) {
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
|
||||
} else if(pointerEvent.pointerDrag != null && pointerEvent.dragging) {
|
||||
ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
|
||||
}
|
||||
|
||||
pointerEvent.eligibleForClick = false;
|
||||
pointerEvent.pointerPress = null;
|
||||
pointerEvent.rawPointerPress = null;
|
||||
|
||||
if(pointerEvent.pointerDrag != null && pointerEvent.dragging)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
|
||||
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.pointerDrag = null;
|
||||
|
||||
if(pointerEvent.pointerDrag != null)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
|
||||
|
||||
pointerEvent.pointerDrag = null;
|
||||
|
||||
// send exit events as we need to simulate this on touch up on touch device
|
||||
ExecuteEvents.ExecuteHierarchy(pointerEvent.pointerEnter, pointerEvent, ExecuteEvents.pointerExitHandler);
|
||||
pointerEvent.pointerEnter = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process submit keys.
|
||||
/// </summary>
|
||||
protected bool SendSubmitEventToSelectedObject() {
|
||||
if(eventSystem.currentSelectedGameObject == null)
|
||||
return false;
|
||||
|
||||
var state = GamePad.GetState(Player);
|
||||
var data = GetBaseEventData();
|
||||
if(state.Pressed(SubmitButton))
|
||||
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.submitHandler);
|
||||
|
||||
if(state.Pressed(CancelButton))
|
||||
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.cancelHandler);
|
||||
return data.used;
|
||||
}
|
||||
|
||||
private Vector2 GetMoveVector() {
|
||||
var x = GamePad.GetAxis(HorizontalAxis, Player);
|
||||
if(InvertHorizontal) x = -x;
|
||||
var y = GamePad.GetAxis(VerticalAxis, Player);
|
||||
if(InvertVertical) y = -y;
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
private Vector2 GetRawMoveVector() {
|
||||
Vector2 move = GetMoveVector();
|
||||
|
||||
if(HorizontalPressed) {
|
||||
if(move.x < 0)
|
||||
move.x = -1f;
|
||||
if(move.x > 0)
|
||||
move.x = 1f;
|
||||
}
|
||||
if(VerticalPressed) {
|
||||
if(move.y < 0)
|
||||
move.y = -1f;
|
||||
if(move.y > 0)
|
||||
move.y = 1f;
|
||||
}
|
||||
return move;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process keyboard events.
|
||||
/// </summary>
|
||||
protected bool SendMoveEventToSelectedObject() {
|
||||
float time = Time.unscaledTime;
|
||||
|
||||
Vector2 movement = GetRawMoveVector();
|
||||
if(Mathf.Approximately(movement.x, 0f) && Mathf.Approximately(movement.y, 0f)) {
|
||||
m_ConsecutiveMoveCount = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If user pressed key again, always allow event
|
||||
bool allow = HorizontalPressed || VerticalPressed;
|
||||
bool similarDir = (Vector2.Dot(movement, m_LastMoveVector) > 0);
|
||||
if(!allow) {
|
||||
// Otherwise, user held down key or axis.
|
||||
// If direction didn't change at least 90 degrees, wait for delay before allowing consequtive event.
|
||||
if(similarDir && m_ConsecutiveMoveCount == 1)
|
||||
allow = (time > m_PrevActionTime + m_RepeatDelay);
|
||||
// If direction changed at least 90 degree, or we already had the delay, repeat at repeat rate.
|
||||
else
|
||||
allow = (time > m_PrevActionTime + 1f / m_InputActionsPerSecond);
|
||||
}
|
||||
if(!allow)
|
||||
return false;
|
||||
|
||||
// Debug.Log(m_ProcessingEvent.rawType + " axis:" + m_AllowAxisEvents + " value:" + "(" + x + "," + y + ")");
|
||||
var axisEventData = GetAxisEventData(movement.x, movement.y, 0.6f);
|
||||
|
||||
if(axisEventData.moveDir != MoveDirection.None) {
|
||||
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, axisEventData, ExecuteEvents.moveHandler);
|
||||
if(!similarDir)
|
||||
m_ConsecutiveMoveCount = 0;
|
||||
m_ConsecutiveMoveCount++;
|
||||
m_PrevActionTime = time;
|
||||
m_LastMoveVector = movement;
|
||||
} else {
|
||||
m_ConsecutiveMoveCount = 0;
|
||||
}
|
||||
|
||||
return axisEventData.used;
|
||||
}
|
||||
|
||||
protected void ProcessMouseEvent() {
|
||||
ProcessMouseEvent(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process all mouse events.
|
||||
/// </summary>
|
||||
protected void ProcessMouseEvent(int id) {
|
||||
var mouseData = GetMousePointerEventData(id);
|
||||
var leftButtonData = mouseData.GetButtonState(PointerEventData.InputButton.Left).eventData;
|
||||
|
||||
// Process the first mouse button fully
|
||||
ProcessMousePress(leftButtonData);
|
||||
ProcessMove(leftButtonData.buttonData);
|
||||
ProcessDrag(leftButtonData.buttonData);
|
||||
|
||||
// Now process right / middle clicks
|
||||
ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData);
|
||||
ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Right).eventData.buttonData);
|
||||
ProcessMousePress(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData);
|
||||
ProcessDrag(mouseData.GetButtonState(PointerEventData.InputButton.Middle).eventData.buttonData);
|
||||
|
||||
if(!Mathf.Approximately(leftButtonData.buttonData.scrollDelta.sqrMagnitude, 0.0f)) {
|
||||
var scrollHandler = ExecuteEvents.GetEventHandler<IScrollHandler>(leftButtonData.buttonData.pointerCurrentRaycast.gameObject);
|
||||
ExecuteEvents.ExecuteHierarchy(scrollHandler, leftButtonData.buttonData, ExecuteEvents.scrollHandler);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool SendUpdateEventToSelectedObject() {
|
||||
if(eventSystem.currentSelectedGameObject == null)
|
||||
return false;
|
||||
|
||||
var data = GetBaseEventData();
|
||||
ExecuteEvents.Execute(eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler);
|
||||
return data.used;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process the current mouse press.
|
||||
/// </summary>
|
||||
protected void ProcessMousePress(MouseButtonEventData data) {
|
||||
var pointerEvent = data.buttonData;
|
||||
var currentOverGo = pointerEvent.pointerCurrentRaycast.gameObject;
|
||||
|
||||
// PointerDown notification
|
||||
if(data.PressedThisFrame()) {
|
||||
pointerEvent.eligibleForClick = true;
|
||||
pointerEvent.delta = Vector2.zero;
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.useDragThreshold = true;
|
||||
pointerEvent.pressPosition = pointerEvent.position;
|
||||
pointerEvent.pointerPressRaycast = pointerEvent.pointerCurrentRaycast;
|
||||
|
||||
DeselectIfSelectionChanged(currentOverGo, pointerEvent);
|
||||
|
||||
// search for the control that will receive the press
|
||||
// if we can't find a press handler set the press
|
||||
// handler to be what would receive a click.
|
||||
var newPressed = ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.pointerDownHandler);
|
||||
|
||||
// didnt find a press handler... search for a click handler
|
||||
if(newPressed == null)
|
||||
newPressed = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// Debug.Log("Pressed: " + newPressed);
|
||||
|
||||
float time = Time.unscaledTime;
|
||||
|
||||
if(newPressed == pointerEvent.lastPress) {
|
||||
var diffTime = time - pointerEvent.clickTime;
|
||||
if(diffTime < 0.3f)
|
||||
++pointerEvent.clickCount;
|
||||
else
|
||||
pointerEvent.clickCount = 1;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
} else {
|
||||
pointerEvent.clickCount = 1;
|
||||
}
|
||||
|
||||
pointerEvent.pointerPress = newPressed;
|
||||
pointerEvent.rawPointerPress = currentOverGo;
|
||||
|
||||
pointerEvent.clickTime = time;
|
||||
|
||||
// Save the drag handler as well
|
||||
pointerEvent.pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentOverGo);
|
||||
|
||||
if(pointerEvent.pointerDrag != null)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.initializePotentialDrag);
|
||||
}
|
||||
|
||||
// PointerUp notification
|
||||
if(data.ReleasedThisFrame()) {
|
||||
// Debug.Log("Executing pressup on: " + pointer.pointerPress);
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerUpHandler);
|
||||
|
||||
// Debug.Log("KeyCode: " + pointer.eventData.keyCode);
|
||||
|
||||
// see if we mouse up on the same element that we clicked on...
|
||||
var pointerUpHandler = ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentOverGo);
|
||||
|
||||
// PointerClick and Drop events
|
||||
if(pointerEvent.pointerPress == pointerUpHandler && pointerEvent.eligibleForClick) {
|
||||
ExecuteEvents.Execute(pointerEvent.pointerPress, pointerEvent, ExecuteEvents.pointerClickHandler);
|
||||
} else if(pointerEvent.pointerDrag != null && pointerEvent.dragging) {
|
||||
ExecuteEvents.ExecuteHierarchy(currentOverGo, pointerEvent, ExecuteEvents.dropHandler);
|
||||
}
|
||||
|
||||
pointerEvent.eligibleForClick = false;
|
||||
pointerEvent.pointerPress = null;
|
||||
pointerEvent.rawPointerPress = null;
|
||||
|
||||
if(pointerEvent.pointerDrag != null && pointerEvent.dragging)
|
||||
ExecuteEvents.Execute(pointerEvent.pointerDrag, pointerEvent, ExecuteEvents.endDragHandler);
|
||||
|
||||
pointerEvent.dragging = false;
|
||||
pointerEvent.pointerDrag = null;
|
||||
|
||||
// redo pointer enter / exit to refresh state
|
||||
// so that if we moused over somethign that ignored it before
|
||||
// due to having pressed on something else
|
||||
// it now gets it.
|
||||
if(currentOverGo != pointerEvent.pointerEnter) {
|
||||
HandlePointerExitAndEnter(pointerEvent, null);
|
||||
HandlePointerExitAndEnter(pointerEvent, currentOverGo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/CarbonInput/Scripts/CarbonInputModule.cs.meta
Normal file
12
Assets/CarbonInput/Scripts/CarbonInputModule.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c23f78a1d53c00e469381bd390575be4
|
||||
timeCreated: 1506844177
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Assets/CarbonInput/Scripts/CarbonInputRuntime.asmdef
Normal file
3
Assets/CarbonInput/Scripts/CarbonInputRuntime.asmdef
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "CarbonInputRuntime"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c04efb7064997fd46bdd8b7b41abab35
|
||||
timeCreated: 1565201667
|
||||
licenseType: Store
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
41
Assets/CarbonInput/Scripts/CarbonSettings.cs
Normal file
41
Assets/CarbonInput/Scripts/CarbonSettings.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// Used to store global settings for CarbonInput.
|
||||
/// </summary>
|
||||
[CreateAssetMenu(fileName = "CarbonInput", menuName = "Carbon Input/Settings", order = 100)]
|
||||
public class CarbonSettings : ScriptableObject {
|
||||
/// <summary>
|
||||
/// Defines the behaviour of PlayerIndex.Any
|
||||
/// </summary>
|
||||
[Tooltip("Defines the behaviour of PlayerIndex.Any")]
|
||||
public AnyBehaviour Behaviour = AnyBehaviour.CheckAll;
|
||||
/// <summary>
|
||||
/// Defines if any <see cref="CAxis"/> must be inverted.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
// ReSharper disable once InconsistentNaming
|
||||
private bool[] InvertedAxis = new bool[CarbonController.AxisCount];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the given axis to be inverted or not.
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
/// <returns></returns>
|
||||
public bool this[CAxis axis] {
|
||||
get { return InvertedAxis[(int)axis]; }
|
||||
set { InvertedAxis[(int)axis] = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will try to load the CarbonInput asset. If the asset is not found, it wil return a new CarbonSettings object.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static CarbonSettings Default() {
|
||||
CarbonSettings settings = Resources.Load<CarbonSettings>("CarbonInput");
|
||||
if(settings != null) return settings;
|
||||
return CreateInstance<CarbonSettings>();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/CarbonInput/Scripts/CarbonSettings.cs.meta
Normal file
12
Assets/CarbonInput/Scripts/CarbonSettings.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cd6a205b4f3e8440b49c91f90e95ea2
|
||||
timeCreated: 1455907889
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
19
Assets/CarbonInput/Scripts/ControllerInstance.cs
Normal file
19
Assets/CarbonInput/Scripts/ControllerInstance.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace CarbonInput {
|
||||
public class ControllerInstance {
|
||||
public CarbonController Controller;
|
||||
public int Index;
|
||||
|
||||
public ControllerInstance(CarbonController controller, int index) {
|
||||
Controller = controller;
|
||||
Index = index + 1;
|
||||
}
|
||||
|
||||
public bool GetButton(CButton button) {
|
||||
return Controller.GetButton(button, Index);
|
||||
}
|
||||
|
||||
public float GetAxis(CAxis axis) {
|
||||
return Controller.GetAxis(axis, Index);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Assets/CarbonInput/Scripts/ControllerInstance.cs.meta
Normal file
16
Assets/CarbonInput/Scripts/ControllerInstance.cs.meta
Normal file
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ce0c19a8201a5b41b3155e5fbd127d3
|
||||
labels:
|
||||
- Gamepad
|
||||
- Input
|
||||
- Joystick
|
||||
timeCreated: 1462002425
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
91
Assets/CarbonInput/Scripts/Enums.cs
Normal file
91
Assets/CarbonInput/Scripts/Enums.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
// ReSharper disable CheckNamespace
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the game controller associated with a player.
|
||||
/// </summary>
|
||||
public enum PlayerIndex {
|
||||
Any, One, Two, Three, Four, Five, Six, Seven, Eight
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a single button of a gamepad using the common XBox layout.
|
||||
/// </summary>
|
||||
public enum CButton {
|
||||
A, B, X, Y,
|
||||
Back, Start,
|
||||
LB, RB,
|
||||
LS, RS,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a single button of a gamepad using the playstation layout.
|
||||
/// </summary>
|
||||
public enum PSButton {
|
||||
Cross, Circle, Square, Triangle,
|
||||
Select, Start,
|
||||
L1, R1,
|
||||
//L2 and R2 are mapped by LT and RT
|
||||
L3, R3
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a single axis of a gamepad. The dpad is also considered an axis.
|
||||
/// </summary>
|
||||
public enum CAxis {
|
||||
LX, LY,
|
||||
RX, RY,
|
||||
LT, RT,
|
||||
DX, DY
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flag mapping used to define all supported platforms.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CPlatform {
|
||||
Windows = 1 << 0,
|
||||
Linux = 1 << 1,
|
||||
OSX = 1 << 2,
|
||||
WSA = 1 << 3,
|
||||
Android = 1 << 4,
|
||||
IOS = 1 << 5,
|
||||
[Obsolete] WP8 = 1 << 6,
|
||||
Wii = 1 << 7,
|
||||
[Obsolete] XBox360 = 1 << 8,
|
||||
XBoxOne = 1 << 9,
|
||||
[Obsolete] PS3 = 1 << 10,
|
||||
PS4 = 1 << 11,
|
||||
PSP2 = 1 << 12,
|
||||
WebGL = 1 << 13
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration of all sticks of a gamepad. Used to get a <see cref="Vector2"/> consisting of the corresponding x and y values of a given axis.
|
||||
/// </summary>
|
||||
public enum CStick {
|
||||
Left, Right, DPad
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes the different behaviours of <see cref="PlayerIndex.Any"/>.
|
||||
/// </summary>
|
||||
public enum AnyBehaviour {
|
||||
/// <summary>
|
||||
/// Use the same mapping <see cref="PlayerIndex.One"/> uses, but listen on any gamepad for that mapping.
|
||||
/// </summary>
|
||||
UseMappingOne,
|
||||
/// <summary>
|
||||
/// Always use <see cref="PlayerIndex.One"/> whenever <see cref="PlayerIndex.Any"/> is used.
|
||||
/// </summary>
|
||||
UseControllerOne,
|
||||
/// <summary>
|
||||
/// Go over all players and use first match.
|
||||
/// Slightly slower than the other two behaviours, but it is the most accurate.
|
||||
/// </summary>
|
||||
CheckAll
|
||||
}
|
||||
|
||||
12
Assets/CarbonInput/Scripts/Enums.cs.meta
Normal file
12
Assets/CarbonInput/Scripts/Enums.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 254fffb768b22e0498fb4bdbb3d0a031
|
||||
timeCreated: 1455636603
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
297
Assets/CarbonInput/Scripts/GamePad.cs
Normal file
297
Assets/CarbonInput/Scripts/GamePad.cs
Normal file
@@ -0,0 +1,297 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using CarbonInput;
|
||||
|
||||
/// <summary>
|
||||
/// Interface to the carbon controller input system.
|
||||
/// </summary>
|
||||
// ReSharper disable once CheckNamespace
|
||||
// ReSharper disable InconsistentNaming
|
||||
public static class GamePad {
|
||||
public delegate void OnReloadEvent();
|
||||
/// <summary>
|
||||
/// This event is fired when a reload has happened.
|
||||
/// </summary>
|
||||
public static event OnReloadEvent OnReload;
|
||||
/// <summary>
|
||||
/// Used for lazy initialization.
|
||||
/// </summary>
|
||||
private static bool IsInitialized;
|
||||
/// <summary>
|
||||
/// Array of all mappings supporting this platform.
|
||||
/// </summary>
|
||||
private static CarbonController[] AllMappings;
|
||||
/// <summary>
|
||||
/// One mapping for each player, including <see cref="PlayerIndex.Any"/> (index 0).
|
||||
/// </summary>
|
||||
private static ControllerInstance[] PlayerMappings;
|
||||
/// <summary>
|
||||
/// <see cref="GamePadState"/>s of all players.
|
||||
/// </summary>
|
||||
private static readonly GamePadState[] States = new GamePadState[CarbonController.PlayerIndices];
|
||||
/// <summary>
|
||||
/// Number of connected and supported hardware gamepads, without TouchInput/Keyboard.
|
||||
/// </summary>
|
||||
private static int gamepadCount;
|
||||
/// <summary>
|
||||
/// Number of connected and supported hardware gamepads, without TouchInput/Keyboard.
|
||||
/// </summary>
|
||||
public static int GamePadCount { get { if(!IsInitialized) Initialize(); return gamepadCount; } }
|
||||
|
||||
/// <summary>
|
||||
/// Used to store settings like <see cref="AnyBehaviour"/> and inverted axes.
|
||||
/// </summary>
|
||||
private static CarbonSettings settings;
|
||||
/// <summary>
|
||||
/// Used to store settings like <see cref="AnyBehaviour"/> and inverted axes.
|
||||
/// </summary>
|
||||
public static CarbonSettings Settings {
|
||||
get {
|
||||
if(!IsInitialized) Initialize();
|
||||
return settings;
|
||||
}
|
||||
set {
|
||||
if(!IsInitialized) Initialize();
|
||||
settings = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly CarbonController disabledInput = CarbonController.CreateDisabledInput();
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array of all mappings supported by this platform.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static CarbonController[] GetAllMappings() {
|
||||
if(!IsInitialized) Initialize();
|
||||
return AllMappings;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns an array of all player mappings. Index 0 is the mapping for <see cref="PlayerIndex.Any"/> and indices 1 to 8 meant to
|
||||
/// reference <see cref="PlayerIndex.One"/> to <see cref="PlayerIndex.Eight"/>.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static ControllerInstance[] GetPlayerMappings() {
|
||||
if(!IsInitialized) Initialize();
|
||||
return PlayerMappings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reinitializes all GamePads.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this library by loading all mappings from file and matching the given gamepads.
|
||||
/// </summary>
|
||||
private static void Initialize() {
|
||||
if(!IsInitialized) { // first init
|
||||
new GameObject("GamePad ReInit").AddComponent<ReInit>();
|
||||
}
|
||||
List<CarbonController> mappings = new List<CarbonController>(Resources.LoadAll<CarbonController>("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<ControllerInstance> matches = new List<ControllerInstance>();
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the mapping used by player <paramref name="id"/>.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static ControllerInstance GetMapping(PlayerIndex id) {
|
||||
if(!IsInitialized) Initialize();
|
||||
return PlayerMappings[(int)id];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if there is any real gamepad connected.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static bool AnyConnected() {
|
||||
if(!IsInitialized) Initialize();
|
||||
return gamepadCount > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the state of button <paramref name="btn"/> of player <paramref name="id"/>.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the state of button <paramref name="btn"/> of player <paramref name="id"/> using a playstation controller layout.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetButton(PSButton btn, PlayerIndex id = PlayerIndex.Any) {
|
||||
return GetButton((CButton)btn, id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <paramref name="axis"/> of player <paramref name="id"/>. The result is in range [-1, 1], except for the two triggers.
|
||||
/// They are in range [0, 1].
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="Vector2"/> for the specified stick of player <paramref name="id"/>.
|
||||
/// </summary>
|
||||
/// <param name="stick"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector for the left thumbstick of player <paramref name="id"/>.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector2 GetLeftStick(PlayerIndex id = PlayerIndex.Any) {
|
||||
return new Vector2(GetAxis(CAxis.LX, id), GetAxis(CAxis.LY, id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector for the right thumbstick of player <paramref name="id"/>.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector2 GetRightStick(PlayerIndex id = PlayerIndex.Any) {
|
||||
return new Vector2(GetAxis(CAxis.RX, id), GetAxis(CAxis.RY, id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the left trigger of player <paramref name="id"/>. Result is in range [0, 1].
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static float GetLeftTrigger(PlayerIndex id = PlayerIndex.Any) {
|
||||
return GetAxis(CAxis.LT, id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the right trigger of player <paramref name="id"/>. Result is in range [0, 1].
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static float GetRightTrigger(PlayerIndex id = PlayerIndex.Any) {
|
||||
return GetAxis(CAxis.RT, id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a vector for the dpad of player <paramref name="id"/>.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static Vector2 GetDPad(PlayerIndex id = PlayerIndex.Any) {
|
||||
return new Vector2(GetAxis(CAxis.DX, id), GetAxis(CAxis.DY, id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the state of player <paramref name="id"/>.
|
||||
/// A <see cref="GamePadState"/> 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.
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public static GamePadState GetState(PlayerIndex id = PlayerIndex.Any) {
|
||||
if(!IsInitialized) Initialize();
|
||||
GamePadState state = States[(int)id];
|
||||
state.Update();
|
||||
return state;
|
||||
}
|
||||
}
|
||||
16
Assets/CarbonInput/Scripts/GamePad.cs.meta
Normal file
16
Assets/CarbonInput/Scripts/GamePad.cs.meta
Normal file
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9d410e5e689bdf4e8770d6a55f96bc4
|
||||
labels:
|
||||
- Gamepad
|
||||
- Input
|
||||
- Joystick
|
||||
timeCreated: 1455633863
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
262
Assets/CarbonInput/Scripts/GamePadState.cs
Normal file
262
Assets/CarbonInput/Scripts/GamePadState.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
using UnityEngine;
|
||||
using CarbonInput;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the current state of a specific gamepad.
|
||||
/// The state of any button can be accessed by the attributes <see cref="A"/>, <see cref="B"/>,... or via the method <see cref="Button(CButton)"/>. <para/>
|
||||
/// <see cref="Pressed(CButton)"/> returns true during the frame it was pressed. <para/>
|
||||
/// <see cref="Released(CButton)"/> returns true during the frame it was released. <para/>
|
||||
/// <see cref="Left"/>, <see cref="Right"/> and <see cref="DPad"/> will give you direct access to the corresponding axes.
|
||||
/// The trigger can be accessed by <see cref="LT"/> and <see cref="RT"/>.
|
||||
/// </summary>
|
||||
// ReSharper disable once CheckNamespace
|
||||
// ReSharper disable InconsistentNaming
|
||||
public class GamePadState {
|
||||
/// <summary>
|
||||
/// Any axis is being considered "pressed" if it's absolute value is greater than this threshold.
|
||||
/// </summary>
|
||||
private const float AxisPressedThreshold = 0.3f;
|
||||
|
||||
#region Buttons
|
||||
/// <summary>
|
||||
/// Stores the state of all buttons from the last frame.
|
||||
/// </summary>
|
||||
private bool[] LastFrameButtons = new bool[CarbonController.ButtonCount];
|
||||
/// <summary>
|
||||
/// Stores the state of all buttons from this frame.
|
||||
/// </summary>
|
||||
private bool[] Buttons = new bool[CarbonController.ButtonCount];
|
||||
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.A"/> is pressed.
|
||||
/// </summary>
|
||||
public bool A { get { return Buttons[(int)CButton.A]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.B"/> is pressed.
|
||||
/// </summary>
|
||||
public bool B { get { return Buttons[(int)CButton.B]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.X"/> is pressed.
|
||||
/// </summary>
|
||||
public bool X { get { return Buttons[(int)CButton.X]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.Y"/> is pressed.
|
||||
/// </summary>
|
||||
public bool Y { get { return Buttons[(int)CButton.Y]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.Back"/> is pressed.
|
||||
/// </summary>
|
||||
public bool Back { get { return Buttons[(int)CButton.Back]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.Start"/> is pressed.
|
||||
/// </summary>
|
||||
public bool Start { get { return Buttons[(int)CButton.Start]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.LB"/> is pressed.
|
||||
/// </summary>
|
||||
public bool LB { get { return Buttons[(int)CButton.LB]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.RB"/> is pressed.
|
||||
/// </summary>
|
||||
public bool RB { get { return Buttons[(int)CButton.RB]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.LS"/> is pressed.
|
||||
/// </summary>
|
||||
public bool LS { get { return Buttons[(int)CButton.LS]; } }
|
||||
/// <summary>
|
||||
/// Is true while <see cref="CButton.RS"/> is pressed.
|
||||
/// </summary>
|
||||
public bool RS { get { return Buttons[(int)CButton.RS]; } }
|
||||
#endregion
|
||||
|
||||
#region Axis
|
||||
/// <summary>
|
||||
/// Stores the state of all axis values from the last frame.
|
||||
/// </summary>
|
||||
private float[] LastAxis = new float[CarbonController.AxisCount];
|
||||
/// <summary>
|
||||
/// Stores the state of all axis values from this frame.
|
||||
/// </summary>
|
||||
private float[] Axis = new float[CarbonController.AxisCount];
|
||||
|
||||
/// <summary>
|
||||
/// X and Y axis of the left thumbstick.
|
||||
/// </summary>
|
||||
public Vector2 Left { get { return new Vector2(Axis[(int)CAxis.LX], Axis[(int)CAxis.LY]); } }
|
||||
/// <summary>
|
||||
/// X and Y axis of the right thumbstick.
|
||||
/// </summary>
|
||||
public Vector2 Right { get { return new Vector2(Axis[(int)CAxis.RX], Axis[(int)CAxis.RY]); } }
|
||||
/// <summary>
|
||||
/// Left trigger.
|
||||
/// </summary>
|
||||
public float LT { get { return Axis[(int)CAxis.LT]; } }
|
||||
/// <summary>
|
||||
/// Right trigger.
|
||||
/// </summary>
|
||||
public float RT { get { return Axis[(int)CAxis.RT]; } }
|
||||
/// <summary>
|
||||
/// X and Y axis of the dpad.
|
||||
/// </summary>
|
||||
public Vector2 DPad { get { return new Vector2(Axis[(int)CAxis.DX], Axis[(int)CAxis.DY]); } }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Defines the owner of this <see cref="GamePadState"/>.
|
||||
/// </summary>
|
||||
private readonly PlayerIndex Index;
|
||||
/// <summary>
|
||||
/// Number of the last frame, used to determine if we're in a new frame or not.
|
||||
/// </summary>
|
||||
private int LastFrame;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the button state has changed since the last frame.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <returns></returns>
|
||||
public bool HasChanged(CButton btn) { return Buttons[(int)btn] != LastFrameButtons[(int)btn]; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true while the button is pressed.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <returns></returns>
|
||||
public bool Button(CButton btn) { return Buttons[(int)btn]; }
|
||||
/// <summary>
|
||||
/// Returns true during the frame the user pressed the button.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <returns></returns>
|
||||
public bool Pressed(CButton btn) { return Buttons[(int)btn] && !LastFrameButtons[(int)btn]; }
|
||||
/// <summary>
|
||||
/// Returns true during the frame the user released the button.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <returns></returns>
|
||||
public bool Released(CButton btn) { return !Buttons[(int)btn] && LastFrameButtons[(int)btn]; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true while the axis is "pressed", which is if the absolute value of this axis is greater than a certain threshold.
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
/// <returns></returns>
|
||||
public bool Button(CAxis axis) {
|
||||
return Mathf.Abs(Axis[(int)axis]) > AxisPressedThreshold;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns true during the frame the axis is "pressed", which is if the absolute value of this axis is greater than a certain threshold.
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
/// <returns></returns>
|
||||
public bool Pressed(CAxis axis) {
|
||||
bool pressedNow = Mathf.Abs(Axis[(int)axis]) > AxisPressedThreshold;
|
||||
bool pressedLastFrame = Mathf.Abs(LastAxis[(int)axis]) > AxisPressedThreshold;
|
||||
return pressedNow && !pressedLastFrame;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns true during the frame the axis is no longer "pressed", which is if the absolute value of this axis is greater than a certain threshold.
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
/// <returns></returns>
|
||||
public bool Released(CAxis axis) {
|
||||
bool pressedNow = Mathf.Abs(Axis[(int)axis]) > AxisPressedThreshold;
|
||||
bool pressedLastFrame = Mathf.Abs(LastAxis[(int)axis]) > AxisPressedThreshold;
|
||||
return !pressedNow && pressedLastFrame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the given axis.
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
/// <returns></returns>
|
||||
public float GetAxis(CAxis axis) {
|
||||
return Axis[(int)axis];
|
||||
}
|
||||
|
||||
#region PSButton
|
||||
/// <summary>
|
||||
/// Returns true while the button is pressed.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <returns></returns>
|
||||
public bool Button(PSButton btn) { return Button((CButton)btn); }
|
||||
/// <summary>
|
||||
/// Returns true during the frame the user pressed the button.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <returns></returns>
|
||||
public bool Pressed(PSButton btn) { return Pressed((CButton)btn); }
|
||||
/// <summary>
|
||||
/// Returns true during the frame the user released the button.
|
||||
/// </summary>
|
||||
/// <param name="btn"></param>
|
||||
/// <returns></returns>
|
||||
public bool Released(PSButton btn) { return Released((CButton)btn); }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if any button is currently pressed.
|
||||
/// </summary>
|
||||
public bool AnyButton { get; private set; }
|
||||
/// <summary>
|
||||
/// Returns true if any axis is currently not zero.
|
||||
/// </summary>
|
||||
public bool AnyAxis { get; private set; }
|
||||
/// <summary>
|
||||
/// Returns true if any button is currently pressed or if any axis is currently not zero.
|
||||
/// </summary>
|
||||
public bool AnyButtonOrAxis { get { return AnyButton || AnyAxis; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a button that is currently pressed or null if no buttons are pressed.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public CButton? GetAnyButton() {
|
||||
for(int i = 0; i < CarbonController.ButtonCount; i++)
|
||||
if(Buttons[i]) return (CButton)i;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an axis that is not zero or null if all axis are zero.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public CAxis? GetAnyAxis() {
|
||||
for(int i = 0; i < CarbonController.AxisCount; i++)
|
||||
if(Mathf.Abs(Axis[i]) > AxisPressedThreshold) return (CAxis)i;
|
||||
return null;
|
||||
}
|
||||
|
||||
public GamePadState(PlayerIndex id) {
|
||||
Index = id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will update all buttons and axes of this instance.
|
||||
/// Multiple calls in the same frame won't have any effect.
|
||||
/// </summary>
|
||||
public void Update() {
|
||||
if(LastFrame == Time.frameCount) return;
|
||||
LastFrame = Time.frameCount;
|
||||
SwapArrays();
|
||||
AnyButton = false;
|
||||
for(int i = 0; i < Buttons.Length; i++) {
|
||||
AnyButton |= (Buttons[i] = GamePad.GetButton((CButton)i, Index));
|
||||
}
|
||||
AnyAxis = false;
|
||||
for(int i = 0; i < Axis.Length; i++) {
|
||||
AnyAxis |= Mathf.Abs(Axis[i] = GamePad.GetAxis((CAxis)i, Index)) > AxisPressedThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
private void SwapArrays() {
|
||||
bool[] tmp = LastFrameButtons;
|
||||
LastFrameButtons = Buttons;
|
||||
Buttons = tmp;
|
||||
|
||||
float[] axis = LastAxis;
|
||||
LastAxis = Axis;
|
||||
Axis = axis;
|
||||
}
|
||||
}
|
||||
16
Assets/CarbonInput/Scripts/GamePadState.cs.meta
Normal file
16
Assets/CarbonInput/Scripts/GamePadState.cs.meta
Normal file
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b67ce27dec0bf414c8f69f7def8a1077
|
||||
labels:
|
||||
- Gamepad
|
||||
- Input
|
||||
- Joystick
|
||||
timeCreated: 1455696443
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
152
Assets/CarbonInput/Scripts/Mappings.cs
Normal file
152
Assets/CarbonInput/Scripts/Mappings.cs
Normal file
@@ -0,0 +1,152 @@
|
||||
using UnityEngine;
|
||||
|
||||
// User don't have to use this directly, so there is no need to have this in global namespace
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// Describes a mapping for a single gamepad button.
|
||||
/// For normal gamepads, IsWrapper is false and therefor the Button attribute is used.
|
||||
/// If IsWrapper is set to true, the KeyCode is used.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class ButtonMapping {
|
||||
/// <summary>
|
||||
/// If <see cref="Type"/> is <see cref="ButtonType.Default"/> this is the joystick button id.
|
||||
/// </summary>
|
||||
public int Button;
|
||||
/// <summary>
|
||||
/// If <see cref="Type"/> is <see cref="ButtonType.Wrapper"/> this is the key used to emulate this gamepad button.
|
||||
/// </summary>
|
||||
public KeyCode Key;
|
||||
/// <summary>
|
||||
/// Defines if this mapping is a wrapper or not.
|
||||
/// </summary>
|
||||
public ButtonType Type = ButtonType.Default;
|
||||
|
||||
public ButtonMapping() { }
|
||||
/// <summary>
|
||||
/// Copy constructor.
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
public ButtonMapping(ButtonMapping other) { CopyFrom(other); }
|
||||
|
||||
/// <summary>
|
||||
/// Copy all values from the parameter.
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
public void CopyFrom(ButtonMapping other) {
|
||||
Button = other.Button;
|
||||
Key = other.Key;
|
||||
Type = other.Type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines if a button is wrapper or not.
|
||||
/// </summary>
|
||||
public enum ButtonType {
|
||||
/// <summary>
|
||||
/// Button is a real gamepad button.
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// Uses a keyboard key to emulate a gamepad button.
|
||||
/// </summary>
|
||||
Wrapper
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes a mapping for a single gamepad axis.
|
||||
/// Every axis can be inverted.
|
||||
/// </summary>
|
||||
[System.Serializable]
|
||||
public class AxisMapping {
|
||||
/// <summary>
|
||||
/// Index of gamepad axis, used if Type is Default or Clamped.
|
||||
/// Used as button index if Type is ButtonWrapper or ButtonWrapper2.
|
||||
/// </summary>
|
||||
public int Axis;
|
||||
/// <summary>
|
||||
/// Only used if Type is ButtonWrapper2.
|
||||
/// Button index for positive value.
|
||||
/// </summary>
|
||||
public int Alternative;
|
||||
/// <summary>
|
||||
/// Whether this axis will be inverted.
|
||||
/// </summary>
|
||||
public bool Invert = false;
|
||||
/// <summary>
|
||||
/// Defines how this mapping behaves.
|
||||
/// </summary>
|
||||
public AxisType Type = AxisType.Default;
|
||||
/// <summary>
|
||||
/// If Type is ButtonWrapper, this is the value returned if the button is not pressed.
|
||||
/// If Type is Clamped, this is the lower bound of the axis.
|
||||
/// </summary>
|
||||
public float Min = 0.0f;
|
||||
/// <summary>
|
||||
/// If Type is ButtonWrapper, this is the value returned if the button is pressed.
|
||||
/// If Type is Clamped, this is the upper bound of the axis.
|
||||
/// </summary>
|
||||
public float Max = 1.0f;
|
||||
/// <summary>
|
||||
/// Used for KeyWrapper. Axis value is -1 if this key is pressed and Key2 is not pressed.
|
||||
/// </summary>
|
||||
public KeyCode Key1;
|
||||
/// <summary>
|
||||
/// Used for KeyWrapper. Axis value is 1 if this key is pressed and Key1 is not pressed.
|
||||
/// </summary>
|
||||
public KeyCode Key2;
|
||||
|
||||
public AxisMapping() { }
|
||||
/// <summary>
|
||||
/// Copy constructor.
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
public AxisMapping(AxisMapping other) { CopyFrom(other); }
|
||||
|
||||
/// <summary>
|
||||
/// Copy all values from the parameter.
|
||||
/// </summary>
|
||||
/// <param name="other"></param>
|
||||
public void CopyFrom(AxisMapping other) {
|
||||
Axis = other.Axis;
|
||||
Alternative = other.Alternative;
|
||||
Invert = other.Invert;
|
||||
Type = other.Type;
|
||||
Min = other.Min;
|
||||
Max = other.Max;
|
||||
Key1 = other.Key1;
|
||||
Key2 = other.Key2;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration of all possible axis types.
|
||||
/// </summary>
|
||||
public enum AxisType {
|
||||
/// <summary>
|
||||
/// Axis is a normal gamepad axis.
|
||||
/// </summary>
|
||||
Default,
|
||||
/// <summary>
|
||||
/// Gamepad does not have this axis, but it has a button for that axis
|
||||
/// </summary>
|
||||
ButtonWrapper,
|
||||
/// <summary>
|
||||
/// Gamepad does not have anything for this, fallback to KeyCodes
|
||||
/// </summary>
|
||||
KeyWrapper,
|
||||
/// <summary>
|
||||
/// The range of this axis is not in the normal range.
|
||||
/// </summary>
|
||||
Clamped,
|
||||
/// <summary>
|
||||
/// Gamepad does not have this axis, but it can be emulated by two buttons.
|
||||
/// </summary>
|
||||
ButtonWrapper2,
|
||||
/// <summary>
|
||||
/// Gamepad axis goes from -1 to 1, but it should go from 0 to 1.
|
||||
/// </summary>
|
||||
TriggerLimiter
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Assets/CarbonInput/Scripts/Mappings.cs.meta
Normal file
16
Assets/CarbonInput/Scripts/Mappings.cs.meta
Normal file
@@ -0,0 +1,16 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3be0fab311c3f9646b6a78261d1e628a
|
||||
labels:
|
||||
- Gamepad
|
||||
- Input
|
||||
- Joystick
|
||||
timeCreated: 1455638035
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
44
Assets/CarbonInput/Scripts/ReInit.cs
Normal file
44
Assets/CarbonInput/Scripts/ReInit.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// This class will check if a new gamepad was connected or if a gamepad lost its connection.
|
||||
/// If this is the case, they are reinitialized.
|
||||
/// </summary>
|
||||
public class ReInit : MonoBehaviour {
|
||||
private string[] _names;
|
||||
|
||||
void Start() {
|
||||
_names = Input.GetJoystickNames();
|
||||
StartCoroutine(CheckRoutine());
|
||||
DontDestroyOnLoad(gameObject);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks once a second if any gamepad has lost connection or was reconnected.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private IEnumerator CheckRoutine() {
|
||||
yield return new WaitForSeconds(0.25f);
|
||||
// On UWP platform Unity needs a few milliseconds to init all gamepads,
|
||||
// therefore it might be the case that they will be initilized now
|
||||
while(true) {
|
||||
if(JoysticksChanged()) {
|
||||
_names = Input.GetJoystickNames();
|
||||
GamePad.ReInit();
|
||||
}
|
||||
yield return new WaitForSeconds(1f);
|
||||
}
|
||||
}
|
||||
|
||||
private bool JoysticksChanged() {
|
||||
var names = Input.GetJoystickNames();
|
||||
if(names.Length != _names.Length) return true;
|
||||
for(var i = 0; i < names.Length; i++) {
|
||||
if(names[i] != _names[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/CarbonInput/Scripts/ReInit.cs.meta
Normal file
12
Assets/CarbonInput/Scripts/ReInit.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8625f2a23b7973242b753f01cf6d7131
|
||||
timeCreated: 1483358527
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
32
Assets/CarbonInput/Scripts/SwitchPS4Gamepad.cs
Normal file
32
Assets/CarbonInput/Scripts/SwitchPS4Gamepad.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace CarbonInput {
|
||||
public class SwitchPS4Gamepad : MonoBehaviour {
|
||||
public CarbonController Wired;
|
||||
public CarbonController Bluetooth;
|
||||
public Toggle Toggle;
|
||||
|
||||
private int highPriority;
|
||||
private int lowPriority;
|
||||
|
||||
private void Start() {
|
||||
highPriority = Mathf.Min(Wired.Priority, Bluetooth.Priority);
|
||||
lowPriority = Mathf.Max(Wired.Priority, Bluetooth.Priority);
|
||||
if(Toggle != null) {
|
||||
Toggle.isOn = Bluetooth.Priority < Wired.Priority;
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeMapping(bool useBluetooth) {
|
||||
if(useBluetooth) {
|
||||
Bluetooth.Priority = highPriority;
|
||||
Wired.Priority = lowPriority;
|
||||
} else {
|
||||
Wired.Priority = highPriority;
|
||||
Bluetooth.Priority = lowPriority;
|
||||
}
|
||||
GamePad.ReInit();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/CarbonInput/Scripts/SwitchPS4Gamepad.cs.meta
Normal file
12
Assets/CarbonInput/Scripts/SwitchPS4Gamepad.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93d840a09c7ea71489775748bfc05d32
|
||||
timeCreated: 1523470047
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/CarbonInput/Scripts/TouchInput.meta
Normal file
9
Assets/CarbonInput/Scripts/TouchInput.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae75e61147db4204ca8bc1fcfc536818
|
||||
folderAsset: yes
|
||||
timeCreated: 1455826393
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
53
Assets/CarbonInput/Scripts/TouchInput/BaseTouchInput.cs
Normal file
53
Assets/CarbonInput/Scripts/TouchInput/BaseTouchInput.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// Base class for all touch controls.
|
||||
/// </summary>
|
||||
public class BaseTouchInput : MonoBehaviour {
|
||||
/// <summary>
|
||||
/// The index of the player this control belongs to. If set to Any, it will use the first free player.
|
||||
/// </summary>
|
||||
[Tooltip("The index of the player this control belongs to. If set to Any, it will use the first free player.")]
|
||||
public PlayerIndex Index;
|
||||
/// <summary>
|
||||
/// Mapping of this control.
|
||||
/// </summary>
|
||||
protected TouchMapping Mapping;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize this input by injecting a <see cref="TouchMapping"/> into <see cref="GamePad.PlayerMappings"/>.
|
||||
/// </summary>
|
||||
protected void InitMapping() {
|
||||
if(Index == PlayerIndex.Any) {
|
||||
ControllerInstance[] mappings = GamePad.GetPlayerMappings();
|
||||
for(int i = 1; i < CarbonController.PlayerIndices; i++) {
|
||||
if(mappings[i].Controller.Replacable || mappings[i].Controller is TouchMapping) {
|
||||
UseMapping(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// all mappings already in use
|
||||
} else {
|
||||
UseMapping((int)Index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes index <paramref name="idx"/> of the <see cref="GamePad.PlayerMappings"/> to a <see cref="TouchMapping"/>.
|
||||
/// </summary>
|
||||
/// <param name="idx"></param>
|
||||
private void UseMapping(int idx) {
|
||||
ControllerInstance[] mappings = GamePad.GetPlayerMappings();
|
||||
// if there is already a TouchMapping, use it.
|
||||
if(mappings[idx] != null && mappings[idx].Controller is TouchMapping)
|
||||
Mapping = (TouchMapping)mappings[idx].Controller;
|
||||
else {//otherwise overwrite the old value
|
||||
Mapping = ScriptableObject.CreateInstance<TouchMapping>();
|
||||
mappings[idx] = new ControllerInstance(Mapping, 0);
|
||||
}
|
||||
// if we set PlayerIndex.One, we must also set PlayerIndex.Any, because AnyBehaviour.UseMappingOne needs this
|
||||
if(idx == 1) mappings[0] = mappings[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Assets/CarbonInput/Scripts/TouchInput/BaseTouchInput.cs.meta
Normal file
18
Assets/CarbonInput/Scripts/TouchInput/BaseTouchInput.cs.meta
Normal file
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 996c12ad06e1905499f873d083ef1fb0
|
||||
labels:
|
||||
- Touchinput
|
||||
- Touch
|
||||
- Input
|
||||
- Gamepad
|
||||
- Joystick
|
||||
timeCreated: 1455829286
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
44
Assets/CarbonInput/Scripts/TouchInput/DisableTouchInput.cs
Normal file
44
Assets/CarbonInput/Scripts/TouchInput/DisableTouchInput.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// Attach this to the canvas all touch controls are in.
|
||||
/// On startup this script will check if there are any real gamepads and if so, it will disable the touch controls.
|
||||
/// </summary>
|
||||
public class DisableTouchInput : MonoBehaviour {
|
||||
[Tooltip("If true, touch controls will be disabled on Console Platforms, even if there are no gamepads connected.")]
|
||||
public bool HideOnConsole = true;
|
||||
[Tooltip("If true, touch controls will be disabled in Web Player, even if there are no gamepads connected.")]
|
||||
public bool HideOnWeb = true;
|
||||
[Tooltip("If true, touch controls will be disabled in the Editor, even if there are no gamepads connected.")]
|
||||
public bool HideOnEditMode = false;
|
||||
[Tooltip("If true, touch controls will be disabled on Windows, Linux and Mac, even if there are no gamepads connected.")]
|
||||
public bool HideOnPC = true;
|
||||
void Start() {
|
||||
#if UNITY_EDITOR
|
||||
if(HideOnEditMode) { Hide(); return; }
|
||||
#endif
|
||||
#if UNITY_WEB
|
||||
if(HideOnWeb) { Hide(); return; }
|
||||
#endif
|
||||
#if UNITY_STANDALONE
|
||||
if(HideOnPC) { Hide(); return; }
|
||||
#endif
|
||||
if(HideOnConsole && Application.isConsolePlatform
|
||||
|| GamePad.GamePadCount > 0) { // There are gamepads so we don't need touchcontrols
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deactivates all children with a <see cref="BaseTouchInput"/> component.
|
||||
/// </summary>
|
||||
private void Hide() {
|
||||
// Iterate over all children
|
||||
foreach(RectTransform rect in GetComponentsInChildren<RectTransform>()) {
|
||||
if(rect.GetComponent<BaseTouchInput>() != null) // Deactivate all TouchControls
|
||||
rect.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8fff0c72c46bce4e827c2d00d47911f
|
||||
labels:
|
||||
- Touchinput
|
||||
- Touch
|
||||
- Input
|
||||
- Gamepad
|
||||
- Joystick
|
||||
timeCreated: 1456010930
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
57
Assets/CarbonInput/Scripts/TouchInput/TouchButton.cs
Normal file
57
Assets/CarbonInput/Scripts/TouchInput/TouchButton.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// Touch control simulating a single gamepad button.
|
||||
/// </summary>
|
||||
public class TouchButton : BaseTouchInput, IPointerDownHandler, IPointerUpHandler, IDragHandler {
|
||||
/// <summary>
|
||||
/// The <see cref="CButton"/> this control emulates.
|
||||
/// </summary>
|
||||
public CButton Button;
|
||||
/// <summary>
|
||||
/// Opacity of this control if it is pressed.
|
||||
/// </summary>
|
||||
[Tooltip("Opacity of this control if it is pressed.")]
|
||||
[Range(0, 1)]
|
||||
public float OpacityPressed = 0.5f;
|
||||
/// <summary>
|
||||
/// Opacity of this control if it is not pressed.
|
||||
/// </summary>
|
||||
[Tooltip("Opacity of this control if it is not pressed.")]
|
||||
[Range(0, 1)]
|
||||
public float OpacityReleased = 1f;
|
||||
|
||||
void Start() {
|
||||
InitMapping();
|
||||
UpdateState(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the state of this control. This methods sets the opacity and the state in the <see cref="TouchMapping"/>.
|
||||
/// </summary>
|
||||
/// <param name="pressed"></param>
|
||||
public void UpdateState(bool pressed) {
|
||||
var image = GetComponent<Image>();
|
||||
var color = image.color;
|
||||
color.a = pressed ? OpacityPressed : OpacityReleased;
|
||||
image.color = color;
|
||||
if(Mapping != null) Mapping[Button] = pressed;
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData eventData) {
|
||||
UpdateState(true);
|
||||
}
|
||||
|
||||
public void OnPointerUp(PointerEventData eventData) {
|
||||
UpdateState(false);
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData eventData) {
|
||||
RectTransform rect = GetComponent<RectTransform>();
|
||||
UpdateState(RectTransformUtility.RectangleContainsScreenPoint(rect, eventData.position));
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Assets/CarbonInput/Scripts/TouchInput/TouchButton.cs.meta
Normal file
18
Assets/CarbonInput/Scripts/TouchInput/TouchButton.cs.meta
Normal file
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d698f325b18cad948af4abeae474734d
|
||||
labels:
|
||||
- Touchinput
|
||||
- Touch
|
||||
- Input
|
||||
- Gamepad
|
||||
- Joystick
|
||||
timeCreated: 1455826413
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
45
Assets/CarbonInput/Scripts/TouchInput/TouchMapping.cs
Normal file
45
Assets/CarbonInput/Scripts/TouchInput/TouchMapping.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// Internal wrapper class, used to access touch input.
|
||||
/// </summary>
|
||||
public class TouchMapping : CarbonController {
|
||||
/// <summary>
|
||||
/// Currently pressed buttons.
|
||||
/// </summary>
|
||||
private readonly bool[] buttonMap = new bool[ButtonCount];
|
||||
/// <summary>
|
||||
/// Current values of all axes.
|
||||
/// </summary>
|
||||
private readonly float[] axisMap = new float[AxisCount];
|
||||
|
||||
private void OnEnable() {
|
||||
name = "TouchInput";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the specific button is pressed or not.
|
||||
/// </summary>
|
||||
/// <param name="button"></param>
|
||||
/// <returns></returns>
|
||||
public bool this[CButton button] {
|
||||
get { return buttonMap[(int)button]; }
|
||||
set { buttonMap[(int)button] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the given axis.
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
/// <returns></returns>
|
||||
public float this[CAxis axis] {
|
||||
get { return axisMap[(int)axis]; }
|
||||
set { axisMap[(int)axis] = value; }
|
||||
}
|
||||
|
||||
public override bool GetButton(CButton btn, int id) {
|
||||
return this[btn];
|
||||
}
|
||||
public override float GetAxis(CAxis axis, int id) {
|
||||
return this[axis];
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Assets/CarbonInput/Scripts/TouchInput/TouchMapping.cs.meta
Normal file
18
Assets/CarbonInput/Scripts/TouchInput/TouchMapping.cs.meta
Normal file
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4fae99fbdd9f6aa47b8f0aedfa36d8b7
|
||||
labels:
|
||||
- Touchinput
|
||||
- Touch
|
||||
- Input
|
||||
- Gamepad
|
||||
- Joystick
|
||||
timeCreated: 1455827496
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
175
Assets/CarbonInput/Scripts/TouchInput/TouchStick.cs
Normal file
175
Assets/CarbonInput/Scripts/TouchInput/TouchStick.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace CarbonInput {
|
||||
/// <summary>
|
||||
/// Touch control simulating a thumbstick.
|
||||
/// </summary>
|
||||
public class TouchStick : BaseTouchInput, IPointerDownHandler, IPointerUpHandler, IDragHandler {
|
||||
private const float NearZero = 0.0001f;
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal axis of this control.
|
||||
/// </summary>
|
||||
[Tooltip("Horizontal axis")]
|
||||
public CAxis X = CAxis.LX;
|
||||
/// <summary>
|
||||
/// Vertical axis of this control.
|
||||
/// </summary>
|
||||
[Tooltip("Vertical axis")]
|
||||
public CAxis Y = CAxis.LY;
|
||||
|
||||
/// <summary>
|
||||
/// Touches inside this area will be handled by the stick.
|
||||
/// </summary>
|
||||
[Tooltip("Touches inside this area will be handled by the stick.")]
|
||||
public RectTransform TouchArea;
|
||||
/// <summary>
|
||||
/// Base of the joystick.
|
||||
/// </summary>
|
||||
[Tooltip("Base of the joystick.")]
|
||||
public RectTransform Base;
|
||||
/// <summary>
|
||||
/// Knob of the joystick.
|
||||
/// </summary>
|
||||
[Tooltip("Knob of the joystick.")]
|
||||
public RectTransform Stick;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum distance between center of base and center of stick.
|
||||
/// </summary>
|
||||
[Tooltip("Maximum distance between center of base and center of stick.")]
|
||||
[Range(20, 120)]
|
||||
public float Range = 60;
|
||||
/// <summary>
|
||||
/// Should the joystick disappear on release?
|
||||
/// </summary>
|
||||
[Tooltip("Should the joystick disappear on release?")]
|
||||
public bool HideOnRelease;
|
||||
/// <summary>
|
||||
/// If HideOnRelease is set to true, this value will determine after which time the joystick will start to fade out.
|
||||
/// </summary>
|
||||
[Tooltip("If HideOnRelease is set to true, this value will determine after which time the joystick will start to fade out.")]
|
||||
public float FadeoutDelay;
|
||||
/// <summary>
|
||||
/// If HideOnRelease is set to true, this value will determine how long the fadeout will last.
|
||||
/// </summary>
|
||||
[Tooltip("If HideOnRelease is set to true, this value will determine how long the fadeout will last.")]
|
||||
public float FadeoutTime = 1f;
|
||||
/// <summary>
|
||||
/// If the user moves to far away from the stick, should the stick follow?
|
||||
/// </summary>
|
||||
[Tooltip("If the user moves to far away from the stick, should the stick follow?")]
|
||||
public bool Movable;
|
||||
|
||||
private CanvasRenderer[] childRenderer;
|
||||
|
||||
void Start() {
|
||||
InitMapping();
|
||||
childRenderer = GetComponentsInChildren<CanvasRenderer>();
|
||||
if(HideOnRelease) Hide(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows this control.
|
||||
/// </summary>
|
||||
public void Show() {
|
||||
StopAllCoroutines();
|
||||
SetOpacity(1f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides this control.
|
||||
/// </summary>
|
||||
/// <param name="fadeout">If true, the control will slowly fade out.</param>
|
||||
public void Hide(bool fadeout) {
|
||||
StopAllCoroutines();
|
||||
if(fadeout) StartCoroutine(FadeSequence());
|
||||
else SetOpacity(0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the opacity of this control and all children.
|
||||
/// </summary>
|
||||
/// <param name="opacity"></param>
|
||||
private void SetOpacity(float opacity) {
|
||||
foreach(CanvasRenderer renderer in childRenderer) renderer.SetAlpha(opacity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine used to slowly fadeout.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private IEnumerator FadeSequence() {
|
||||
if(FadeoutDelay > 0) yield return new WaitForSeconds(FadeoutDelay);
|
||||
float opacity = 1f;
|
||||
float speed = 1f / FadeoutTime;
|
||||
while(opacity >= 0.0f) {
|
||||
opacity -= Time.deltaTime * speed;
|
||||
if(opacity < 0) opacity = 0;
|
||||
SetOpacity(opacity);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of this stick in the <see cref="TouchMapping"/> and also sets the knob position.
|
||||
/// If <see cref="Movable"/> is true, it will also follow the user.
|
||||
/// </summary>
|
||||
/// <param name="pos">Touch position in world space</param>
|
||||
private void UpdateStick(Vector2 pos) {
|
||||
// get direction in local space
|
||||
Vector2 direction = (pos - (Vector2)Base.position);
|
||||
direction.x /= Base.lossyScale.x;
|
||||
direction.y /= Base.lossyScale.y;
|
||||
float length = direction.magnitude;
|
||||
if(length < NearZero) {
|
||||
UpdateAxis(Vector2.zero);
|
||||
return;
|
||||
}
|
||||
if(length > Range) {
|
||||
if(Movable) {
|
||||
Vector2 delta = direction.normalized * (length - Range);
|
||||
Vector2 newPos = (Vector2)Base.localPosition + delta;
|
||||
newPos.x = Mathf.Clamp(newPos.x, TouchArea.rect.xMin, TouchArea.rect.xMax);
|
||||
newPos.y = Mathf.Clamp(newPos.y, TouchArea.rect.yMin, TouchArea.rect.yMax);
|
||||
Base.localPosition = newPos;
|
||||
}
|
||||
length = Range;
|
||||
}
|
||||
UpdateAxis(direction.normalized * (length / Range));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the <see cref="AxisMapping"/>.
|
||||
/// </summary>
|
||||
/// <param name="axis"></param>
|
||||
private void UpdateAxis(Vector2 axis) {
|
||||
if(Mapping == null) return;
|
||||
Stick.localPosition = axis * Range;
|
||||
Mapping[X] = axis.x;
|
||||
Mapping[Y] = -axis.y; // invert to match "normal" controller axis
|
||||
}
|
||||
|
||||
public void OnPointerDown(PointerEventData data) {
|
||||
Show();
|
||||
if(RectTransformUtility.RectangleContainsScreenPoint(Stick, data.position) ||
|
||||
RectTransformUtility.RectangleContainsScreenPoint(Base, data.position)) {
|
||||
UpdateStick(data.position);
|
||||
} else if(Movable) {
|
||||
Base.position = data.position;
|
||||
UpdateAxis(Vector2.zero);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPointerUp(PointerEventData data) {
|
||||
UpdateAxis(Vector2.zero);
|
||||
if(HideOnRelease) Hide(true);
|
||||
}
|
||||
|
||||
public void OnDrag(PointerEventData data) {
|
||||
UpdateStick(data.position);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Assets/CarbonInput/Scripts/TouchInput/TouchStick.cs.meta
Normal file
18
Assets/CarbonInput/Scripts/TouchInput/TouchStick.cs.meta
Normal file
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d08a4cd93a9455549863e3be1bc004f2
|
||||
labels:
|
||||
- Touchinput
|
||||
- Touch
|
||||
- Input
|
||||
- Gamepad
|
||||
- Joystick
|
||||
timeCreated: 1455826432
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user