using System;
namespace Otter {
///
/// Movement Component that can be used by an Entity to provide simple top-down style movement.
/// This class requires an Axis component be assigned to it, and that Axis must be also updated
/// by another source. A simple way to do this is to just have the Entity have an Axis component
/// as well as the movement component, and then pass a reference to the axis into the movement.
///
/// The movement also requires a Collider if you want it to be able to collide with walls and other
/// things!
///
public class BasicMovement : Movement {
#region Public Fields
///
/// The Speed of the Movement.
///
public Speed Speed;
///
/// The movement will accelerate toward this Speed.
///
public Speed TargetSpeed;
///
/// The rate at which the Speed will approach the TargetSpeed.
///
public float Accel;
///
/// Determines if diagonal movement should be limited. This is to fix the problem where a vector of
/// (1, 1) would have more length than a vector of (1, 0) or (0, 1).
///
public bool CircleClamp = true;
///
/// The axis used to move. This must be set to something and updated for the movement to work.
///
public Axis Axis;
///
/// If true the movement will not update.
///
public bool Freeze;
#endregion
#region Constructors
///
/// Creates the basic movement.
///
/// The maximum speed allowed in the x axis.
/// The maximum speed allowed in the y axis.
/// The acceleration.
public BasicMovement(float xMax, float yMax, float accel)
: base() {
Speed = new Speed(xMax, yMax);
TargetSpeed = new Speed(xMax, yMax);
Accel = accel;
}
#endregion
#region Public Methods
///
/// Updates the Movement.
///
public override void Update() {
base.Update();
if (Freeze) return;
TargetSpeed.MaxX = Speed.MaxX;
TargetSpeed.MaxY = Speed.MaxY;
if (Axis != null) {
TargetSpeed.X = Axis.X * TargetSpeed.MaxX;
TargetSpeed.Y = Axis.Y * TargetSpeed.MaxY;
// Multiply by 1/sqrt(2) for circle clamp.
if (CircleClamp && Math.Abs(TargetSpeed.X) == 1 && Math.Abs(TargetSpeed.Y) == 1) {
TargetSpeed.X *= .7071f;
TargetSpeed.Y *= .7071f;
}
}
Speed.X = Util.Approach(Speed.X, TargetSpeed.X, Accel);
Speed.Y = Util.Approach(Speed.Y, TargetSpeed.Y, Accel);
MoveXY((int)Speed.X, (int)Speed.Y, Collider);
if (OnMove != null) {
OnMove();
}
}
///
/// A callback for when the horizontal sweep test hits a collision.
///
///
public override void MoveCollideX(Collider collider) {
Speed.X = 0;
}
///
/// A callback for when the vertical sweep test hits a collision.
///
///
public override void MoveCollideY(Collider collider) {
Speed.Y = 0;
}
#endregion
}
}