Last active
December 16, 2015 16:08
-
-
Save eman41/5460580 to your computer and use it in GitHub Desktop.
A movement controller for platforms from an XNA prototype I've been working on. Platforms using this will move back and forth between two points, stopping at each end for the hold-time specified. This is part of a composition-based API, so you can drop in a controller, a sensor, etc and create platforms of various flavors. An option exists to fo…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Microsoft.Xna.Framework; | |
public class PlatformController : IResetable | |
{ | |
private Vector2 _startPos = Vector2.Zero; | |
private Vector2 _stopPos = Vector2.Zero; | |
private float _speed = 0f; | |
private bool _beingHeld = false; | |
private bool _moveOneTime = false; | |
private bool _holdingUntilReset = false; | |
private Timer _holdTimer; | |
private Vector2 _heldVelocity = Vector2.Zero; | |
/// <summary> | |
/// Initializes a new platform controller. | |
/// Start/Strop should be given in level tile coordinates. | |
/// </summary> | |
public PlatformController(Vector2 start, Vector2 stop, float speed, | |
TimeSpan holdTime, bool oneTime = false) | |
{ | |
_holdTimer = new Timer(holdTime); | |
_moveOneTime = oneTime; | |
_startPos = TranslateToPixelCoords(start); | |
_stopPos = TranslateToPixelCoords(stop); | |
_speed = speed; | |
Reset(); | |
} | |
private Vector2 TranslateToPixelCoords(Vector2 levelCoords) | |
{ | |
float x = levelCoords.X * GameMap.TILE_SIZE; | |
float y = levelCoords.Y * GameMap.TILE_SIZE; | |
return new Vector2(x, y); | |
} | |
private Vector2 GetStartVelocity(Vector2 start, Vector2 stop, float speed) | |
{ | |
Vector2 moveNormal = new Vector2(start.X - stop.X, start.Y - stop.Y); | |
moveNormal.Normalize(); | |
return new Vector2(moveNormal.X * speed, moveNormal.Y * speed); | |
} | |
/// <summary>Current X, Y pixel coordinates of this platform</summary> | |
public Vector2 Position { get; set; } | |
/// <summary>Current platform speed</summary> | |
public Vector2 Velocity { get; set; } | |
/// <summary>Reset this entity to it's starting state</summary> | |
public void Reset() | |
{ | |
Position = _startPos; | |
Velocity = GetStartVelocity(_startPos, _stopPos, _speed); | |
_beingHeld = false; | |
_holdingUntilReset = false; | |
_holdTimer.Reset(); | |
} | |
/// <summary>Update the state of the platform.</summary> | |
/// <param name="gameTime">Current Game time</param> | |
public void Update(GameTime gameTime) | |
{ | |
if (_beingHeld) | |
{ | |
if (HoldDurationExceeded(gameTime.ElapsedGameTime)) | |
{ | |
ReleaseAndReverseDirection(); | |
} | |
else | |
{ | |
ClampToNearestEndpoint(); | |
} | |
} | |
else if (!BetweenEndPoints()) | |
{ | |
HoldPlatform(); | |
} | |
UpdatePosition(); | |
} | |
private bool HoldDurationExceeded(TimeSpan elapsed) | |
{ | |
// AdvanceTimerCyclic returns true when it resets. | |
return _holdTimer.AdvanceTimerCyclic(elapsed); | |
} | |
private void ReleaseAndReverseDirection() | |
{ | |
_beingHeld = false; | |
Velocity = -1 * _heldVelocity; | |
} | |
private void ClampToNearestEndpoint() | |
{ | |
Velocity = Vector2.Zero; | |
Position = IsCloserToStart() ? _startPos : _stopPos; | |
_holdingUntilReset = _moveOneTime && Position.Equals(_stopPos); | |
} | |
private bool IsCloserToStart() | |
{ | |
return DistanceTo(_startPos) < DistanceTo(_stopPos); | |
} | |
private float DistanceTo(Vector2 vec) | |
{ | |
return Vector2.Distance(vec, Position); | |
} | |
private bool BetweenEndPoints() | |
{ | |
// Look ahead to avoid bouncing. | |
return MathUtilities.PointBetween(_startPos, _stopPos, Position + Velocity); | |
} | |
private void HoldPlatform() | |
{ | |
_beingHeld = true; | |
_heldVelocity = Velocity; | |
Velocity = Vector2.Zero; | |
} | |
private void UpdatePosition() | |
{ | |
if (!_holdingUntilReset) | |
{ | |
Position += Velocity; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Namespace/Package utilities not included:
IResetable
: Command interface providing theReset()
function.Timer
: Wrapper class forTimeSpan
, provides an advance method that restarts when it reaches0
.MathUtilities
: Vector math not provided by XNA.GameMap
: Class for game maps/levels.