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
}
}