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