Sunday, April 8, 2007

XNA Tutorial 2: Cursors and Buttons




The second tutorial in a hopefully long list. This tutorial will cover how to create a cursor in XNA, check to see if you have clicked on a button.
First thing you need to do is gather the artwork. You need a cursor, a button, an image that represents Hovering, and another that represents Clicking.
Create your Windows Game project with the name of something like Cursors-Buttons Example.
Add the artwork to the project.
The way we're going to do this is we're going to create a mouseHandler class that will handle drawing the mouse and changing it's position to wherever the mouse is, giving the effect of a cursor. We'll also create a button class that will handle it's own drawing and will be used with a MouseHandler function to check if it's being hovered over which will lead to checking if it's being clicked.
We'll add the button to a Button list that we'll go through during the Draw function to draw every button in the list (only one). We just hardcode the other sprites to appear depending on if we're hovering over the button or clicking it respectively.
On the update we check if we click and/or hover over the button.
Beggining variables:

SpriteBatch batch; //Needed for 2D drawing
MouseHandler ourMouse; //An instance of the MouseHandler class
Texture2D onHover; //The Hover image texture
Texture2D onClick; //The Click image texxture
Vector2 hoverPos; //The position of the Hover sprite
Vector2 clickPos; //The position of the Click sprite
List <>buttonlist; //Our list of buttons
Button mainButton; //An instance of Button
bool Clicking; //Are we clicking?
bool Hovering; //Are we hovering?
MouseState mouseState; //MouseState needed for what checking our mouseClicks and location
That's all pretty much goes without saying, MouseHandler and Button are classes that I created, we will go over them right now.
The MouseHandler class goes in it's own .cs file.
Dependencies:

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
Code:

class MouseHandler
{
private Vector2 pos;
private Texture2D tex;
private MouseState mouseState;
//We create variables

public MouseHandler(Vector2 pos, Texture2D tex)
{
this.pos = pos; //Inital pos (0,0)
this.tex = tex; //Cursor texture
}
//On Update we will call this function
public void Update()
{
mouseState = Mouse.GetState(); //Needed to find the most current mouse states.
this.pos.X = mouseState.X; //Change x pos to mouseX
this.pos.Y = mouseState.Y; //Change y pos to mouseY
}
//Drawing function to be called in the main Draw function.
public void Draw(SpriteBatch batch) //SpriteBatch to use.
{
batch.Draw(this.tex, this.pos, Color.White); //Draw it using the batch.
}

public bool ButtonClick(Button b)
{
if (this.pos.X >= b.position.X // To the right of the left side
&& this.pos.X < b.position.X + b.tex.Width //To the left of the right side
&& this.pos.Y > b.position.Y //Below the top side
&& this.pos.Y < b.position.Y + b.tex.Height) //Above the bottom side
return true; //We are; return true.
else
return false; //We're not; return false.
}
That's it for the mouseHandler class.
The button class:
Dependencies:

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
Code:

class Button
{
public Vector2 position;
public Texture2D tex;
//Set up variables
public Button(Vector2 position, Texture2D tex) //Our constructor
{
this.position = position; //Position in 2D
this.tex = tex; //Our texture to draw
}
public void Draw(SpriteBatch batch) //Draw function, same as mousehandler one.
{
batch.Draw(tex, position, Color.White);
}
}
Alright, almost done.

batch = new SpriteBatch(graphics.GraphicsDevice); //A SpriteBatch is born.

//Handle the button creation
mainButton = new Button(new Vector2(250, 100), content.Load(@"Button"));
//Actually creating the button.
this.buttonlist = new List
<>(); //Actually creating the list
this.buttonlist.Add(mainButton); //Add the button we recently made to the list.

//Handle the cursor creation
ourMouse = new MouseHandler(new Vector2(0, 0), content.Load(@"cursor"));
//Actually creating the MouseHandler now.

//Handle extra sprites.
onHover = content.Load(@"hovering"); //Sets texture to be used
onClick = content.Load(@"clicked"); //Sets texture to be used
hoverPos = new Vector2(250, 200); //Sets position
clickPos = new Vector2(250, 300); //Sets position
Alright, getting there...
Updating the game.
Here's the function that will handle the mouseClicking.

private void HandleMouse()
{
mouseState = Mouse.GetState(); //Get the current state of the mouse
if (ourMouse.ButtonClick(mainButton)) //There's only one button, so we just hardcode it.
//If we're hovering over the mouse
Hovering = true; //We ARE hovering
else
Hovering = false; //Not hovering.
//We don't even need to use ButtonClick() again if we know if we're hovering.
if (mouseState.LeftButton == ButtonState.Pressed && Hovering) //If we're clicking with the Left Mouse Button and we're over the button.
Clicking = true; //We ARE clicking
else
Clicking = false; //Not clicking
}
This function will be called in the Update function.
Heres the added code for the update function:

HandleMouse(); //Check clicking
ourMouse.Update(); //Update the mouse's position.
The Draw function.

batch.Begin();
//Between batch.Begin() and batch.End() we are allowed to draw.
foreach (Button b in buttonlist) //For every button run through the code between the {}
{
//For every button in our list, draw it
b.Draw(batch);
}
if (Hovering) //If we are hovering
{
//Draw the hover sprite
batch.Draw(this.onHover, this.hoverPos, Color.White);
}
if (Clicking) //If we are clicking
{
//Draw the clicking sprite.
batch.Draw(this.onClick, this.clickPos, Color.White);
}
//Draw the mouse.
ourMouse.Draw(batch);
//Done
batch.End();

Wala! Finito! Finished! Enjoy. I may be creating an add onto this tutorial that will cover menus and that kind of thing. Scenegraphs need to be covered too, they're used in the SpaceWars example that comes with XNA and they are really great.

172 comments: