using System; using System.Collections.Generic; namespace Otter { /// /// A base class for Movement Components to extend. /// public abstract class Movement : Component { #region Private Fields protected int MoveBufferX = 0, MoveBufferY = 0; #endregion #region Public Fields /// /// An action triggered after movement as been applied. Up to subclasses to implement. /// public Action OnMove; /// /// Determines how many units represent 1 pixel. Default is 100. Example: A speed of 100 would /// move the object 1 pixel per update. /// public int SpeedScale = 100; /// /// The main Collider to use for detecting collisions. If this is not set, no collisions will /// register at all! /// public new Collider Collider; /// /// An action triggered when there is a collision in the X axis. /// public Action OnCollideX; /// /// An action triggered when there is a collision in the Y axis. /// public Action OnCollideY; #endregion #region Public Properties /// /// The list of types that the Collider should check for collisions for when moving. /// public List CollisionsSolid { get; private set; } #endregion #region Constructors public Movement() { CollisionsSolid = new List(); } #endregion #region Public Methods /// /// Register a tag that the Collider should check for collisions with. /// /// The tags to collide with. public void AddCollision(params int[] tags) { foreach (var t in tags) { CollisionsSolid.Add(t); } } /// /// Register a tag that the Collider should check for collisions with. /// /// The tags to collide with. public void AddCollision(params Enum[] tags) { AddCollision(Util.EnumToIntArray(tags)); } /// /// Remove a tag from the collision checking. /// /// public void RemoveCollision(params int[] tags) { foreach (int t in tags) { if (CollisionsSolid.Contains(t)) { CollisionsSolid.Remove(t); } } } /// /// Move the object in the X axis by the value of speed. Sweeping collision test. /// /// The speed to move by (remember SpeedScale is applied.) /// The Collider to use when moving. public virtual void MoveX(int speed, Collider collider = null) { MoveBufferX += speed; while (Math.Abs(MoveBufferX) >= SpeedScale) { int move = Math.Sign(MoveBufferX); if (collider != null) { Collider c = collider.Collide(Entity.X + move, Entity.Y, CollisionsSolid); if (c == null) { Entity.X += move; MoveBufferX = (int)Util.Approach(MoveBufferX, 0, SpeedScale); } else { MoveBufferX = 0; MoveCollideX(c); } } if (collider == null || CollisionsSolid.Count == 0) { Entity.X += move; MoveBufferX = (int)Util.Approach(MoveBufferX, 0, SpeedScale); } } } /// /// Move the object in the Y axis by the value of speed. Sweeping collision test. /// /// The speed to move by (remember SpeedScale is applied.) /// The Collider to use when moving. public virtual void MoveY(int speed, Collider collider = null) { MoveBufferY += speed; while (Math.Abs(MoveBufferY) >= SpeedScale) { int move = Math.Sign(MoveBufferY); if (collider != null) { Collider c = collider.Collide(Entity.X, Entity.Y + move, CollisionsSolid); if (c == null) { Entity.Y += move; MoveBufferY = (int)Util.Approach(MoveBufferY, 0, SpeedScale); } else { MoveBufferY = 0; MoveCollideY(c); } } if (collider == null || CollisionsSolid.Count == 0) { Entity.Y += move; MoveBufferY = (int)Util.Approach(MoveBufferY, 0, SpeedScale); } } } /// /// Called when MoveX collides with a collider. /// /// The collider that was hit. public virtual void MoveCollideX(Collider collider) { if (OnCollideX != null) { OnCollideX(); } } /// /// Called when MoveY collides with a collider. /// /// The collider that was hit. public virtual void MoveCollideY(Collider collider) { if (OnCollideY != null) { OnCollideY(); } } /// /// Shortcut to call both move x and move y. /// /// /// /// public void MoveXY(int speedX, int speedY, Collider collider = null) { MoveX(speedX, collider); MoveY(speedY, collider); } #endregion } }