using SFML.Window; using System; using System.Collections.Generic; namespace Otter { /// /// Component that represents an axis of input. Interprets both X and Y from -1 to 1. Can use multiple /// sources of input like keyboard, mouse buttons, or joystick axes and buttons. Input can also be delivered from code. /// public class Axis : Component { #region Static Methods /// /// Create a new Axis that uses the arrow keys for movement. /// /// A new Axis. public static Axis CreateArrowKeys() { return new Axis(Key.Up, Key.Right, Key.Down, Key.Left); } /// /// Create a new Axis that uses WASD for movement. /// /// A new Axis. public static Axis CreateWASD() { return new Axis(Key.W, Key.D, Key.S, Key.A); } #endregion #region Private Fields #endregion #region Public Fields /// /// The Keys to uss. /// public Dictionary> Keys = new Dictionary>(); /// /// The joystick buttons to use. /// public Dictionary>> JoyButtons = new Dictionary>>(); /// /// The X axes to use. /// public List> AxesX = new List>(); /// /// The Y axes to use. /// public List> AxesY = new List>(); /// /// Determines if the axis is currently enabled. If false, X and Y will report 0. /// public bool Enabled = true; /// /// The range that must be exceeded by joysticks in order for their input to register. /// public float DeadZone = 0.15f; /// /// Determines if the DeadZone will be treated as 0 for joysticks. /// If true, remaps the range DeadZone to 100 to 0 to 1. /// If false, remaps the range 0 to 100 to 0 to 1. /// public bool RemapRange = true; /// /// Determines if raw data coming from the joysticks should be rounded to 2 digits. /// public bool RoundInput = true; /// /// Determines if input has any effect on the axis. When set to true the axis will remain at /// the X and Y it was at when locked. /// public bool Locked = false; #endregion #region Public Properties /// /// The current Vector2 position of the axis. /// public Vector2 Position { get { return new Vector2(X, Y); } } /// /// The X position of the axis from -1 to 1. /// public float X { get; private set; } /// /// The Y position of the axis from -1 to 1. /// public float Y { get; private set; } /// /// The previous X position of the axis. /// public float LastX { get; private set; } /// /// The previous Y position of the axis. /// public float LastY { get; private set; } /// /// Check if the axis is currently forced. /// public bool ForcedInput { get; private set; } /// /// The the up Button for the Axis. /// public Button Up { get; private set; } /// /// The the left Button for the Axis. /// public Button Left { get; private set; } /// /// Gets the down Button for the Axis. /// public Button Down { get; private set; } /// /// Gets the right Button for the Axis. /// public Button Right { get; private set; } /// /// Check if the axis has any means of input currently registered to it. /// public bool HasInput { get { if (ForcedInput) return true; if (Keys.Count > 0) return true; if (JoyButtons.Count > 0) return true; if (AxesX.Count > 0) return true; if (AxesY.Count > 0) return true; return false; } } /// /// Check of the axis is completely neutral. /// public bool Neutral { get { return X == 0 && Y == 0; } } #endregion #region Constructors /// /// Create a new Axis. /// public Axis() { ForcedInput = false; foreach (Direction d in Enum.GetValues(typeof(Direction))) { Keys[d] = new List(); JoyButtons.Add(d, new List>()); for (int i = 0; i < Joystick.Count; i++) { JoyButtons[d].Add(new List()); } } for (int i = 0; i < Joystick.Count; i++) { AxesX.Add(new List()); AxesY.Add(new List()); } // Create buttons for Axis. Up = new Button(); Down = new Button(); Left = new Button(); Right = new Button(); } /// /// Create a new Axis using Keys. /// /// The Key for Up. /// The Key for Right. /// The Key for Down. /// The Key for Left. public Axis(Key up, Key right, Key down, Key left) : this() { AddKeys(up, right, down, left); } /// /// Create a new Axis using a joystick axis. /// /// The JoyAxis to use for X. /// The JoyAxis to use for Y. /// The joystick id to use. public Axis(JoyAxis x, JoyAxis y, params int[] joystick) : this() { foreach (var j in joystick) { AddJoyAxis(x, y, j); } } /// /// Create a new Axis using AxisButtons. /// /// The AxisButton for Up. /// The AxisButton for Right. /// The AxisButton for Down. /// The AxisButton for Left. /// The joystick id to use. public Axis(AxisButton up, AxisButton right, AxisButton down, AxisButton left, params int[] joystick) : this() { AddButton(up, Direction.Up, joystick); AddButton(right, Direction.Right, joystick); AddButton(down, Direction.Down, joystick); AddButton(left, Direction.Left, joystick); } #endregion #region Public Methods /// /// Reset the Axis to report no input. /// public void Reset() { X = 0; Y = 0; LastX = 0; LastY = 0; Left.Reset(); Right.Reset(); Up.Reset(); Down.Reset(); } /// /// Clear all registered inputs for the Axis. /// public void Clear() { Keys.Clear(); JoyButtons.Clear(); AxesX.Clear(); AxesY.Clear(); } /// /// Add a joystick axis. /// /// The x axis of the joystick. /// The y axis of the joystick. /// The joystick id. /// The Axis. public Axis AddJoyAxis(JoyAxis x, JoyAxis y, params int[] joystick) { foreach (var j in joystick) { AxesX[j].Add(x); AxesY[j].Add(y); } return this; } /// /// Add another Axis to this Axis. /// /// The source Axis to use. /// This Axis. public Axis AddAxis(Axis source) { foreach (Direction d in Enum.GetValues(typeof(Direction))) { // Copy keys from source Axis. Keys[d].AddRange(source.Keys[d]); for (int i = 0; i < Joystick.Count; i++) { // Copy buttons from source Axis. JoyButtons[d].AddRange(source.JoyButtons[d]); } } for (int i = 0; i < Joystick.Count; i++) { // Copy joy axes from source Axis. AxesX[i].AddRange(source.AxesX[i]); AxesY[i].AddRange(source.AxesY[i]); } return this; } /// /// Add a joystick button. /// /// The joystick button id. /// The direction this button should effect. /// The joystick id. /// The Axis. public Axis AddButton(int button, Direction direction, params int[] joystick) { foreach (var j in joystick) { JoyButtons[direction][j].Add(button); } return this; } /// /// Add a joystick axis button. /// /// The joystick axis button. /// The direction this axis button should effect. /// The joystick id. /// The Axis. public Axis AddButton(AxisButton button, Direction direction, params int[] joystick) { foreach (var j in joystick) { AddButton((int)button, direction, j); } return this; } /// /// Add a key. /// /// The keyboard key. /// The direction this key should effect. /// The Axis. public Axis AddKey(Key key, Direction direction) { Keys[direction].Add(key); return this; } /// /// Add keys. /// /// Four keys to create a pair of axes from (Up, Right, Down, Left). /// The Axis. public Axis AddKeys(params Key[] upRightDownLeft) { if (upRightDownLeft.Length != 4) { throw new ArgumentException("Must use four keys for an axis!"); } AddKey(upRightDownLeft[0], Direction.Up); AddKey(upRightDownLeft[1], Direction.Right); AddKey(upRightDownLeft[2], Direction.Down); AddKey(upRightDownLeft[3], Direction.Left); return this; } /// /// Force the axis state. /// /// The forced x state. /// The forced y state. public void ForceState(float x, float y) { ForcedInput = true; X = x; Y = y; } /// /// Force the axis state. /// /// The forced x and y state. public void ForceState(Vector2 xy) { ForceState(xy.X, xy.Y); } /// /// Force the axis x state. /// /// The forced x state. public void ForceStateX(float x) { ForceState(x, Y); } /// /// Force the axis y state. /// /// The forced y state. public void ForceStateY(float y) { ForceState(X, y); } /// /// Relinquish control of the axis back to input. /// public void ReleaseState() { ForcedInput = false; } /// /// Update the Axis. /// public override void UpdateFirst() { base.UpdateFirst(); LastX = X; LastY = Y; if (Locked) return; if (!Enabled) { X = 0; Y = 0; return; } if (ForcedInput) { return; } X = 0; Y = 0; for (int i = 0; i < Joystick.Count; i++) { foreach (JoyAxis axis in AxesX[i]) { float a = Input.Instance.GetAxis(axis, i) * 0.01f; } foreach (JoyAxis axis in AxesY[i]) { float a = Input.Instance.GetAxis(axis, i) * 0.01f; } foreach (JoyAxis axis in AxesX[i]) { float a = Input.Instance.GetAxis(axis, i) * 0.01f; if (Math.Abs(a) >= DeadZone) { if (RemapRange) { if (a > 0) { X += Util.ScaleClamp(a, 0, 1, 0, 1); } else { X += Util.ScaleClamp(a, -1, -0, -1, 0); } } else { X += a; } } if (RoundInput) X = (float)Math.Round(X, 2); } foreach (JoyAxis axis in AxesY[i]) { float a = Input.Instance.GetAxis(axis, i) * 0.01f; if (Math.Abs(a) >= DeadZone) { if (RemapRange) { if (a > 0) { Y += Util.ScaleClamp(a, 0, 1, 0, 1); } else { Y += Util.ScaleClamp(a, -1, -0, -1, 0); } } else { Y += a; } } if (RoundInput) Y = (float)Math.Round(Y, 2); } } foreach (Key k in Keys[Direction.Up]) { if (Input.Instance.KeyDown(k)) { Y -= 1; } } foreach (Key k in Keys[Direction.Down]) { if (Input.Instance.KeyDown(k)) { Y += 1; } } foreach (Key k in Keys[Direction.Left]) { if (Input.Instance.KeyDown(k)) { X -= 1; } } foreach (Key k in Keys[Direction.Right]) { if (Input.Instance.KeyDown(k)) { X += 1; } } for (int i = 0; i < Joystick.Count; i++) { foreach (int b in JoyButtons[Direction.Up][i]) { if (Input.Instance.ButtonDown(b, i)) { Y -= 1; } } foreach (int b in JoyButtons[Direction.Down][i]) { if (Input.Instance.ButtonDown(b, i)) { Y += 1; } } foreach (int b in JoyButtons[Direction.Left][i]) { if (Input.Instance.ButtonDown(b, i)) { X -= 1; } } foreach (int b in JoyButtons[Direction.Right][i]) { if (Input.Instance.ButtonDown(b, i)) { X += 1; } } } X = Util.Clamp(X, -1, 1); Y = Util.Clamp(Y, -1, 1); // Update the buttons. This makes it easy to read the Axis as buttons for Up, Right, Left, Down. Right.UpdateFirst(); Up.UpdateFirst(); Left.UpdateFirst(); Down.UpdateFirst(); Right.ForceState(false); Up.ForceState(false); Left.ForceState(false); Down.ForceState(false); if (X > 0.5f) { Right.ForceState(true); } if (X < -0.5f) { Left.ForceState(true); } if (Y > 0.5f) { Down.ForceState(true); } if (Y < -0.5f) { Up.ForceState(true); } } public override string ToString() { return "[Axis X: " + X.ToString() + " Y: " + Y.ToString() + "]"; } #endregion } }