How to Create a Controller

controller1.gif

I've come to a point where I want to implement/create an interface/controller for my game. This seemed difficult because I couldn't find any tutorials on the subject. I did eventually figure it out and figured I would share what I've learned. I should stress that this isn't necessarily the best way, its simply something I've come up with.

Here are some of the final picture's for those curious:

controller2.gif

It looks better in action. But basically it stacks to the left based off of what was selected.

So lets set up a new XNA 3.1 Project in Visual C#. I have named mine ControllerTutorial.

controller3.gif

Now we add the Primitives Class. (Credit to the Author of the class: http://pastebin.com/f7145c640)
(Note: I have modified it to do a filled in Square)

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace ControllerTutorial
{

        //////////////////////////////////////////////////////////////////////////
        // Class    :   BasicPrimitives
        // Auther   :   http://pastebin.com/f7145c640
        // Purpose  :   Render simple 2D shapes.
        //////////////////////////////////////////////////////////////////////////
        public class BasicPrimitives
        {
            /*********************************************************************/
            // Members.
            /*********************************************************************/
 
            #region Fields

            /// <summary>The color of the primitive object.</summary>
            private Color m_Color = Color.White;

            /// <summary>The position of the primitive object.</summary>
            private Vector2 m_vPosition = Vector2.Zero;
            private Texture2D myTexture;
            /// <summary>The render depth of the primitive line object (0 = front, 1 = back).</summary>
            private float m_fDepth = 0f;

            /// <summary>The thickness of the shape's edge.</summary>
            private float m_fThickness = 1f;
 
            /// <summary>1x1 pixel that creates the shape.</summary>
            private Texture2D m_Pixel = null;

            /// <summary>List of vectors.</summary>
            private List<Vector2> m_VectorList = new List<Vector2>();

            #endregion // Fields

            #region Properties

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Get/Set the colour of the primitive object.
            /// </summary>
            //////////////////////////////////////////////////////////////////////////
            public Color Colour
            {
                get { return m_Color; }
                set { m_Color = value; }
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Get/Set the position of the primitive object.
            /// </summary>
            //////////////////////////////////////////////////////////////////////////
            public Vector2 Position
            {
                get { return m_vPosition; }
                set { m_vPosition = value; }
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Get/Set the render depth of the primitive line object (0 = front, 1 = back).
            /// </summary>
            //////////////////////////////////////////////////////////////////////////
            public float Depth
            {
                get { return m_fDepth; }
                set { m_fDepth = value; }
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Get/Set the thickness of the shape's edge.
            /// </summary>
            //////////////////////////////////////////////////////////////////////////
            public float Thickness
            {
                get { return m_fThickness; }
                set { m_fThickness = value; }
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Gets the number of vectors which make up the primitive object.
            /// </summary>
            //////////////////////////////////////////////////////////////////////////
            public int CountVectors
            {
                get { return m_VectorList.Count; }
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Gets the vector position from the list.
            /// </summary>
            /// <param name="_nIndex">The index to get from.</param>
            //////////////////////////////////////////////////////////////////////////
            public Vector2 GetVector(int _nIndex)
            {
                return m_VectorList[_nIndex];
            }

            #endregion // Properties

            /*********************************************************************/
            // Functions.
            /*********************************************************************/

            #region Initialization | Dispose

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Creates a new primitive object.
            /// </summary>
            /// <param name="_graphicsDevice">The graphics device object to use.</param>
            //////////////////////////////////////////////////////////////////////////
            public BasicPrimitives(GraphicsDevice _graphicsDevice)
            {
                graphicsDevice = _graphicsDevice;
                //////////////////////////////////////////////////////////////////////////
                // Create the pixel texture.
                m_Pixel = new Texture2D(_graphicsDevice, 1, 1, 1, TextureUsage.None, SurfaceFormat.Color);
                m_Pixel.SetData<Color>(new Color[] { Color.White });
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Called when the primitive object is destroyed.
            /// </summary>
            //////////////////////////////////////////////////////////////////////////
            ~BasicPrimitives()
            {
                m_Pixel.Dispose();
                m_VectorList.Clear();
            }

            #endregion // Initialization | Dispose

            #region List Manipulation Methods

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Adds a vector to the primitive object.
            /// </summary>
            /// <param name="_vPosition">The vector to add.</param>
            //////////////////////////////////////////////////////////////////////////
            public void AddVector(Vector2 _vPosition)
            {
                m_VectorList.Add(_vPosition);
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Inserts a vector into the primitive object.
            /// </summary>
            /// <param name="_nIndex">The index to insert it at.</param>
            /// <param name="_vPosition">The vector to insert.</param>
            //////////////////////////////////////////////////////////////////////////
            public void InsertVector(int _nIndex, Vector2 _vPosition)
            {
                m_VectorList.Insert(_nIndex, _vPosition);
           }

             //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Removes a vector from the primitive object.
            /// </summary>
            /// <param name="_vPosition">The vector to remove.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RemoveVector(Vector2 _vPosition)
            {
                m_VectorList.Remove(_vPosition);
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>

            /// Removes a vector from the primitive object.
            /// </summary>
            /// <param name="_nIndex">The index of the vector to remove.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RemoveVector(int _nIndex)
            {
                m_VectorList.RemoveAt(_nIndex);
            }

            public GraphicsDevice graphicsDevice;

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Clears all vectors from the list.
            /// </summary>
            //////////////////////////////////////////////////////////////////////////
            public void ClearVectors()
            {
                m_VectorList.Clear();
            }

            #endregion // List Manipulation Methods

            #region Creation Methods

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Create a line primitive.
            /// </summary>
            /// <param name="_vStart">Start of the line, in pixels.</param>
            /// <param name="_vEnd">End of the line, in pixels.</param>
            //////////////////////////////////////////////////////////////////////////
            public void CreateLine(Vector2 _vStart, Vector2 _vEnd)
            {
                m_VectorList.Clear();
                m_VectorList.Add(_vStart);
                m_VectorList.Add(_vEnd);
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Create a triangle primitive.
            /// </summary>
            /// <param name="_vPoint1">Fist point, in pixels.</param>
            /// <param name="_vPoint2">Second point, in pixels.</param>
            /// <param name="_vPoint3">Third point, in pixels.</param>
            //////////////////////////////////////////////////////////////////////////
            public void CreateTriangle(Vector2 _vPoint1, Vector2 _vPoint2, Vector2 _vPoint3)
            {
                m_VectorList.Clear();
                m_VectorList.Add(_vPoint1);
                m_VectorList.Add(_vPoint2);
                m_VectorList.Add(_vPoint3);
                m_VectorList.Add(_vPoint1);
            }
 
            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Create a square primitive.
            /// </summary>
            /// <param name="_vTopLeft">Top left hand corner of the square.</param>
            /// <param name="_vBottomRight">Bottom right hand corner of the square.</param>
            //////////////////////////////////////////////////////////////////////////
            public void CreateSquare(Vector2 _vTopLeft, Vector2 _vBottomRight)
            {
                m_VectorList.Clear();
                m_VectorList.Add(_vTopLeft);
                m_VectorList.Add(new Vector2(_vTopLeft.X, _vBottomRight.Y));
                m_VectorList.Add(_vBottomRight);
                m_VectorList.Add(new Vector2(_vBottomRight.X, _vTopLeft.Y));
                m_VectorList.Add(_vTopLeft);
 
                myTexture = CreateRectangle((int)_vBottomRight.X, (int)_vBottomRight.Y, graphicsDevice);//
            }
 
            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Creates a circle starting from (0, 0).
            /// </summary>
            /// <param name="_fRadius">The radius (half the width) of the circle.</param>
            /// <param name="_nSides">The number of sides on the circle. (64 is average).</param>
            //////////////////////////////////////////////////////////////////////////
            public void CreateCircle(float _fRadius, int _nSides)
            {
                m_VectorList.Clear();

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                float fMax = (float)MathHelper.TwoPi;
                float fStep = fMax / (float)_nSides;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Create the full circle.
                for (float fTheta = fMax; fTheta >= -1; fTheta -= fStep)
                {
                    m_VectorList.Add(new Vector2(_fRadius * (float)Math.Cos((double)fTheta),
                                                 _fRadius * (float)Math.Sin((double)fTheta)));
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Creates an ellipse starting from (0, 0) with the given width and height.
            /// Vectors are generated using the parametric equation of an ellipse.
            /// </summary>
            /// <param name="_fSemiMajorAxis">The width of the ellipse at its center.</param>
            /// <param name="_fSemiMinorAxis">The height of the ellipse at its center.</param>
            /// <param name="_nSides">The number of sides on the ellipse. (64 is average).</param>
            //////////////////////////////////////////////////////////////////////////
            public void CreateEllipse(float _fSemiMajorAxis, float _fSemiMinorAxis, int _nSides)
            {
                m_VectorList.Clear();

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                float fMax = (float)MathHelper.TwoPi;
                float fStep = fMax / (float)_nSides;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Create full ellipse.
                for (float fTheta = fMax; fTheta >= -1; fTheta -= fStep)
                {
                    m_VectorList.Add(new Vector2((float)(_fSemiMajorAxis * Math.Cos(fTheta)),
                                                 (float)(_fSemiMinorAxis * Math.Sin(fTheta))));
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }
 
            #endregion // Creation Methods

            #region Render Methods

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render points of the primitive.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderPointPrimitive(SpriteBatch _spriteBatch)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count <= 0)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////
 
                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero;
                float fAngle = 0f;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];

                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                              (double)(vPosition2.X - vPosition1.X));

                     // Stretch the pixel between the two vectors.
                    _spriteBatch.Draw(m_Pixel,
                                      m_vPosition + m_VectorList[i],
                                      null,
                                      m_Color,
                                      fAngle,
                                      new Vector2(0.5f, 0.5f),
                                      m_fThickness,
                                      SpriteEffects.None,
                                      m_fDepth);
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render points of the primitive.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            /// <param name="_fAngle">The counterclockwise rotation in radians. (0.0f is default).</param>
            /// <param name="_vPivot">Position in which to rotate around.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderPointPrimitive(SpriteBatch _spriteBatch, float _fAngle, Vector2 _vPivot)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count <= 0)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Rotate object based on pivot.
                Rotate(_fAngle, _vPivot);
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero;
                float fAngle = 0f;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];

                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                               (double)(vPosition2.X - vPosition1.X));
 
                    // Stretch the pixel between the two vectors.
                    _spriteBatch.Draw(m_Pixel,
                                      m_vPosition + m_VectorList[i],
                                      null,
                                      m_Color,
                                      fAngle,
                                      new Vector2(0.5f, 0.5f),
                                      m_fThickness,
                                      SpriteEffects.None,
                                      m_fDepth);
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }
 
            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render the lines of the primitive.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderLinePrimitive(SpriteBatch _spriteBatch)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count < 2)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero;
                float fDistance = 0f, fAngle = 0f;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];
 
                    // Calculate the distance between the two vectors.
                    fDistance = Vector2.Distance(vPosition1, vPosition2);

                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                               (double)(vPosition2.X - vPosition1.X));

                    // Stretch the pixel between the two vectors.
                    _spriteBatch.Draw(m_Pixel,
                                      m_vPosition + vPosition1,
                                      null,
                                      m_Color,
                                      fAngle,
                                      new Vector2(0, 0.5f),
                                      new Vector2(fDistance, m_fThickness),
                                      SpriteEffects.None,
                                      m_fDepth);
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render the lines of the primitive.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            /// <param name="_fAngle">The counterclockwise rotation in radians. (0.0f is default).</param>
            /// <param name="_vPivot">Position in which to rotate around.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderLinePrimitive(SpriteBatch _spriteBatch, float _fAngle, Vector2 _vPivot)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count < 2)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Rotate object based on pivot.
                Rotate(_fAngle, _vPivot);
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero;
                float fDistance = 0f, fAngle = 0f;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];

                    // Calculate the distance between the two vectors.
                    fDistance = Vector2.Distance(vPosition1, vPosition2);


                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                               (double)(vPosition2.X - vPosition1.X));

                    // Stretch the pixel between the two vectors.
                    _spriteBatch.Draw(m_Pixel,
                                      m_vPosition + vPosition1,
                                      null,
                                      m_Color,
                                      fAngle,
                                      new Vector2(0, 0.5f),
                                      new Vector2(fDistance, m_fThickness),
                                      SpriteEffects.None,
                                      m_fDepth);
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            private Texture2D CreateRectangle(int width, int height, GraphicsDevice GD)
            {
                Texture2D rectangleTexture = new Texture2D(GD, width, height, 1, TextureUsage.None,
                SurfaceFormat.Color);// create the rectangle texture, ,but it will have no color! lets fix that

               Color[] color = new Color[width * height];//set the color to the amount of pixels in the textures

                 for (int i = 0; i < color.Length; i++)//loop through all the colors setting them to whatever values we want
                {
                    color[i] = new Color(0, 0, 0, 255);
                }
                rectangleTexture.SetData(color);//set the color data on the texture
                return rectangleTexture;//return the texture
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render primitive by using a square algorithm.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderSquarePrimitive(SpriteBatch _spriteBatch)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count < 2)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero, vLength = Vector2.Zero;
                float fDistance = 0f, fAngle = 0f;
                int nCount = 0;
                //
                //////////////////////////////////////////////////////////////////////////
                _spriteBatch.Draw(myTexture, Position, Color.White);
                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    //////////////////////////////////////////////////////////////////////////
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Calculate the distance between the two vectors.
                    fDistance = Vector2.Distance(vPosition1, vPosition2);

                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                               (double)(vPosition2.X - vPosition1.X));

                    // Calculate length.
                    vLength = vPosition2 - vPosition1;
                    vLength.Normalize();

                    // Calculate count for roundness.
                    nCount = (int)Math.Round(fDistance);
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Run through and render the primitive.
                    while (nCount-- > 0)
                    {
                        // Increment position.
                        vPosition1 += vLength;

                        // Stretch the pixel between the two vectors.
                        _spriteBatch.Draw(m_Pixel,
                                          m_vPosition + vPosition1,
                                          null,
                                          m_Color,
                                          0,
                                          Vector2.Zero,
                                          m_fThickness,
                                          SpriteEffects.None,
                                          m_fDepth);
                    }
                    //
                    //////////////////////////////////////////////////////////////////////////
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render primitive by using a square algorithm.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            /// <param name="_fAngle">The counterclockwise rotation in radians. (0.0f is default).</param>
            /// <param name="_vPivot">Position in which to rotate around.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderSquarePrimitive(SpriteBatch _spriteBatch, float _fAngle, Vector2 _vPivot)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count < 2)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Rotate object based on pivot.
                Rotate(_fAngle, _vPivot);
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero, vLength = Vector2.Zero;
                float fDistance = 0f, fAngle = 0f;
                int nCount = 0;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    //////////////////////////////////////////////////////////////////////////
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Calculate the distance between the two vectors.
                    fDistance = Vector2.Distance(vPosition1, vPosition2);
 
                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                               (double)(vPosition2.X - vPosition1.X));

                    // Calculate length.
                    vLength = vPosition2 - vPosition1;
                    vLength.Normalize();

                    // Calculate count for roundness.
                    nCount = (int)Math.Round(fDistance);
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Run through and render the primitive.
                    while (nCount-- > 0)
                    {
                        // Increment position.
                        vPosition1 += vLength;

                        // Stretch the pixel between the two vectors.
                        _spriteBatch.Draw(m_Pixel,
                                          m_vPosition + vPosition1,
                                          null,
                                          m_Color,
                                          0,
                                          Vector2.Zero,
                                          m_fThickness,
                                          SpriteEffects.None,
                                          m_fDepth);
                    }
                    //
                    //////////////////////////////////////////////////////////////////////////
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render primitive by using a round algorithm.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderRoundPrimitive(SpriteBatch _spriteBatch)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count < 2)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero, vLength = Vector2.Zero;
                float fDistance = 0f, fAngle = 0f;
                int nCount = 0;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    //////////////////////////////////////////////////////////////////////////
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Calculate the distance between the two vectors.
                    fDistance = Vector2.Distance(vPosition1, vPosition2);

                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),\
                                               (double)(vPosition2.X - vPosition1.X));

                    // Calculate length.
                    vLength = vPosition2 - vPosition1;
                    vLength.Normalize();

                    // Calculate count for roundness.
                    nCount = (int)Math.Round(fDistance);
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Run through and render the primitive.
                    while (nCount-- > 0)
                    {
                        // Increment position.
                        vPosition1 += vLength;

                        // Stretch the pixel between the two vectors.
                        _spriteBatch.Draw(m_Pixel,
                                          m_vPosition + vPosition1 + 0.5f * (vPosition2 - vPosition1),
                                          null,
                                          m_Color,
                                          fAngle,
                                          new Vector2(0.5f, 0.5f),
                                          new Vector2(fDistance, m_fThickness),
                                          SpriteEffects.None,
                                          m_fDepth);
                    }
                    //
                    //////////////////////////////////////////////////////////////////////////
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render primitive by using a round algorithm.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            /// <param name="_fAngle">The counterclockwise rotation in radians. (0.0f is default).</param>
            /// <param name="_vPivot">Position in which to rotate around.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderRoundPrimitive(SpriteBatch _spriteBatch, float _fAngle, Vector2 _vPivot)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count < 2)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Rotate object based on pivot.
                Rotate(_fAngle, _vPivot);
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero, vLength = Vector2.Zero;
                float fDistance = 0f, fAngle = 0f;
                int nCount = 0;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    //////////////////////////////////////////////////////////////////////////
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Calculate the distance between the two vectors.
                    fDistance = Vector2.Distance(vPosition1, vPosition2);

                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                               (double)(vPosition2.X - vPosition1.X));

                    // Calculate length.
                    vLength = vPosition2 - vPosition1;
                    vLength.Normalize();

                    // Calculate count for roundness.
                    nCount = (int)Math.Round(fDistance);
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Run through and render the primitive.
                    while (nCount-- > 0)
                    {
                        // Increment position.
                        vPosition1 += vLength;

                        // Stretch the pixel between the two vectors.
                        _spriteBatch.Draw(m_Pixel,
                                          m_vPosition + vPosition1 + 0.5f * (vPosition2 - vPosition1),
                                          null,
                                          m_Color,
                                          fAngle,
                                          new Vector2(0.5f, 0.5f),
                                          new Vector2(fDistance, m_fThickness),
                                          SpriteEffects.None,
                                          m_fDepth);
                    }
                    //
                    //////////////////////////////////////////////////////////////////////////
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render primitive by using a point and line algorithm.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderPolygonPrimitive(SpriteBatch _spriteBatch)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count < 2)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero;
                float fDistance = 0f, fAngle = 0f;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    //////////////////////////////////////////////////////////////////////////
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Calculate the distance between the two vectors.
                    fDistance = Vector2.Distance(vPosition1, vPosition2);

                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                               (double)(vPosition2.X - vPosition1.X));
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Stretch the pixel between the two vectors.
                    _spriteBatch.Draw(m_Pixel,
                                      Position + vPosition1 + 0.5f * (vPosition2 - vPosition1),
                                      null,
                                      m_Color,
                                      fAngle,
                                      new Vector2(0.5f, 0.5f),
                                      new Vector2(fDistance, Thickness),
                                      SpriteEffects.None,
                                      m_fDepth);

                    // Render the points of the polygon.
                    _spriteBatch.Draw(m_Pixel,
                                      m_vPosition + vPosition1,
                                      null,
                                      m_Color,
                                      fAngle,
                                      new Vector2(0.5f, 0.5f),
                                      m_fThickness,
                                      SpriteEffects.None,
                                      m_fDepth);
                    //
                    //////////////////////////////////////////////////////////////////////////
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }

            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Render primitive by using a point and line algorithm.
            /// </summary>
            /// <param name="_spriteBatch">The sprite batch to use to render the primitive object.</param>
            /// <param name="_fAngle">The counterclockwise rotation in radians. (0.0f is default).</param>
            /// <param name="_vPivot">Position in which to rotate around.</param>
            //////////////////////////////////////////////////////////////////////////
            public void RenderPolygonPrimitive(SpriteBatch _spriteBatch, float _fAngle, Vector2 _vPivot)
            {
                //////////////////////////////////////////////////////////////////////////
                // Validate.
                if (m_VectorList.Count < 2)
                    return;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Rotate object based on pivot.
                Rotate(_fAngle, _vPivot);
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Local variables.
                Vector2 vPosition1 = Vector2.Zero, vPosition2 = Vector2.Zero;
                float fDistance = 0f, fAngle = 0f;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Run through the list of vectors.
                for (int i = m_VectorList.Count - 1; i >= 1; --i)
                {
                    //////////////////////////////////////////////////////////////////////////
                    // Store positions.
                    vPosition1 = m_VectorList[i - 1];
                    vPosition2 = m_VectorList[i];
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Calculate the distance between the two vectors.
                    fDistance = Vector2.Distance(vPosition1, vPosition2);

                    // Calculate the angle between the two vectors.
                    fAngle = (float)Math.Atan2((double)(vPosition2.Y - vPosition1.Y),
                                               (double)(vPosition2.X - vPosition1.X));
                    //
                    //////////////////////////////////////////////////////////////////////////

                    //////////////////////////////////////////////////////////////////////////
                    // Stretch the pixel between the two vectors.
                    _spriteBatch.Draw(m_Pixel,
                                      Position + vPosition1 + 0.5f * (vPosition2 - vPosition1),
                                      null,
                                      m_Color,
                                      fAngle,
                                      new Vector2(0.5f, 0.5f),
                                      new Vector2(fDistance, Thickness),
                                      SpriteEffects.None,
                                      m_fDepth);

                    // Render the points of the polygon.
                    _spriteBatch.Draw(m_Pixel,
                                      m_vPosition + vPosition1,
                                      null,
                                      m_Color,
                                      fAngle,
                                      new Vector2(0.5f, 0.5f),
                                      m_fThickness,
                                      SpriteEffects.None,
                                      m_fDepth);
                    //
                    //////////////////////////////////////////////////////////////////////////
                }
                //
                //////////////////////////////////////////////////////////////////////////
            }
            #endregion // Render Methods
            #region Public Methods
            //////////////////////////////////////////////////////////////////////////
            /// <summary>
            /// Rotate primitive object based on pivot.
            /// </summary>
            /// <param name="_fAngle">The counterclockwise rotation in radians. (0.0f is default).</param>
            /// <param name="_vPivot">Position in which to rotate around.</param>
            //////////////////////////////////////////////////////////////////////////
            public void Rotate(float _fAngle, Vector2 _vPivot)
            {
                //////////////////////////////////////////////////////////////////////////
                // Subtract pivot from all points.
                for (int i = m_VectorList.Count - 1; i >= 0; --i)
                    m_VectorList[i] -= _vPivot;
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Rotate about the origin.
                Matrix mat = Matrix.CreateRotationZ(_fAngle);
                for (int i = m_VectorList.Count - 1; i >= 0; --i)
                    m_VectorList[i] = Vector2.Transform(m_VectorList[i], mat);
                //
                //////////////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////////////
                // Add pivot to all points.
                for (int i = m_VectorList.Count - 1; i >= 0; --i)
                    m_VectorList[i] += _vPivot;
                //
                //////////////////////////////////////////////////////////////////////////
            }

            #endregion // Public Methods
        }
}


