]> Dogcows Code - chaz/carfire/blobdiff - CarFire/CarFire/CarFire/MovementManager.cs
Smooth movement between cells.
[chaz/carfire] / CarFire / CarFire / CarFire / MovementManager.cs
diff --git a/CarFire/CarFire/CarFire/MovementManager.cs b/CarFire/CarFire/CarFire/MovementManager.cs
new file mode 100644 (file)
index 0000000..372be6c
--- /dev/null
@@ -0,0 +1,188 @@
+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
This page took 0.022028 seconds and 4 git commands to generate.