You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
18 KiB
C#

using SFML.Window;
using System;
using System.Collections.Generic;
namespace Otter {
/// <summary>
/// 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.
/// </summary>
public class Axis : Component {
#region Static Methods
/// <summary>
/// Create a new Axis that uses the arrow keys for movement.
/// </summary>
/// <returns>A new Axis.</returns>
public static Axis CreateArrowKeys() {
return new Axis(Key.Up, Key.Right, Key.Down, Key.Left);
}
/// <summary>
/// Create a new Axis that uses WASD for movement.
/// </summary>
/// <returns>A new Axis.</returns>
public static Axis CreateWASD() {
return new Axis(Key.W, Key.D, Key.S, Key.A);
}
#endregion
#region Private Fields
#endregion
#region Public Fields
/// <summary>
/// The Keys to uss.
/// </summary>
public Dictionary<Direction, List<Key>> Keys = new Dictionary<Direction, List<Key>>();
/// <summary>
/// The joystick buttons to use.
/// </summary>
public Dictionary<Direction, List<List<int>>> JoyButtons = new Dictionary<Direction, List<List<int>>>();
/// <summary>
/// The X axes to use.
/// </summary>
public List<List<JoyAxis>> AxesX = new List<List<JoyAxis>>();
/// <summary>
/// The Y axes to use.
/// </summary>
public List<List<JoyAxis>> AxesY = new List<List<JoyAxis>>();
/// <summary>
/// Determines if the axis is currently enabled. If false, X and Y will report 0.
/// </summary>
public bool Enabled = true;
/// <summary>
/// The range that must be exceeded by joysticks in order for their input to register.
/// </summary>
public float DeadZone = 0.15f;
/// <summary>
/// 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.
/// </summary>
public bool RemapRange = true;
/// <summary>
/// Determines if raw data coming from the joysticks should be rounded to 2 digits.
/// </summary>
public bool RoundInput = true;
/// <summary>
/// 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.
/// </summary>
public bool Locked = false;
#endregion
#region Public Properties
/// <summary>
/// The current Vector2 position of the axis.
/// </summary>
public Vector2 Position {
get {
return new Vector2(X, Y);
}
}
/// <summary>
/// The X position of the axis from -1 to 1.
/// </summary>
public float X { get; private set; }
/// <summary>
/// The Y position of the axis from -1 to 1.
/// </summary>
public float Y { get; private set; }
/// <summary>
/// The previous X position of the axis.
/// </summary>
public float LastX { get; private set; }
/// <summary>
/// The previous Y position of the axis.
/// </summary>
public float LastY { get; private set; }
/// <summary>
/// Check if the axis is currently forced.
/// </summary>
public bool ForcedInput { get; private set; }
/// <summary>
/// The the up Button for the Axis.
/// </summary>
public Button Up { get; private set; }
/// <summary>
/// The the left Button for the Axis.
/// </summary>
public Button Left { get; private set; }
/// <summary>
/// Gets the down Button for the Axis.
/// </summary>
public Button Down { get; private set; }
/// <summary>
/// Gets the right Button for the Axis.
/// </summary>
public Button Right { get; private set; }
/// <summary>
/// Check if the axis has any means of input currently registered to it.
/// </summary>
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;
}
}
/// <summary>
/// Check of the axis is completely neutral.
/// </summary>
public bool Neutral {
get {
return X == 0 && Y == 0;
}
}
#endregion
#region Constructors
/// <summary>
/// Create a new Axis.
/// </summary>
public Axis() {
ForcedInput = false;
foreach (Direction d in Enum.GetValues(typeof(Direction))) {
Keys[d] = new List<Key>();
JoyButtons.Add(d, new List<List<int>>());
for (int i = 0; i < Joystick.Count; i++) {
JoyButtons[d].Add(new List<int>());
}
}
for (int i = 0; i < Joystick.Count; i++) {
AxesX.Add(new List<JoyAxis>());
AxesY.Add(new List<JoyAxis>());
}
// Create buttons for Axis.
Up = new Button();
Down = new Button();
Left = new Button();
Right = new Button();
}
/// <summary>
/// Create a new Axis using Keys.
/// </summary>
/// <param name="up">The Key for Up.</param>
/// <param name="right">The Key for Right.</param>
/// <param name="down">The Key for Down.</param>
/// <param name="left">The Key for Left.</param>
public Axis(Key up, Key right, Key down, Key left)
: this() {
AddKeys(up, right, down, left);
}
/// <summary>
/// Create a new Axis using a joystick axis.
/// </summary>
/// <param name="x">The JoyAxis to use for X.</param>
/// <param name="y">The JoyAxis to use for Y.</param>
/// <param name="joystick">The joystick id to use.</param>
public Axis(JoyAxis x, JoyAxis y, params int[] joystick)
: this() {
foreach (var j in joystick) {
AddJoyAxis(x, y, j);
}
}
/// <summary>
/// Create a new Axis using AxisButtons.
/// </summary>
/// <param name="up">The AxisButton for Up.</param>
/// <param name="right">The AxisButton for Right.</param>
/// <param name="down">The AxisButton for Down.</param>
/// <param name="left">The AxisButton for Left.</param>
/// <param name="joystick">The joystick id to use.</param>
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
/// <summary>
/// Reset the Axis to report no input.
/// </summary>
public void Reset() {
X = 0;
Y = 0;
LastX = 0;
LastY = 0;
Left.Reset();
Right.Reset();
Up.Reset();
Down.Reset();
}
/// <summary>
/// Clear all registered inputs for the Axis.
/// </summary>
public void Clear() {
Keys.Clear();
JoyButtons.Clear();
AxesX.Clear();
AxesY.Clear();
}
/// <summary>
/// Add a joystick axis.
/// </summary>
/// <param name="x">The x axis of the joystick.</param>
/// <param name="y">The y axis of the joystick.</param>
/// <param name="joystick">The joystick id.</param>
/// <returns>The Axis.</returns>
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;
}
/// <summary>
/// Add another Axis to this Axis.
/// </summary>
/// <param name="source">The source Axis to use.</param>
/// <returns>This Axis.</returns>
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;
}
/// <summary>
/// Add a joystick button.
/// </summary>
/// <param name="button">The joystick button id.</param>
/// <param name="direction">The direction this button should effect.</param>
/// <param name="joystick">The joystick id.</param>
/// <returns>The Axis.</returns>
public Axis AddButton(int button, Direction direction, params int[] joystick) {
foreach (var j in joystick) {
JoyButtons[direction][j].Add(button);
}
return this;
}
/// <summary>
/// Add a joystick axis button.
/// </summary>
/// <param name="button">The joystick axis button.</param>
/// <param name="direction">The direction this axis button should effect.</param>
/// <param name="joystick">The joystick id.</param>
/// <returns>The Axis.</returns>
public Axis AddButton(AxisButton button, Direction direction, params int[] joystick) {
foreach (var j in joystick) {
AddButton((int)button, direction, j);
}
return this;
}
/// <summary>
/// Add a key.
/// </summary>
/// <param name="key">The keyboard key.</param>
/// <param name="direction">The direction this key should effect.</param>
/// <returns>The Axis.</returns>
public Axis AddKey(Key key, Direction direction) {
Keys[direction].Add(key);
return this;
}
/// <summary>
/// Add keys.
/// </summary>
/// <param name="upRightDownLeft">Four keys to create a pair of axes from (Up, Right, Down, Left).</param>
/// <returns>The Axis.</returns>
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;
}
/// <summary>
/// Force the axis state.
/// </summary>
/// <param name="x">The forced x state.</param>
/// <param name="y">The forced y state.</param>
public void ForceState(float x, float y) {
ForcedInput = true;
X = x;
Y = y;
}
/// <summary>
/// Force the axis state.
/// </summary>
/// <param name="xy">The forced x and y state.</param>
public void ForceState(Vector2 xy) {
ForceState(xy.X, xy.Y);
}
/// <summary>
/// Force the axis x state.
/// </summary>
/// <param name="x">The forced x state.</param>
public void ForceStateX(float x) {
ForceState(x, Y);
}
/// <summary>
/// Force the axis y state.
/// </summary>
/// <param name="y">The forced y state.</param>
public void ForceStateY(float y) {
ForceState(X, y);
}
/// <summary>
/// Relinquish control of the axis back to input.
/// </summary>
public void ReleaseState() {
ForcedInput = false;
}
/// <summary>
/// Update the Axis.
/// </summary>
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
}
}