Lets take a moment to try out the BasicPrimitives class to understand how to use it.

controller3.1.gif

Here we created a public variable named Primative1.

controller3.2.gif

Now in our LoadContent Method we want to create a new Instance of the class and turn the primative into a square. We also set its position.
One thing that took a me a day to figure out was that when creating the square you aren't setting its position. I mistakenly created the square way out in the middle of the screen and couldn't figure out why when its position was zero the square wasnt aligning correctly to the left of the screen. So be careful when you are creating the square.

controller3.3.gif

In our Draw Method we call RenderSquarePrimitive and send it our spriteBatch so it can draw to the screen. The result is:

controller4.gif

Alright nothing groundbreaking yet but I wanted to show how the BasicPrimatives class is used.

Now delete those variables as we don't want a square blocking our view.

controller5.gif

This is my Diagram for Controller/Interface.

The Interface is the collection of buttons.

The Controller is responsible for managing which buttons are shown and handling user input.

AnimationState helps to show whether an Interface is doing the Intro, Outro animation or is still (in the Stacked Position).

SelectedButton is used to set in the Interface which button the user selected (this is because the actual selection is done in Controller (Remember it handles the user's input)).

Intro, Outro, and Initial: These classes simply make it easy for me to set the positions that I want the buttons to be in during the selected animation (or Initial which is where the buttons start from).

Button class holds the individual button information

So to recap:

Controller is the worker that organizes everything. There will be only 1.

Interface is a collection of buttons (In this case 4). There will be multiple Interfaces. Interfaces are setup in the Controller class when it is first created.

How will we control Interfaces / How do we know which one to go to when one is selected?
We will use a tree/node method.

controller6.gif

In this example you can hopefully see the logic of the Interfaces class. Each Instance will have a Parent Node that refers back to what would have spawned it as well as its Current Node number. Within each Button in Interface is the Next Node number.

So in the Controller class if we are on CurrentNode 0 and the user selects A. We know to move on to Node 3.

Ok, now lets get down to the code.

controller7.gif

Alright lets start by Create a class and naming it Controller.

controller8.gif

Lets start first with the enums. Nothing extremely exciting here.

With AnimationState we prepare for 3 states. Intro (when the buttons move from the left to the right), Outro (when the buttons move from the right to the left), and Still (This is when the buttons "Stack on the left").

With SelectedButton we prepare for 4 states. Whether A, B, X, or Y was selected for that Interface.

controller9.gif

Now lets move on to the 3 classes that represent the 3 positions of the buttons within the interface.

Initial: The starting position of the buttons. At its base this is all the way to the left and all in a column.(Note: this is adjusted in the code so that when the Interfaces are stacked the Initial Position is moved to compensate. However I still wanted a stable launching point of coordinates, thus this class).

Intro: This is the final position to the right that the buttons will end up in. (This doesn't need to be adjusted it will always remain at these values).

Outro: This is where the buttons rest to the left. (Note: this is adjusted to the right for the Stacked effect)

controller10.gif

Now for our Button Class:

The Pos is mainly for the Text within the box.
The Name is the Text.
The NextNode is where the button leads to the next Interface.
The Primative is the box that is drawn.

Lets now create our Interface Class

    //Interface (Collection of Buttons)
    public class Interface
    {
        const int MaxMoves = 10; //This controls how fast the animation occurs

        //Each Interface will have 4 Buttons
        public button ButtonA = new button();
        public button ButtonB = new button();
        public button ButtonX = new button();
        public button ButtonY = new button();

        //We need to know what Animation state the Interface is at.
        public AnimationState AnimState;
        //We need to know which button was selected (this is for the
        //stacked effect to only show which button was selected\
        public SelectedButton selectedButton;

        public int moves; //Used for Animation Movement
        public int Node; //The Interface Node
        public int ParentNode; //The Parent Interface Node

        public bool bMoving; //Whether or not an Animation is Occuring

        int Width = 48; //Width of the box

        //Create the 3 Positions
        public intro IntroPosition = new intro();
        public Outro OutroPosition = new Outro();
        public Initial InitialPosition = new Initial();
        //...................................................
 
        //For Displaying to the screen
        SpriteBatch spriteBatch;
        GraphicsDevice graphicsDevice;
        SpriteFont spriteFont;

        // Constructor
        public Interface(int Parentn, int currentNode, SpriteBatch spriteB, GraphicsDevice graphicsD, SpriteFont spf)
        {
            graphicsDevice = graphicsD;
            spriteBatch = spriteB;
            spriteFont = spf;
            ParentNode = Parentn;
            Node = currentNode;

            //Create the Primatives Through the Buttons
            ButtonA.Primative = new BasicPrimitives(graphicsDevice);
            ButtonA.Primative.CreateSquare(new Vector2(0, 0), new Vector2(Width * 2, Width / 2));

            ButtonB.Primative = new BasicPrimitives(graphicsDevice);
            ButtonB.Primative.CreateSquare(new Vector2(0, 0), new Vector2(Width * 2, Width / 2));

            ButtonX.Primative = new BasicPrimitives(graphicsDevice);
            ButtonX.Primative.CreateSquare(new Vector2(0, 0), new Vector2(Width * 2, Width / 2));

            ButtonY.Primative = new BasicPrimitives(graphicsDevice);
            ButtonY.Primative.CreateSquare(new Vector2(0, 0), new Vector2(Width * 2, Width / 2));
            //////////////////////////////////////////////////////////////////////////////////////

            //Set the initial Parameters
            SetPosition();
        }

        public void SetPosition()
        {//Set Initial parameters
            bMoving = false;
            moves = 0;
            AnimState = AnimationState.Still;

            ButtonA.Primative.Position = InitialPosition.ButtonA;
            ButtonB.Primative.Position = InitialPosition.ButtonB;
            ButtonX.Primative.Position = InitialPosition.ButtonX;
            ButtonY.Primative.Position = InitialPosition.ButtonY;
        }

        public void SetInitial(Outro PrevOutroPosition)
        {//PrevOutroPosition b/c the previous outro is current intro position

            //Reset the Initial position
            InitialPosition = new Initial();

            //Set InitialPosition to the Previous Interfaces Outro
            //This is because where the the other Interface Ends
            //the new Interface should begin.
            InitialPosition.ButtonA = PrevOutroPosition.ButtonA;
            InitialPosition.ButtonB = PrevOutroPosition.ButtonB;
            InitialPosition.ButtonX = PrevOutroPosition.ButtonX;
            InitialPosition.ButtonY = PrevOutroPosition.ButtonY;

            //Now set the box to that position.
            ButtonA.Primative.Position = InitialPosition.ButtonA;
            ButtonB.Primative.Position = InitialPosition.ButtonB;
            ButtonX.Primative.Position = InitialPosition.ButtonX;
            ButtonY.Primative.Position = InitialPosition.ButtonY;
        }

        public void SetOutro(int n)
        {
            //Set Outro parameters
            //n = the collection level
            //this gives us a stacked look
            OutroPosition = new Outro();
            OutroPosition.ButtonA = OutroPosition.ButtonA + (new Vector2(n, 0) * new Vector2(Width * 3, 0));
            OutroPosition.ButtonB = OutroPosition.ButtonB + (new Vector2(n, 0) * new Vector2(Width * 3, 0));
            OutroPosition.ButtonX = OutroPosition.ButtonX + (new Vector2(n, 0) * new Vector2(Width * 3, 0));
            OutroPosition.ButtonY = OutroPosition.ButtonY + (new Vector2(n, 0) * new Vector2(Width * 3, 0));
        }

        public bool Update()
        {//Returns true if object is moving, else return false
            Vector2 Direction;
            Vector2 Speed;

            //If an Animation is going
            if (bMoving)
            {
                //If in the Intro Animation
                if (AnimState == AnimationState.Intro)
                {
                    moves++;//Increase the movement counter

                    //This moves the A Primative to the IntroPosition
                    Direction = IntroPosition.ButtonA - ButtonA.Primative.Position;
                    if (moves < MaxMoves) Speed = Direction / (MaxMoves - moves);
                    else Speed = Direction;
                    Speed = new Vector2((int)Speed.X, (int)Speed.Y);
                    ButtonA.Primative.Position += Speed;

                    //This moves the B Primative to the IntroPosition
                    Direction = IntroPosition.ButtonB - ButtonB.Primative.Position;
                    if (moves < MaxMoves) Speed = Direction / (MaxMoves - moves);
                    else Speed = Direction;
                    Speed = new Vector2((int)Speed.X, (int)Speed.Y);
                    ButtonB.Primative.Position += Speed;

                    //This moves the X Primative to the IntroPosition
                    Direction = IntroPosition.ButtonX - ButtonX.Primative.Position;
                    if (moves < MaxMoves) Speed = Direction / (MaxMoves - moves);
                    else Speed = Direction;
                    Speed = new Vector2((int)Speed.X, (int)Speed.Y);
                    ButtonX.Primative.Position += Speed;

                    //This moves the Y Primative to the IntroPosition
                    Direction = IntroPosition.ButtonY - ButtonY.Primative.Position;
                    if (moves < MaxMoves) Speed = Direction / (MaxMoves - moves);
                    else Speed = Direction;
                    Speed = new Vector2((int)Speed.X, (int)Speed.Y);
                    ButtonY.Primative.Position += Speed;

                    //If moves >= MaxMoves then we are done
                    if (moves >= MaxMoves)
                    {
                        moves = 0; //reset moves
                        bMoving = false; //we are done Animating
                    }
                }

                //If in the Outro Animation
                if (AnimState == AnimationState.Outro)
                {
                    moves++; //Increases the movement counter

                    //This moves the A Primative to the OutroPosition
                    Direction = OutroPosition.ButtonA - ButtonA.Primative.Position;
                    if (moves < MaxMoves) Speed = Direction / (MaxMoves - moves);
                    else Speed = Direction;
                    Speed = new Vector2((int)Speed.X, (int)Speed.Y);
                    ButtonA.Primative.Position += Speed;

                    //This moves the B Primative to the OutroPosition
                    Direction = OutroPosition.ButtonB - ButtonB.Primative.Position;
                    if (moves < MaxMoves) Speed = Direction / (MaxMoves - moves);
                    else Speed = Direction;
                    Speed = new Vector2((int)Speed.X, (int)Speed.Y);
                    ButtonB.Primative.Position += Speed;

                    //This moves the X Primative to the OutroPosition
                    Direction = OutroPosition.ButtonX - ButtonX.Primative.Position;
                    if (moves < MaxMoves) Speed = Direction / (MaxMoves - moves);
                    else Speed = Direction;
                    Speed = new Vector2((int)Speed.X, (int)Speed.Y);
                    ButtonX.Primative.Position += Speed;

                    //This moves the Y Primative to the OutroPosition
                    Direction = OutroPosition.ButtonY - ButtonY.Primative.Position;
                    if (moves < MaxMoves) Speed = Direction / (MaxMoves - moves);
                    else Speed = Direction;
                    Speed = new Vector2((int)Speed.X, (int)Speed.Y);
                    ButtonY.Primative.Position += Speed;

                    //If moves >= MaxMoves then we are done
                    if (moves >= MaxMoves)
                    {
                        bMoving = false//we are done moving
                        moves = 0; //reset moves
                    }

                }

                //This is for setting the Button Position so that the Text is centered in the Box
                Vector2 Center = spriteFont.MeasureString(ButtonA.Name) / 2;
                ButtonA.Pos = ButtonA.Primative.Position + new Vector2((Width - Center.X), 0);

                Center = spriteFont.MeasureString(ButtonB.Name) / 2;
                ButtonB.Pos = ButtonB.Primative.Position + new Vector2((Width - Center.X), 0);

                Center = spriteFont.MeasureString(ButtonX.Name) / 2;
                ButtonX.Pos = ButtonX.Primative.Position + new Vector2((Width - Center.X), 0);

                Center = spriteFont.MeasureString(ButtonY.Name) / 2;
                ButtonY.Pos = ButtonY.Primative.Position + new Vector2((Width - Center.X), 0);
                /////////////////////////////////////////////////////////////////////////////////

                return true; //returns True, the object is Animating
            }

            return false; //returns False, the object is NOT Animating
        }

        public void Draw()
        {
            //If the Interface is not in the Stacked position (all the way to the left)
            if (AnimState != AnimationState.Still)
            {//Since we are not in the stacked position we want to show all the buttons
                //as long as the Name!=""
                if (ButtonA.Name != "") ButtonA.Primative.RenderSquarePrimitive(spriteBatch);
                if (ButtonB.Name != "") ButtonB.Primative.RenderSquarePrimitive(spriteBatch);
                if (ButtonX.Name != "") ButtonX.Primative.RenderSquarePrimitive(spriteBatch);
                if (ButtonY.Name != "") ButtonY.Primative.RenderSquarePrimitive(spriteBatch);
                spriteBatch.DrawString(spriteFont, ButtonA.Name, ButtonA.Pos, Color.White);
                spriteBatch.DrawString(spriteFont, ButtonB.Name, ButtonB.Pos, Color.White);
                spriteBatch.DrawString(spriteFont, ButtonX.Name, ButtonX.Pos, Color.White);
                spriteBatch.DrawString(spriteFont, ButtonY.Name, ButtonY.Pos, Color.White);
            }
            else
            {//We are in the stacked position, therefore only show the button that was selected
                if (selectedButton == SelectedButton.A)
                {
                    ButtonA.Primative.RenderSquarePrimitive(spriteBatch);
                    spriteBatch.DrawString(spriteFont, ButtonA.Name, ButtonA.Pos, Color.White);
                }

                if (selectedButton == SelectedButton.B)
                {
                    ButtonB.Primative.RenderSquarePrimitive(spriteBatch);
                    spriteBatch.DrawString(spriteFont, ButtonB.Name, ButtonB.Pos, Color.White);
                }

                if (selectedButton == SelectedButton.X)
                {
                    ButtonX.Primative.RenderSquarePrimitive(spriteBatch);
                    spriteBatch.DrawString(spriteFont, ButtonX.Name, ButtonX.Pos, Color.White);
                }

                if (selectedButton == SelectedButton.Y)
                {
                    ButtonY.Primative.RenderSquarePrimitive(spriteBatch);
                    spriteBatch.DrawString(spriteFont, ButtonY.Name, ButtonY.Pos, Color.White);
                }
            }
        }
    }


For our Interface Class we:
Create 4 Buttons
Create InitialPosition, OutroPosition, and IntroPosition
Since we want the Interface to Display to the screen we create the SpriteBatch, SpriteFont, and GraphicsDevice
AnimState: Our tracker for telling which animation the Interface is on
ButtonSelected: Our tracker for which button on the Interface is selected.
Width: The width of the Buttons
MaxMoves: Controls the speed of the Animation
Node: Interface Identifying Node
ParentNode: The Node it came from

For the Methods()

Constructor(): Gets passed spriteBatch, graphicsDevice, and spriteFont from the Controller Class. Sets Identifying Node and its Parent Node. The Constructor also sets up the Button Primatives and sets their initial positions.

Update(): Responsible for moving the Animation along. It also aligns the text to the center of the Box. Returns true or false if there is Animation to the Controller (this allows us to not accept input while an Animation is playing).

Draw(): Draws the Interface to the screen. Based off the AnimationState it will either draw all the buttons, or only the selected one.

Finally, lets add the last class, the Controller Class:

   //Controller (Responsible for directing and collecting the Interfaces)
    public class Controller
    {
        //Layout will contain all the Interfaces that will be created. They are
        //referenced by (int) node
        Dictionary<int, Interface> Layout = new Dictionary<int, Interface>();

        //This is a collection of (int) that reference Layout.
        //Every time a button is selected a new int(that references an Interface)
        //is added to the List.
        public List<int> Connections = new List<int>();

        // Used for the delay in selecting a button and when its Animation ends.
        int CurrentNode;
        int NextNode;

        // Determining which button was pressed
        string ButtonPressed = "";

        SpriteBatch spriteBatch;
        SpriteFont spriteFont;
        GraphicsDevice graphicsDevice;

        GamePadState OldState;
        GamePadState NewState;

        // For setting up the Different Interfaces
        Interface CurrentConfig;

        //Constructor
        public Controller(GraphicsDevice gd, SpriteFont sf, SpriteBatch sb)
            : base()
        {
            spriteBatch = sb;
            spriteFont = sf;
            graphicsDevice = gd;
            //Set CurrentNode to the Interface Node 0
            CurrentNode = 0;
            //Now add that Interface to the Connetions List<int>
            Connections.Add(0);
            Load();
        }

        protected void Load()
        {

            //Setup the Interfaces
            CurrentConfig = new Interface(0, 0, spriteBatch, graphicsDevice, spriteFont);
            CurrentConfig.ButtonA.Name = "Action";
            CurrentConfig.ButtonB.Name = "";
            CurrentConfig.ButtonX.Name = "Inventory";
            CurrentConfig.ButtonY.Name = "Menu";
            CurrentConfig.ButtonA.NextNode = 1;
            CurrentConfig.ButtonB.NextNode = 0;
            CurrentConfig.ButtonX.NextNode = 2;
            CurrentConfig.ButtonY.NextNode = 4;
            Layout.Add(0, CurrentConfig);

            CurrentConfig = new Interface(0, 1, spriteBatch, graphicsDevice, spriteFont);
            CurrentConfig.ButtonA.Name = "GoTo";
            CurrentConfig.ButtonB.Name = "Back";
            CurrentConfig.ButtonX.Name = "Investigate";
            CurrentConfig.ButtonY.Name = "Use";
            CurrentConfig.ButtonA.NextNode = 5;
            CurrentConfig.ButtonB.NextNode = CurrentConfig.ParentNode;
            CurrentConfig.ButtonX.NextNode = 6;
            CurrentConfig.ButtonY.NextNode = 7;
            Layout.Add(1, CurrentConfig);

            CurrentConfig = new Interface(0, 2, spriteBatch, graphicsDevice, spriteFont);
            CurrentConfig.ButtonA.Name = "Item";
            CurrentConfig.ButtonB.Name = "Back";
            CurrentConfig.ButtonX.Name = "Equip";
            CurrentConfig.ButtonY.Name = "Character";
            CurrentConfig.ButtonA.NextNode = 8;
            CurrentConfig.ButtonB.NextNode = CurrentConfig.ParentNode;
            CurrentConfig.ButtonX.NextNode = 9;
            CurrentConfig.ButtonY.NextNode = 10;
            Layout.Add(2, CurrentConfig);

            CurrentConfig = new Interface(0, 3, spriteBatch, graphicsDevice, spriteFont);
            CurrentConfig.ButtonA.Name = "Sound";
            CurrentConfig.ButtonB.Name = "Back";
            CurrentConfig.ButtonX.Name = "Gameplay";
            CurrentConfig.ButtonY.Name = "Graphics";
            CurrentConfig.ButtonA.NextNode = 11;

            CurrentConfig.ButtonB.NextNode = CurrentConfig.ParentNode;
            CurrentConfig.ButtonX.NextNode = 12;
            CurrentConfig.ButtonY.NextNode = 13;
            Layout.Add(3, CurrentConfig);

            CurrentConfig = new Interface(1, 5, spriteBatch, graphicsDevice, spriteFont);
            CurrentConfig.ButtonA.Name = "Library";
            CurrentConfig.ButtonB.Name = "Back";
            CurrentConfig.ButtonX.Name = "School";
            CurrentConfig.ButtonY.Name = "Cafe";
            CurrentConfig.ButtonA.NextNode = 14;
            CurrentConfig.ButtonB.NextNode = CurrentConfig.ParentNode;
            CurrentConfig.ButtonX.NextNode = 15;
            CurrentConfig.ButtonY.NextNode = 16;
            Layout.Add(5, CurrentConfig);

            //Setup the Node 0 to Animate right away
            Layout[CurrentNode].SetPosition();
            Layout[CurrentNode].bMoving = true;
            Layout[CurrentNode].AnimState = AnimationState.Intro;
        }
 
        public void Update()
        {
            bool bCantUpdate = false;

            //step through all the int in Connections
            foreach (int i in Connections)
            {   //If Update returns true (and therefore one of the Connections is Animating)
                if (Layout[i].Update())
                {
                    bCantUpdate = true; //Dont Update Input
                }
            }

            //If we aren't updating
            if (bCantUpdate == false)
            {    //Get new user input
                InputUpdate();
            }

            //determine if we should add or delete node in connections
            if (Layout[CurrentNode].bMoving == false)
            {   //This handles adding or deleting nodes from the Connections List<int>
                ProcessConnections();
            }

       }

         public void ProcessConnections()
        {
            //If we have more than one Connection in the List<int>
            //Therefor we are deeper than the 0 Node
            if (Connections.Count > 1)
            {
                //Set CurrentInterface to the Last Interface in Connections List<int>
                //(which is the current Interface)
                Interface CurrentInterface = Layout[Connections[Connections.Count - 1]];

                //If our Current Interface has stopped Animating AND the AnimationState is Outro
                if (CurrentInterface.bMoving == false && CurrentInterface.AnimState == AnimationState.Outro)
                {
                    //If the button was B
                    //(We are Exiting an Interface)
                    if (ButtonPressed == "B")
                    {
                        //We are done with the Outro so set state to Still
                        CurrentInterface.AnimState = AnimationState.Still;

                        //Remove the CurrentNode (which was grabbed in InputUpdate)
                        Connections.Remove(CurrentNode);

                        //Now set the NextNode to Animating and to the Intro state
                        Layout[NextNode].bMoving = true;
                        Layout[NextNode].AnimState = AnimationState.Intro;

                        ///Our CurrentNode is now NextNode
                        CurrentNode = NextNode;
                    }
                    else
                    {//We are adding an Interface
                        //We are done with the Outro so set state to Still
                        Layout[CurrentNode].AnimState = AnimationState.Still;

                        //Add the NextNode (which was grabbed in InputUpdate)
                        Connections.Add(NextNode);

                        //Now set the new Interface to its Initial Position
                        //(Based off of the old Outro Position --this creates the stacked look)
                        Layout[NextNode].SetInitial(Layout[CurrentNode].OutroPosition);
                        //Now set the Animation into motion and set it to Intro
                        Layout[NextNode].bMoving = true;
                        Layout[NextNode].AnimState = AnimationState.Intro;

                        //Our CurrentNode is now NextNode...
                        CurrentNode = NextNode;
                    } 

                }
            }
            else
            {//We are on the 0 Node (Note there is no need to check for B since we are at 0 Node)
                //If our Current Interface has stopped Animating AND the AnimationState is Outro
                if (Layout[CurrentNode].bMoving == false && Layout[CurrentNode].AnimState == AnimationState.Outro)
                {
                    //We are done with the Outro so set state to Still
                    Layout[CurrentNode].AnimState = AnimationState.Still;
 
                    //Add the NextNode (which was grabbed in InputUpdate)
                    Connections.Add(NextNode);

                    //Now set the new Interface to its Initial Position
                    //(Based off of the old Outro Position --this creates the stacked look)
                    Layout[NextNode].SetInitial(Layout[CurrentNode].OutroPosition);
                    //Now set the Animation into motion and set it to Intro
                    Layout[NextNode].bMoving = true;
                    Layout[NextNode].AnimState = AnimationState.Intro;

                    //Our CurrentNode is now NextNode...
                    CurrentNode = NextNode;
                }
            }
        }

        public void InputUpdate()
        {
            //Set the NewState to our Current Gamepad
            NewState = GamePad.GetState(PlayerIndex.One);

            //If A
            if (GamePad.GetState(PlayerIndex.One).Buttons.A == ButtonState.Pressed && OldState.Buttons.A == ButtonState.Released)
            {   //If The Node exists in Layout
                if (Layout.ContainsKey(Layout[CurrentNode].ButtonA.NextNode))
                {
                    //Set Current Interface to start Animating
                    Layout[CurrentNode].bMoving = true;
                    //Set Current Interface to Outro Animation
                    Layout[CurrentNode].AnimState = AnimationState.Outro;
                    //Set Outro Position to the Latest Interface COUNT in Connections
                    Layout[CurrentNode].SetOutro(Connections.Count - 1);
                    //Set Current Interface Selected Button to A
                    Layout[CurrentNode].selectedButton = SelectedButton.A;
                    //Set Controller ButtonPressed to A
                    ButtonPressed = "A";

                    //Set the Upcoming Node to the Current Interface ButtonA's NextNode
                    //(It wont be added to Connections until ProcessConnections) this allows
                    //the animation to complete before the new node is processed
                    NextNode = Layout[CurrentNode].ButtonA.NextNode;

                }
            }

            //If B
            if (GamePad.GetState(PlayerIndex.One).Buttons.B == ButtonState.Pressed && OldState.Buttons.B == ButtonState.Released)
            {   //If we are not on node 0
                //(if we were B wouldnt matter since its purpose is to back us up through the menu's)
                if (CurrentNode > 0)
                {
                    //Set Current Interface to start Animating
                    Layout[CurrentNode].bMoving = true;
                    //Set Current Interface to Outro Animation
                    Layout[CurrentNode].AnimState = AnimationState.Outro;
                    //Set Outro Position to the Parent Node's OutroPosition
                    Layout[CurrentNode].OutroPosition = Layout[Layout[CurrentNode].ParentNode].OutroPosition;
                    //Set NextNode to the ParentNode
                    NextNode = Layout[CurrentNode].ParentNode;
                    //Set Controller Button Pressed to B
                    ButtonPressed = "B";
 
                }
            }

            //If X
            if (GamePad.GetState(PlayerIndex.One).Buttons.X == ButtonState.Pressed && OldState.Buttons.X == ButtonState.Released)
            {   //If The Node exists in Layout
                if (Layout.ContainsKey(Layout[CurrentNode].ButtonX.NextNode))
                {
                    //Set Current Interface to start Animating
                    Layout[CurrentNode].bMoving = true;
                    //Set Current Interface to Outro Animation
                    Layout[CurrentNode].AnimState = AnimationState.Outro;
                    //Set Outro Position to the Latest Interface COUNT in Connections
                    Layout[CurrentNode].SetOutro(Connections.Count - 1);
                    //Set Current Interface Selected Button to X
                    Layout[CurrentNode].selectedButton = SelectedButton.X;
                    //Set Controller ButtonPressed to X

                    ButtonPressed = "X";
                    //Set the Upcoming Node to the Current Interface ButtonX's NextNode
                    //(It wont be added to Connections until ProcessConnections) this allows
                    //the animation to complete before the new node is processed
                    NextNode = Layout[CurrentNode].ButtonX.NextNode;
                }
            }

            if (GamePad.GetState(PlayerIndex.One).Buttons.Y == ButtonState.Pressed && OldState.Buttons.Y == ButtonState.Released)
            {
                if (Layout.ContainsKey(Layout[CurrentNode].ButtonY.NextNode))
                {
                    //Set Current Interface to start Animating
                    Layout[CurrentNode].bMoving = true;
                    //Set Current Interface to Outro Animation
                    Layout[CurrentNode].AnimState = AnimationState.Outro;
                    //Set Outro Position to the Latest Interface COUNT in Connections
                    Layout[CurrentNode].SetOutro(Connections.Count - 1);
                    //Set Current Interface Selected Button to Y
                    Layout[CurrentNode].selectedButton = SelectedButton.Y;
                    //Set Controller ButtonPressed to Y
                    ButtonPressed = "Y";
                    //Set the Upcoming Node to the Current Interface ButtonY's NextNode
                    //(It wont be added to Connections until ProcessConnections) this allows
                    //the animation to complete before the new node is processed
                    NextNode = Layout[CurrentNode].ButtonY.NextNode;
                }
            }

            //Set OldState to the NewState (This is to prevent button from being held down)
            OldState = NewState;
        }

        public void Draw()
        {

            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.None);

            //Revers order when stepping through Connections so that Interfaces Overlap Correctly
            foreach (int i in Connections.Reverse<int>())
            {   //Draw each Interface
                Layout[i].Draw();
            }

            spriteBatch.End();

        }

    }

For our Controller class we:
Create our Dictionary Layout. It contains Interfaces that are identified through int (their nodes).

Create our List<int> Connections. This is a list of nodes that references the Interfaces. Each time a button is properly selected an int representing an Interfaces is added to the list.

CurrentNode and NextNode: Used in the delay when an Animation is occurring and when an Interface is added or removed from the Connections List.

ButtonPressed: Used in determining which button was selected after an Animation is finished. (To know whether to delete or add to the Connections List)

SpriteBatch, SpriteFont, graphicsDevice: Gathered from the Game1 class and passed to this class so it can be passed to the Interfaces.

GamePadStates: Used in gathering input from the user.

CurrentConfig: This is used in created our Interfaces. During the load method of this class all the interfaces are created. I use just this one variable and = new Interface() repeatedly to create all the interfaces until I'm done.

Methods():

Construct(): Takes in the spriteBatch, graphicsDevice, and spriteFont from the Game1 class. It also sets the CurrentNode to 0 (since this is when we first create the Instance of this class we want to start at the base level) and adds it to our Connections List<int>. It then calls Load() so that all our interfaces can be created and added to the dictionary.

Load(): Creates all our Interfaces and adds them to the dictionary. It then sets the CurrentInterface (which is the base Node 0) to start Animating and sets its Animation to Intro. It also sets its Initial Position by calling Interface.SetPosition()

Update(): Steps through the Connections and for each Interface it runs their Update(). If any Interface is Animating then it will skip the InputUpdate otherwise it checks for user input by calling InputUpdate(). If the current Interface is not Animating then it calls ProcessConnections, which adds or deletes nodes from Connections List.

InputUpdate(): Checks for user input and acts accordingly.

ProcessConnections(): If user selected B then remove node from Connections. Otherwise add a node to Connections. Then set the Animation to start on the Current Node and set it to Intro.

Draw(): For each Interface referenced in Connections call their Draw() but in reverse order. This is so that buttons behind buttons appear correctly.


Now lets move on to the Game1 Class:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace ControllerTutorial
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        SpriteFont spriteFont;
        Controller MyController;

        public BasicPrimitives Primative1;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
            MyController = new Controller(GraphicsDevice, spriteFont, spriteBatch);
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            //Setup the spriteFont 
          spriteFont = Content.Load<SpriteFont>("Font1");

             // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // TODO: Add your update logic here

            MyController.Update();

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            MyController.Draw();

            base.Draw(gameTime);
        }
    }
}


Not really much to note.

Create a Controller

Setup the Controller

Update Controller during Update()

and Draw Controller during Draw()

Well this is the end of the tutorial. By now you should have a simple button interface you can use. If anyone knows of a better way or even different way of doing things then feel free to let me know about it.


Similar Articles