Role-Playing Game Tutorial 3

There is a new home for my XNA 3.0 RPG Tutorials

http://www.jtmbooks.com/rpgtutorials/project.html

 


You can download the soure code and images here: Button Tutorial

In this tutorial I will show you how to create a GUI button control using XNA. I've tried to make the control extendable so it can be added to the project later. The control works pretty good but it is not quite perfect. I included changing the color of the button by hovering over it and how to check to see if it has been clicked. Later I will change the control to be a game component.

To get started you need to create an XNA Windows game project. Once the project has been created you will have to add a class to the project, call it Button. You will have to add three using statements to the class because it will use parts of the XNA Framework. You need one for the Framework, one for Graphcs and one for Input. These are the using statements:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input; 

I've added several fields to the class. One for the texture for the button, the font the button will use, The location of the button on the screen, the text to be displayed on the button, the location of the text in the button, a SpriteBatch, a variable to hold the current state of the mouse and the last state of the mouse. I also added a field to say the button was clicked and one for text that will be displayed when the button is clicked. These last two will not appear in the final version.

Here are all the fields for the button:

Texture2D image;
SpriteFont font;
Rectangle location;
string text;
Vector2 textLocation;
SpriteBatch spriteBatch;
MouseState mouse;
MouseState oldMouse;
bool clicked = false;
string clickText = "Button was Clicked!";

The field that might require explanation is the location field. I used a Rectangle instead of a Vector2. I did this because I wanted to use the first overload of the Draw method and I wanted to be able to scale the control later.

With that done, I will give the rest of the code for the Button class and then go over the highlight. You will see that I made the fields private and only exposed a few of them These are the fields:

public Button(Texture2D texture, SpriteFont font, SpriteBatch sBatch)
{
    image = texture;
    this.font = font;
    location = new Rectangle(0, 0, image.Width, image.Height);
    spriteBatch = sBatch;
}

public string Text
{
    get { return text; }
    set
    {
        text = value;
        Vector2 size = font.MeasureString(text); 
        textLocation = new Vector2();
        textLocation.Y = location.Y + ((image.Height / 2) - (size.Y / 2));
        textLocation.X = location.X + ((image.Width / 2) - (size.X / 2)); }
}

public void Location(int x, int y)
{
    location.X = x;
    location.Y = y;
}

public void Update()
{
    mouse = Mouse.GetState();
   
    if (mouse.LeftButton == ButtonState.Released && oldMouse.LeftButton == ButtonState.Pressed)
    {
        if (location.Contains(new Point(mouse.X, mouse.Y)))
        {
            clicked = true;
        }
    }

    Text = "Click Me";
    oldMouse = mouse;
}

public void Draw()
{
    spriteBatch.Begin(SpriteBlendMode.AlphaBlend);

    if (location.Contains(new Point(mouse.X, mouse.Y)))
    {
        spriteBatch.Draw(image,
            location, 
            Color.Silver);
    }
    else
    {
        spriteBatch.Draw(image, 
            location,
            Color.White);
    }

    spriteBatch.DrawString(font,
        text,
        textLocation,
        Color.Black);

    if (clicked)
    {
        Vector2 position = new Vector2(10, 75);
        spriteBatch.DrawString(font,
            clickText,
            position,
            Color.White);
    }

    spriteBatch.End();
}

The constructor of the Button class takes three parameters: the image for the button, the font for the button and a SpriteBatch object. I don't think I did anything in the constructor that needs explanation.

The Text property may require a little explanation. The get is simple, it just returns the text. It is the set that is interesting. In the set the text field to the value passed. Then I get the size of the text to be written in the button. After that I create a vector to hold where the text will be drawn. Then I did a little magic. I take the size of the button, divide that by 2, find the size of the text and divide that by 2. Subtract that from the height or width of the button and add it to the X and Y coordinates of the button to center the text in the button.

I used a method to set the location of the button on the screen.

In the Update method I get the state of the mouse. I check to see if the left button has been pressed and released. If the location of where the mouse has been clicked is inside the control, I set clicked to true. You will see that I keep setting the text of the button using the Text property. I found that if I didn't do this it would not draw properly in the control.

Finally there is the Draw method.  I probably could have made a field for the hover event but I just checked if the mouse was inside the button in the Draw method. The Draw method is like the Draw method in the Game class. It makes a call to Begin of the SpriteBatch setting it to AlphaBlend because I made the corners a little rounded. If the mouse is inside the button it draws the button, tinting the button silver, otherwise it draws the button with no tint. Then it draws the text inside the button. Finally, if the button has been clicked it draws a message on the screen.

That is all for the Button class. It is time to turn your attention to the Game1.cs file. I've added the code and the image I used for the button. You will have to download this to get the image for the button. Once you unzipped the file you will need to add the image to the Content folder. You will also need to add a SpriteFont to the Conent folder. You do this by right clicking the Conent folder and adding a new item. Click SpriteFont and call it myFont.

Go ahead and add these two variables to your program:

Button button;
SpriteFont myFont;

Before you can use the mouse, you have to make it visible. You do that by setting the IsMouseVisible property to true. I did it in the Initialize method. Here's the code:

protected override void Initialize()
{
    IsMouseVisible = true;

    base.Initialize();
}

Now it is time to turn your attention to the LoadContent method. In the LoadConent method you will load in the texture for the button and the SpriteFont, then create the button. I don't think that there is anything that you are not familiar with so I'm just going to give you the code.

protected override void LoadContent()
{
      // Create a new SpriteBatch, which can be used to draw textures.

      spriteBatch = new SpriteBatch(GraphicsDevice);

    Texture2D texture;
    texture = Content.Load("button");
    myFont = Content.Load("myFont");
    button = new Button(texture, myFont, spriteBatch);
}

Now it is time for the Update method. All the Update method does is set the location of the button and call the button's Update method. Here's the code:

protected override void Update(GameTime gameTime)
{
      // Allows the game to exit
      if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

    button.Location(10, 10);
    button.Update();
      base.Update(gameTime);

That just leaves the Draw method. All the Draw method does is call the button's Draw method.

protected override void Draw(GameTime gameTime)
{
      GraphicsDevice.Clear(Color.CornflowerBlue);
    button.Draw();
      base.Draw(gameTime);
}  

Well, that is all you need to do to create a simple button.

Thanks again for reading this.