snapping an angle to the closest cardinal direction
- by Josh E
I'm developing a 2D sprite-based game, and I'm finding that I'm having trouble with making the sprites rotate correctly. In a nutshell, I've got spritesheets for each of 5 directions (the other 3 come from just flipping the sprite horizontally), and I need to clamp the velocity/rotation of the sprite to one of those directions. My sprite class has a pre-computed list of radians corresponding to the cardinal directions like this:
protected readonly List<float> CardinalDirections = new List<float>
{
MathHelper.PiOver4,
MathHelper.PiOver2,
MathHelper.PiOver2 + MathHelper.PiOver4,
MathHelper.Pi,
-MathHelper.PiOver4,
-MathHelper.PiOver2,
-MathHelper.PiOver2 + -MathHelper.PiOver4,
-MathHelper.Pi,
};
Here's the positional update code:
if (velocity == Vector2.Zero)
return;
var rot = ((float)Math.Atan2(velocity.Y, velocity.X));
TurretRotation = SnapPositionToGrid(rot);
var snappedX = (float)Math.Cos(TurretRotation);
var snappedY = (float)Math.Sin(TurretRotation);
var rotVector = new Vector2(snappedX, snappedY);
velocity *= rotVector;
//...snip
private float SnapPositionToGrid(float rotationToSnap)
{
if (rotationToSnap == 0)
return 0.0f;
var targetRotation = CardinalDirections.First(x =>
(x - rotationToSnap >= -0.01 && x - rotationToSnap <= 0.01));
return (float)Math.Round(targetRotation, 3);
}
What am I doing wrong here? I know that the SnapPositionToGrid method is far from what it needs to be - the .First(..) call is on purpose so that it throws on no match, but I have no idea how I would go about accomplishing this, and unfortunately, Google hasn't helped too much either. Am I thinking about this the wrong way, or is the answer staring at me in the face?