--- /dev/null
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text;\r
+using Microsoft.Xna.Framework;\r
+\r
+namespace CarFire\r
+{\r
+ /// <summary>\r
+ /// A class to manage the motion of objects on a grid of cells.\r
+ /// Each update you can pass a direction and the manager will move\r
+ /// the position to that point while also enforcing a speed limit.\r
+ /// This class does not detect collisions, so care must be taken\r
+ /// to only pass directions to a walkable cell during an update.\r
+ /// </summary>\r
+ public class MovementManager\r
+ {\r
+ #region Public Properties\r
+\r
+ /// <summary>\r
+ /// Get the current position in map coordinates. This is the\r
+ /// smooth, interpolated set of coordinates.\r
+ /// </summary>\r
+ public Vector2 Position { get { return mPosition; } }\r
+\r
+ /// <summary>\r
+ /// Get the grid coordinates where the object is at or\r
+ /// is moving to.\r
+ /// </summary>\r
+ public Point Coordinates { get { return mCoordinates; } }\r
+\r
+ /// <summary>\r
+ /// Get and set the speed of movement in grid cells / second.\r
+ /// </summary>\r
+ public float Speed;\r
+\r
+ #endregion\r
+\r
+\r
+ #region Public Methods\r
+\r
+ /// <summary>\r
+ /// Construct a movement manager with the initial position of\r
+ /// the thing you want to track.\r
+ /// </summary>\r
+ /// <param name="position">Grid coordinates.</param>\r
+ public MovementManager(Point position)\r
+ {\r
+ mPosition = new Vector2((float)position.X, (float)position.Y);\r
+ mCoordinates = position;\r
+ mLastCoordinates = position;\r
+ Speed = 1.0f;\r
+ }\r
+\r
+ /// <summary>\r
+ /// Construct a movement manager with the initial position of\r
+ /// the thing you want to track and its speed.\r
+ /// </summary>\r
+ /// <param name="position">Grid coordinates.</param>\r
+ /// <param name="speed">Speed: Grid cells per second.</param>\r
+ public MovementManager(Point position, float speed)\r
+ {\r
+ mPosition = new Vector2((float)position.X, (float)position.Y);\r
+ mCoordinates = position;\r
+ mLastCoordinates = position;\r
+ Speed = speed;\r
+ }\r
+\r
+\r
+ /// <summary>\r
+ /// Update the movement manager with the timeslice and no directions.\r
+ /// </summary>\r
+ /// <param name="timeSpan">The timeslice.</param>\r
+ public void Update(TimeSpan timeSpan)\r
+ {\r
+ Update(timeSpan, false, false, false, false);\r
+ }\r
+\r
+ /// <summary>\r
+ /// Update the movement manager with the timeslice and the directions\r
+ /// the object is supposed to go. The directions will be ignored if the\r
+ /// object is currently in transit from one cell to another.\r
+ /// </summary>\r
+ /// <param name="timeSpan">The timeslice.</param>\r
+ /// <param name="moveLeft">Want to move left.</param>\r
+ /// <param name="moveRight">Want to move right.</param>\r
+ /// <param name="moveUp">Want to move up.</param>\r
+ /// <param name="moveDown">Want to move down.</param>\r
+ public void Update(TimeSpan timeSpan, bool moveLeft, bool moveRight, bool moveUp, bool moveDown)\r
+ {\r
+ float passedTime = (float)timeSpan.TotalSeconds;\r
+\r
+ bool requestMove = (moveLeft ^ moveRight) || (moveUp ^ moveDown);\r
+ if (!mIsMoving && requestMove)\r
+ {\r
+ UpdateCoordinates(moveLeft, moveRight, moveUp, moveDown);\r
+\r
+ mIsMoving = true;\r
+ mTimeAccumulator = passedTime;\r
+\r
+ RecalculatePosition(mTimeAccumulator / mInverseSpeed);\r
+ }\r
+ else if (mIsMoving)\r
+ {\r
+ mTimeAccumulator += passedTime;\r
+\r
+ float alpha = mTimeAccumulator / mInverseSpeed;\r
+ if (alpha >= 1.0f)\r
+ {\r
+ if (requestMove)\r
+ {\r
+ mTimeAccumulator = mTimeAccumulator - mInverseSpeed;\r
+ alpha = mTimeAccumulator / mInverseSpeed;\r
+\r
+ UpdateCoordinates(moveLeft, moveRight, moveUp, moveDown);\r
+ }\r
+ else\r
+ {\r
+ mIsMoving = false;\r
+ alpha = 1.0f;\r
+ }\r
+ }\r
+\r
+ RecalculatePosition(alpha);\r
+ }\r
+ }\r
+\r
+\r
+ /// <summary>\r
+ /// Helper method to get neighbor cells from a point and directions.\r
+ /// </summary>\r
+ /// <param name="point">The point.</param>\r
+ /// <param name="left">To the left.</param>\r
+ /// <param name="right">To the right.</param>\r
+ /// <param name="up">Above.</param>\r
+ /// <param name="down">Below.</param>\r
+ /// <returns>The neighbor cell coordinates.</returns>\r
+ public static Point GetNeighborCell(Point point, bool left, bool right, bool up, bool down)\r
+ {\r
+ if (left) point.X--;\r
+ if (right) point.X++;\r
+ if (up) point.Y--;\r
+ if (down) point.Y++;\r
+ return point;\r
+ }\r
+\r
+ #endregion\r
+\r
+\r
+ #region Private Methods\r
+\r
+ void RecalculatePosition(float alpha)\r
+ {\r
+ Console.WriteLine("last: " + mLastCoordinates + ", now: " + mCoordinates + ", alpha: " + alpha);\r
+ mPosition.X = (float)mLastCoordinates.X + alpha * ((float)mCoordinates.X - (float)mLastCoordinates.X);\r
+ mPosition.Y = (float)mLastCoordinates.Y + alpha * ((float)mCoordinates.Y - (float)mLastCoordinates.Y);\r
+ }\r
+\r
+ void UpdateCoordinates(bool moveLeft, bool moveRight, bool moveUp, bool moveDown)\r
+ {\r
+ mLastCoordinates = mCoordinates;\r
+ mCoordinates = GetNeighborCell(mCoordinates, moveLeft, moveRight, moveUp, moveDown);\r
+\r
+ if ((moveLeft && moveUp) || (moveUp && moveRight) || (moveRight && moveDown) || (moveDown && moveLeft))\r
+ {\r
+ mInverseSpeed = 1.4f / Speed;\r
+ }\r
+ else\r
+ {\r
+ mInverseSpeed = 1.0f / Speed;\r
+ }\r
+ }\r
+\r
+ #endregion\r
+\r
+\r
+ #region Private Variables\r
+\r
+ Vector2 mPosition; // Position on the viewable map.\r
+ Point mCoordinates; // Position on the grid.\r
+ Point mLastCoordinates; // Last position on the grid.\r
+ float mInverseSpeed; // The time it takes to move from one cell to another.\r
+ float mTimeAccumulator; // Amount of time passed since last move.\r
+ bool mIsMoving; // Whether or not it is currently in the process of moving.\r
+\r
+ #endregion\r
+ }\r
+}\r